summaryrefslogtreecommitdiff
path: root/java/com/android/incallui
diff options
context:
space:
mode:
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;
- }
-}