summaryrefslogtreecommitdiff
path: root/java/com/android/incallui
diff options
context:
space:
mode:
authorEric Erfanian <erfanian@google.com>2018-05-07 14:58:35 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2018-05-07 14:58:35 +0000
commit84b862acd2c53f665386f1dfd23b57c2bdcf5baf (patch)
tree78bf30ec2633948a69facf84ebfa84a979d814f3 /java/com/android/incallui
parent95c2775dd2b77f9fce454d655d2b23ed700d7f22 (diff)
parent763ce4404ae8e4199da719359a1b01389884cec4 (diff)
Merge changes Ibab0bc7e,I1cb26187,I64225b78,I4806ab65,I7d431e74, ...
* changes: Remove TODOs for showing SIM info in the bottom sheet & call details. Use Telecom Bluetooth API instead of system Bluetooth API. Update audio route after user select different audio route. Clear NewCallLogViewHolder.onClickListener if row is not callable. Filter out unnecessary bottom sheet options for a call to a voicemail box. Aosp fix for v28-support-prelease bottom sheet. Mark photo info as voicemails in bottom sheet Simplify how we build bottom sheet options (a.k.a. modules). Add test to verify no crash on multiple DialerCall#onRemovedFromCallList. Add spam status tests for CallList#onCallAdded More refactoring
Diffstat (limited to 'java/com/android/incallui')
-rw-r--r--java/com/android/incallui/InCallActivity.java3
-rw-r--r--java/com/android/incallui/InCallServiceImpl.java3
-rw-r--r--java/com/android/incallui/audiomode/BluetoothDeviceProvider.java203
-rw-r--r--java/com/android/incallui/audiomode/BluetoothDeviceProviderComponent.java39
-rw-r--r--java/com/android/incallui/audioroute/AudioRouteSelectorDialogFragment.java43
-rw-r--r--java/com/android/incallui/call/DialerCall.java38
-rw-r--r--java/com/android/incallui/call/TelecomAdapter.java11
-rw-r--r--java/com/android/incallui/rtt/impl/AudioSelectMenu.java36
-rw-r--r--java/com/android/incallui/rtt/impl/RttChatFragment.java6
-rw-r--r--java/com/android/incallui/speakeasy/SpeakEasyCallManager.java12
-rw-r--r--java/com/android/incallui/speakeasy/SpeakEasyCallManagerStub.java15
-rw-r--r--java/com/android/incallui/speakeasy/runtime/Constraints.java74
12 files changed, 108 insertions, 375 deletions
diff --git a/java/com/android/incallui/InCallActivity.java b/java/com/android/incallui/InCallActivity.java
index 5ac6b5029..98f001925 100644
--- a/java/com/android/incallui/InCallActivity.java
+++ b/java/com/android/incallui/InCallActivity.java
@@ -1504,7 +1504,8 @@ public class InCallActivity extends TransactionSafeFragmentActivity
call.getVideoTech().isSelfManagedCamera(),
shouldAllowAnswerAndRelease(call),
CallList.getInstance().getBackgroundCall() != null,
- call.isSpeakEasyEligible());
+ getSpeakEasyCallManager().isAvailable(getApplicationContext())
+ && call.isSpeakEasyEligible());
transaction.add(R.id.main, answerScreen.getAnswerScreenFragment(), Tags.ANSWER_SCREEN);
Logger.get(this).logScreenView(ScreenEvent.Type.INCOMING_CALL, this);
diff --git a/java/com/android/incallui/InCallServiceImpl.java b/java/com/android/incallui/InCallServiceImpl.java
index d803956e6..b9d0eccba 100644
--- a/java/com/android/incallui/InCallServiceImpl.java
+++ b/java/com/android/incallui/InCallServiceImpl.java
@@ -26,7 +26,6 @@ import android.telecom.InCallService;
import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler;
import com.android.dialer.feedback.FeedbackComponent;
import com.android.incallui.audiomode.AudioModeProvider;
-import com.android.incallui.audiomode.BluetoothDeviceProviderComponent;
import com.android.incallui.call.CallList;
import com.android.incallui.call.ExternalCallList;
import com.android.incallui.call.TelecomAdapter;
@@ -98,7 +97,6 @@ public class InCallServiceImpl extends InCallService {
final Context context = getApplicationContext();
final ContactInfoCache contactInfoCache = ContactInfoCache.getInstance(context);
AudioModeProvider.getInstance().initializeAudioState(this);
- BluetoothDeviceProviderComponent.get(context).bluetoothDeviceProvider().setUp();
InCallPresenter.getInstance()
.setUp(
context,
@@ -142,7 +140,6 @@ public class InCallServiceImpl extends InCallService {
// Tear down the InCall system
InCallPresenter.getInstance().tearDown();
TelecomAdapter.getInstance().clearInCallService();
- BluetoothDeviceProviderComponent.get(this).bluetoothDeviceProvider().tearDown();
if (returnToCallController != null) {
returnToCallController.tearDown();
returnToCallController = null;
diff --git a/java/com/android/incallui/audiomode/BluetoothDeviceProvider.java b/java/com/android/incallui/audiomode/BluetoothDeviceProvider.java
deleted file mode 100644
index 1aa1c20a8..000000000
--- a/java/com/android/incallui/audiomode/BluetoothDeviceProvider.java
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.incallui.audiomode;
-
-import android.annotation.SuppressLint;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothProfile;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.util.ArraySet;
-import com.android.dialer.common.LogUtil;
-import com.android.dialer.inject.ApplicationContext;
-import java.lang.reflect.Method;
-import java.util.List;
-import java.util.Set;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/** Proxy class for getting and setting connected/active Bluetooth devices. */
-@Singleton
-public final class BluetoothDeviceProvider extends BroadcastReceiver {
-
- // TODO(yueg): use BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED when possible
- private static final String ACTION_ACTIVE_DEVICE_CHANGED =
- "android.bluetooth.headset.profile.action.ACTIVE_DEVICE_CHANGED";
-
- private final Context appContext;
- private final BluetoothProfileServiceListener bluetoothProfileServiceListener =
- new BluetoothProfileServiceListener();
-
- private final Set<BluetoothDevice> connectedBluetoothDeviceSet = new ArraySet<>();
-
- private BluetoothDevice activeBluetoothDevice;
- private BluetoothHeadset bluetoothHeadset;
- private boolean isSetUp;
-
- @Inject
- public BluetoothDeviceProvider(@ApplicationContext Context appContext) {
- this.appContext = appContext;
- }
-
- public void setUp() {
- if (BluetoothAdapter.getDefaultAdapter() == null) {
- // Bluetooth is not supported on this hardware platform
- return;
- }
- // Get Bluetooth service including the initial connected device list (should only contain one
- // device)
- BluetoothAdapter.getDefaultAdapter()
- .getProfileProxy(appContext, bluetoothProfileServiceListener, BluetoothProfile.HEADSET);
- // Get notified of Bluetooth device update
- IntentFilter filter = new IntentFilter();
- filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
- filter.addAction(ACTION_ACTIVE_DEVICE_CHANGED);
- appContext.registerReceiver(this, filter);
-
- isSetUp = true;
- }
-
- public void tearDown() {
- if (!isSetUp) {
- return;
- }
- appContext.unregisterReceiver(this);
- if (bluetoothHeadset != null) {
- BluetoothAdapter.getDefaultAdapter()
- .closeProfileProxy(BluetoothProfile.HEADSET, bluetoothHeadset);
- }
- }
-
- public Set<BluetoothDevice> getConnectedBluetoothDeviceSet() {
- return connectedBluetoothDeviceSet;
- }
-
- public BluetoothDevice getActiveBluetoothDevice() {
- return activeBluetoothDevice;
- }
-
- @SuppressLint("PrivateApi")
- public void setActiveBluetoothDevice(BluetoothDevice bluetoothDevice) {
- if (!connectedBluetoothDeviceSet.contains(bluetoothDevice)) {
- LogUtil.e("BluetoothProfileServiceListener.setActiveBluetoothDevice", "device is not in set");
- return;
- }
- // TODO(yueg): use BluetoothHeadset.setActiveDevice() when possible
- try {
- Method getActiveDeviceMethod =
- bluetoothHeadset.getClass().getDeclaredMethod("setActiveDevice", BluetoothDevice.class);
- getActiveDeviceMethod.setAccessible(true);
- getActiveDeviceMethod.invoke(bluetoothHeadset, bluetoothDevice);
- } catch (Exception e) {
- LogUtil.e(
- "BluetoothProfileServiceListener.setActiveBluetoothDevice",
- "failed to call setActiveDevice",
- e);
- }
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {
- handleActionConnectionStateChanged(intent);
- } else if (ACTION_ACTIVE_DEVICE_CHANGED.equals(intent.getAction())) {
- handleActionActiveDeviceChanged(intent);
- }
- }
-
- private void handleActionConnectionStateChanged(Intent intent) {
- if (!intent.hasExtra(BluetoothDevice.EXTRA_DEVICE)) {
- LogUtil.i(
- "BluetoothDeviceProvider.handleActionConnectionStateChanged",
- "extra BluetoothDevice.EXTRA_DEVICE not found");
- return;
- }
- BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- if (bluetoothDevice == null) {
- return;
- }
-
- int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
- if (state == BluetoothProfile.STATE_DISCONNECTED) {
- connectedBluetoothDeviceSet.remove(bluetoothDevice);
- LogUtil.i("BluetoothDeviceProvider.handleActionConnectionStateChanged", "device removed");
- } else if (state == BluetoothProfile.STATE_CONNECTED) {
- connectedBluetoothDeviceSet.add(bluetoothDevice);
- LogUtil.i("BluetoothDeviceProvider.handleActionConnectionStateChanged", "device added");
- }
- }
-
- private void handleActionActiveDeviceChanged(Intent intent) {
- if (!intent.hasExtra(BluetoothDevice.EXTRA_DEVICE)) {
- LogUtil.i(
- "BluetoothDeviceProvider.handleActionActiveDeviceChanged",
- "extra BluetoothDevice.EXTRA_DEVICE not found");
- return;
- }
- activeBluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- LogUtil.i(
- "BluetoothDeviceProvider.handleActionActiveDeviceChanged",
- (activeBluetoothDevice == null ? "null" : ""));
- }
-
- private final class BluetoothProfileServiceListener implements BluetoothProfile.ServiceListener {
- @Override
- @SuppressLint("PrivateApi")
- public void onServiceConnected(int profile, BluetoothProfile bluetoothProfile) {
- if (profile != BluetoothProfile.HEADSET) {
- return;
- }
- // Get initial connected device list
- bluetoothHeadset = (BluetoothHeadset) bluetoothProfile;
- List<BluetoothDevice> devices = bluetoothProfile.getConnectedDevices();
- for (BluetoothDevice device : devices) {
- connectedBluetoothDeviceSet.add(device);
- LogUtil.i(
- "BluetoothProfileServiceListener.onServiceConnected", "get initial connected device");
- }
-
- // Get initial active device
- // TODO(yueg): use BluetoothHeadset.getActiveDevice() when possible
- try {
- Method getActiveDeviceMethod =
- bluetoothHeadset.getClass().getDeclaredMethod("getActiveDevice");
- getActiveDeviceMethod.setAccessible(true);
- activeBluetoothDevice = (BluetoothDevice) getActiveDeviceMethod.invoke(bluetoothHeadset);
- LogUtil.i(
- "BluetoothProfileServiceListener.onServiceConnected",
- "get initial active device" + ((activeBluetoothDevice == null) ? " null" : ""));
- } catch (Exception e) {
- LogUtil.e(
- "BluetoothProfileServiceListener.onServiceConnected",
- "failed to call getAcitveDevice",
- e);
- }
- }
-
- @Override
- public void onServiceDisconnected(int profile) {
- LogUtil.enterBlock("BluetoothProfileServiceListener.onServiceDisconnected");
- if (profile == BluetoothProfile.HEADSET) {
- bluetoothHeadset = null;
- }
- }
- }
-}
diff --git a/java/com/android/incallui/audiomode/BluetoothDeviceProviderComponent.java b/java/com/android/incallui/audiomode/BluetoothDeviceProviderComponent.java
deleted file mode 100644
index 9cd926835..000000000
--- a/java/com/android/incallui/audiomode/BluetoothDeviceProviderComponent.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.incallui.audiomode;
-
-import android.content.Context;
-import com.android.dialer.inject.HasRootComponent;
-import dagger.Subcomponent;
-
-/** Dagger component for the Bluetooth device provider. */
-@Subcomponent
-public abstract class BluetoothDeviceProviderComponent {
-
- public abstract BluetoothDeviceProvider bluetoothDeviceProvider();
-
- public static BluetoothDeviceProviderComponent get(Context context) {
- return ((BluetoothDeviceProviderComponent.HasComponent)
- ((HasRootComponent) context.getApplicationContext()).component())
- .bluetoothDeviceProviderComponent();
- }
-
- /** Used to refer to the root application component. */
- public interface HasComponent {
- BluetoothDeviceProviderComponent bluetoothDeviceProviderComponent();
- }
-}
diff --git a/java/com/android/incallui/audioroute/AudioRouteSelectorDialogFragment.java b/java/com/android/incallui/audioroute/AudioRouteSelectorDialogFragment.java
index d6946d8de..a561b5ee5 100644
--- a/java/com/android/incallui/audioroute/AudioRouteSelectorDialogFragment.java
+++ b/java/com/android/incallui/audioroute/AudioRouteSelectorDialogFragment.java
@@ -39,12 +39,12 @@ import com.android.dialer.common.FragmentUtils;
import com.android.dialer.common.LogUtil;
import com.android.dialer.logging.DialerImpression;
import com.android.dialer.logging.Logger;
-import com.android.incallui.audiomode.BluetoothDeviceProviderComponent;
import com.android.incallui.call.CallList;
import com.android.incallui.call.DialerCall;
+import com.android.incallui.call.TelecomAdapter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.util.Set;
+import java.util.Collection;
/** Shows picker for audio routes */
public class AudioRouteSelectorDialogFragment extends BottomSheetDialogFragment {
@@ -91,24 +91,33 @@ public class AudioRouteSelectorDialogFragment extends BottomSheetDialogFragment
@Nullable
@Override
+ @SuppressLint("NewApi")
public View onCreateView(
LayoutInflater layoutInflater, @Nullable ViewGroup viewGroup, @Nullable Bundle bundle) {
View view = layoutInflater.inflate(R.layout.audioroute_selector, viewGroup, false);
CallAudioState audioState = getArguments().getParcelable(ARG_AUDIO_STATE);
- Set<BluetoothDevice> bluetoothDeviceSet =
- BluetoothDeviceProviderComponent.get(getContext())
- .bluetoothDeviceProvider()
- .getConnectedBluetoothDeviceSet();
- for (BluetoothDevice device : bluetoothDeviceSet) {
- boolean selected =
- (audioState.getRoute() == CallAudioState.ROUTE_BLUETOOTH)
- && (bluetoothDeviceSet.size() == 1
- || device.equals(
- BluetoothDeviceProviderComponent.get(getContext())
- .bluetoothDeviceProvider()
- .getActiveBluetoothDevice()));
- TextView textView = createBluetoothItem(device, selected);
+ if (BuildCompat.isAtLeastP()) {
+ // Create items for all connected Bluetooth devices
+ Collection<BluetoothDevice> bluetoothDeviceSet = audioState.getSupportedBluetoothDevices();
+ for (BluetoothDevice device : bluetoothDeviceSet) {
+ boolean selected =
+ (audioState.getRoute() == CallAudioState.ROUTE_BLUETOOTH)
+ && (bluetoothDeviceSet.size() == 1
+ || device.equals(audioState.getActiveBluetoothDevice()));
+ TextView textView = createBluetoothItem(device, selected);
+ ((LinearLayout) view).addView(textView, 0);
+ }
+ } else {
+ // Only create Bluetooth audio route
+ TextView textView =
+ (TextView) getLayoutInflater().inflate(R.layout.audioroute_item, null, false);
+ textView.setText(getString(R.string.audioroute_bluetooth));
+ initItem(
+ textView,
+ CallAudioState.ROUTE_BLUETOOTH,
+ audioState,
+ DialerImpression.Type.IN_CALL_SWITCH_AUDIO_ROUTE_BLUETOOTH);
((LinearLayout) view).addView(textView, 0);
}
@@ -183,9 +192,7 @@ public class AudioRouteSelectorDialogFragment extends BottomSheetDialogFragment
AudioRouteSelectorDialogFragment.this, AudioRouteSelectorPresenter.class)
.onAudioRouteSelected(CallAudioState.ROUTE_BLUETOOTH);
// Set active Bluetooth device
- BluetoothDeviceProviderComponent.get(getContext())
- .bluetoothDeviceProvider()
- .setActiveBluetoothDevice(bluetoothDevice);
+ TelecomAdapter.getInstance().requestBluetoothAudio(bluetoothDevice);
dismiss();
});
diff --git a/java/com/android/incallui/call/DialerCall.java b/java/com/android/incallui/call/DialerCall.java
index 1a0de1960..77e2ea30b 100644
--- a/java/com/android/incallui/call/DialerCall.java
+++ b/java/com/android/incallui/call/DialerCall.java
@@ -50,7 +50,6 @@ import android.telecom.VideoProfile;
import android.text.TextUtils;
import android.widget.Toast;
import com.android.contacts.common.compat.CallCompat;
-import com.android.contacts.common.compat.telecom.TelecomManagerCompat;
import com.android.dialer.assisteddialing.ConcreteCreator;
import com.android.dialer.assisteddialing.TransformationInfo;
import com.android.dialer.callintent.CallInitiationType;
@@ -86,7 +85,6 @@ import com.android.incallui.audiomode.AudioModeProvider;
import com.android.incallui.call.state.DialerCallState;
import com.android.incallui.latencyreport.LatencyReport;
import com.android.incallui.rtt.protocol.RttChatMessage;
-import com.android.incallui.speakeasy.runtime.Constraints;
import com.android.incallui.videotech.VideoTech;
import com.android.incallui.videotech.VideoTech.VideoTechListener;
import com.android.incallui.videotech.duo.DuoVideoTech;
@@ -118,8 +116,11 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa
public static final int PROPERTY_CODEC_KNOWN = 0x04000000;
private static final String ID_PREFIX = "DialerCall_";
- private static final String CONFIG_EMERGENCY_CALLBACK_WINDOW_MILLIS =
+
+ @VisibleForTesting
+ public static final String CONFIG_EMERGENCY_CALLBACK_WINDOW_MILLIS =
"emergency_callback_window_millis";
+
private static int idCounter = 0;
/**
@@ -822,10 +823,9 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa
// We want to treat any incoming call that arrives a short time after an outgoing emergency call
// as a potential emergency callback.
if (getExtras() != null
- && getExtras().getLong(TelecomManagerCompat.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS, 0)
- > 0) {
+ && getExtras().getLong(Call.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS, 0) > 0) {
long lastEmergencyCallMillis =
- getExtras().getLong(TelecomManagerCompat.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS, 0);
+ getExtras().getLong(Call.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS, 0);
if (isInEmergencyCallbackWindow(lastEmergencyCallMillis)) {
return true;
}
@@ -1058,6 +1058,7 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa
}
@TargetApi(28)
+ @Nullable
public RttCall getRttCall() {
if (!isActiveRttCall()) {
return null;
@@ -1111,16 +1112,18 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa
if (!BuildCompat.isAtLeastP()) {
return;
}
- // Save any remaining text in the buffer that's not shown by UI yet.
- // This may happen when the call is switched to background before disconnect.
- try {
- String messageLeft = getRttCall().readImmediately();
- if (!TextUtils.isEmpty(messageLeft)) {
- rttTranscript =
- RttChatMessage.getRttTranscriptWithNewRemoteMessage(rttTranscript, messageLeft);
+ if (getRttCall() != null) {
+ // Save any remaining text in the buffer that's not shown by UI yet.
+ // This may happen when the call is switched to background before disconnect.
+ try {
+ String messageLeft = getRttCall().readImmediately();
+ if (!TextUtils.isEmpty(messageLeft)) {
+ rttTranscript =
+ RttChatMessage.getRttTranscriptWithNewRemoteMessage(rttTranscript, messageLeft);
+ }
+ } catch (IOException e) {
+ LogUtil.e("DialerCall.saveRttTranscript", "error when reading remaining message", e);
}
- } catch (IOException e) {
- LogUtil.e("DialerCall.saveRttTranscript", "error when reading remaining message", e);
}
// Don't save transcript if it's empty.
if (rttTranscript.getMessagesCount() == 0) {
@@ -1662,7 +1665,6 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa
if (videoTechManager != null) {
videoTechManager.dispatchRemovedFromCallList();
}
- // TODO(a bug): Add tests for it to make sure no crash on subsequent call to this method.
// TODO(wangqi): Consider moving this to a DialerCallListener.
if (rttTranscript != null && !isCallRemoved) {
saveRttTranscript();
@@ -1697,10 +1699,6 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa
/** Indicates the call is eligible for SpeakEasy */
public boolean isSpeakEasyEligible() {
- if (!Constraints.isAvailable(context)) {
- return false;
- }
-
return !isPotentialEmergencyCallback()
&& !isEmergencyCall()
&& !isActiveRttCall()
diff --git a/java/com/android/incallui/call/TelecomAdapter.java b/java/com/android/incallui/call/TelecomAdapter.java
index a7e10d37c..4ae1bc1db 100644
--- a/java/com/android/incallui/call/TelecomAdapter.java
+++ b/java/com/android/incallui/call/TelecomAdapter.java
@@ -16,7 +16,9 @@
package com.android.incallui.call;
+import android.annotation.TargetApi;
import android.app.Notification;
+import android.bluetooth.BluetoothDevice;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.os.Looper;
@@ -193,4 +195,13 @@ public class TelecomAdapter implements InCallServiceListener {
"no inCallService available for stopping foreground notification");
}
}
+
+ @TargetApi(28)
+ public void requestBluetoothAudio(BluetoothDevice bluetoothDevice) {
+ if (inCallService != null) {
+ inCallService.requestBluetoothAudio(bluetoothDevice);
+ } else {
+ LogUtil.e("TelecomAdapter.requestBluetoothAudio", "inCallService is null");
+ }
+ }
}
diff --git a/java/com/android/incallui/rtt/impl/AudioSelectMenu.java b/java/com/android/incallui/rtt/impl/AudioSelectMenu.java
index 01c3950e9..1c83637ea 100644
--- a/java/com/android/incallui/rtt/impl/AudioSelectMenu.java
+++ b/java/com/android/incallui/rtt/impl/AudioSelectMenu.java
@@ -17,8 +17,6 @@
package com.android.incallui.rtt.impl;
import android.content.Context;
-import android.content.res.ColorStateList;
-import android.graphics.PorterDuff.Mode;
import android.telecom.CallAudioState;
import android.view.View;
import android.widget.PopupWindow;
@@ -28,8 +26,11 @@ import com.android.incallui.incall.protocol.InCallButtonUiDelegate;
public class AudioSelectMenu extends PopupWindow {
private final InCallButtonUiDelegate inCallButtonUiDelegate;
- private final Context context;
private final OnButtonClickListener onButtonClickListener;
+ private final RttCheckableButton bluetoothButton;
+ private final RttCheckableButton speakerButton;
+ private final RttCheckableButton headsetButton;
+ private final RttCheckableButton earpieceButton;
interface OnButtonClickListener {
void onBackPressed();
@@ -40,7 +41,6 @@ public class AudioSelectMenu extends PopupWindow {
InCallButtonUiDelegate inCallButtonUiDelegate,
OnButtonClickListener onButtonClickListener) {
super(context, null, 0, R.style.OverflowMenu);
- this.context = context;
this.inCallButtonUiDelegate = inCallButtonUiDelegate;
this.onButtonClickListener = onButtonClickListener;
View view = View.inflate(context, R.layout.audio_route, null);
@@ -55,28 +55,32 @@ public class AudioSelectMenu extends PopupWindow {
this.onButtonClickListener.onBackPressed();
});
CallAudioState audioState = inCallButtonUiDelegate.getCurrentAudioState();
- initItem(
- view.findViewById(R.id.audioroute_bluetooth), CallAudioState.ROUTE_BLUETOOTH, audioState);
- initItem(view.findViewById(R.id.audioroute_speaker), CallAudioState.ROUTE_SPEAKER, audioState);
- initItem(
- view.findViewById(R.id.audioroute_headset), CallAudioState.ROUTE_WIRED_HEADSET, audioState);
- initItem(
- view.findViewById(R.id.audioroute_earpiece), CallAudioState.ROUTE_EARPIECE, audioState);
+ bluetoothButton = view.findViewById(R.id.audioroute_bluetooth);
+ speakerButton = view.findViewById(R.id.audioroute_speaker);
+ headsetButton = view.findViewById(R.id.audioroute_headset);
+ earpieceButton = view.findViewById(R.id.audioroute_earpiece);
+ initItem(bluetoothButton, CallAudioState.ROUTE_BLUETOOTH, audioState);
+ initItem(speakerButton, CallAudioState.ROUTE_SPEAKER, audioState);
+ initItem(headsetButton, CallAudioState.ROUTE_WIRED_HEADSET, audioState);
+ initItem(earpieceButton, CallAudioState.ROUTE_EARPIECE, audioState);
}
private void initItem(RttCheckableButton item, final int itemRoute, CallAudioState audioState) {
- int selectedColor =
- context.getColor(com.android.incallui.audioroute.R.color.dialer_theme_color);
if ((audioState.getSupportedRouteMask() & itemRoute) == 0) {
item.setVisibility(View.GONE);
} else if (audioState.getRoute() == itemRoute) {
- item.setTextColor(selectedColor);
- item.setCompoundDrawableTintList(ColorStateList.valueOf(selectedColor));
- item.setCompoundDrawableTintMode(Mode.SRC_ATOP);
+ item.setChecked(true);
}
item.setOnClickListener(
(v) -> {
inCallButtonUiDelegate.setAudioRoute(itemRoute);
});
}
+
+ void setAudioState(CallAudioState audioState) {
+ bluetoothButton.setChecked(audioState.getRoute() == CallAudioState.ROUTE_BLUETOOTH);
+ speakerButton.setChecked(audioState.getRoute() == CallAudioState.ROUTE_SPEAKER);
+ headsetButton.setChecked(audioState.getRoute() == CallAudioState.ROUTE_WIRED_HEADSET);
+ earpieceButton.setChecked(audioState.getRoute() == CallAudioState.ROUTE_EARPIECE);
+ }
}
diff --git a/java/com/android/incallui/rtt/impl/RttChatFragment.java b/java/com/android/incallui/rtt/impl/RttChatFragment.java
index e56715981..c393393f8 100644
--- a/java/com/android/incallui/rtt/impl/RttChatFragment.java
+++ b/java/com/android/incallui/rtt/impl/RttChatFragment.java
@@ -107,6 +107,7 @@ public class RttChatFragment extends Fragment
private PrimaryCallState primaryCallState = PrimaryCallState.empty();
private boolean isUserScrolling;
private boolean shouldAutoScrolling;
+ private AudioSelectMenu audioSelectMenu;
/**
* Create a new instance of RttChatFragment.
@@ -558,6 +559,9 @@ public class RttChatFragment extends Fragment
LogUtil.i("RttChatFragment.setAudioState", "audioState: " + audioState);
overflowMenu.setMuteButtonChecked(audioState.isMuted());
overflowMenu.setAudioState(audioState);
+ if (audioSelectMenu != null) {
+ audioSelectMenu.setAudioState(audioState);
+ }
}
@Override
@@ -573,7 +577,7 @@ public class RttChatFragment extends Fragment
@Override
public void showAudioRouteSelector() {
- AudioSelectMenu audioSelectMenu =
+ audioSelectMenu =
new AudioSelectMenu(
getContext(),
inCallButtonUiDelegate,
diff --git a/java/com/android/incallui/speakeasy/SpeakEasyCallManager.java b/java/com/android/incallui/speakeasy/SpeakEasyCallManager.java
index f2721da7d..8a815d385 100644
--- a/java/com/android/incallui/speakeasy/SpeakEasyCallManager.java
+++ b/java/com/android/incallui/speakeasy/SpeakEasyCallManager.java
@@ -16,6 +16,7 @@
package com.android.incallui.speakeasy;
+import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import com.android.incallui.call.DialerCall;
@@ -37,4 +38,15 @@ public interface SpeakEasyCallManager {
* @param call The call which has been removed.
*/
void onCallRemoved(@NonNull DialerCall call);
+
+ /**
+ * Indicates the feature is available.
+ *
+ * @param context The application context.
+ */
+ boolean isAvailable(@NonNull Context context);
+
+ /** Returns the config provider flag associated with the feature. */
+ @NonNull
+ String getConfigProviderFlag();
}
diff --git a/java/com/android/incallui/speakeasy/SpeakEasyCallManagerStub.java b/java/com/android/incallui/speakeasy/SpeakEasyCallManagerStub.java
index 9e58ce18f..a0409737b 100644
--- a/java/com/android/incallui/speakeasy/SpeakEasyCallManagerStub.java
+++ b/java/com/android/incallui/speakeasy/SpeakEasyCallManagerStub.java
@@ -16,6 +16,8 @@
package com.android.incallui.speakeasy;
+import android.content.Context;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import com.android.incallui.call.DialerCall;
@@ -38,4 +40,17 @@ public class SpeakEasyCallManagerStub implements SpeakEasyCallManager {
/** Always inert in the stub. */
@Override
public void onCallRemoved(DialerCall call) {}
+
+ /** Always returns false. */
+ @Override
+ public boolean isAvailable(@NonNull Context unused) {
+ return false;
+ }
+
+ /** Always returns a stub string. */
+ @NonNull
+ @Override
+ public String getConfigProviderFlag() {
+ return "not_yet_implmented";
+ }
}
diff --git a/java/com/android/incallui/speakeasy/runtime/Constraints.java b/java/com/android/incallui/speakeasy/runtime/Constraints.java
deleted file mode 100644
index 1206d599c..000000000
--- a/java/com/android/incallui/speakeasy/runtime/Constraints.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.incallui.speakeasy.runtime;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.os.Build.VERSION_CODES;
-import android.support.annotation.NonNull;
-import android.support.annotation.VisibleForTesting;
-import android.support.v4.os.BuildCompat;
-import android.support.v4.os.UserManagerCompat;
-import com.android.dialer.common.Assert;
-import com.android.dialer.common.LogUtil;
-import com.android.dialer.configprovider.ConfigProviderBindings;
-import com.android.dialer.util.PermissionsUtil;
-
-/** Preconditions for the use of SpeakEasyModule */
-public final class Constraints {
-
- @VisibleForTesting public static final String SPEAK_EASY_ENABLED = "speak_easy_enabled";
- private static final String[] REQUIRED_PERMISSIONS = {
-
- };
-
- // Non-instantiatable.
- private Constraints() {}
-
- public static boolean isAvailable(@NonNull Context context) {
- Assert.isNotNull(context);
-
- return isServerConfigEnabled(context)
- && isUserUnlocked(context)
- && meetsPlatformSdkFloor()
- && hasNecessaryPermissions(context);
- }
-
- private static boolean isServerConfigEnabled(@NonNull Context context) {
- return ConfigProviderBindings.get(context).getBoolean(SPEAK_EASY_ENABLED, false);
- }
-
- private static boolean isUserUnlocked(@NonNull Context context) {
- return UserManagerCompat.isUserUnlocked(context);
- }
-
- private static boolean meetsPlatformSdkFloor() {
- return BuildCompat.isAtLeastP();
- }
-
- @SuppressWarnings("AndroidApiChecker") // Use of Java 8 APIs.
- @TargetApi(VERSION_CODES.N)
- private static boolean hasNecessaryPermissions(@NonNull Context context) {
- for (String permission : REQUIRED_PERMISSIONS) {
- if (!PermissionsUtil.hasPermission(context, permission)) {
- LogUtil.i("Constraints.hasNecessaryPermissions", "missing permission: %s ", permission);
- return false;
- }
- }
- return true;
- }
-}