diff options
Diffstat (limited to 'java/com/android/incallui')
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; - } -} |