From 73d995ff88b3a8894c7463a21a24dcec3f8d68e4 Mon Sep 17 00:00:00 2001 From: Zachary Heidepriem Date: Sat, 11 Nov 2017 15:03:26 -0800 Subject: Implement CallingAccountSelector and AssistedDialAction CallingAccountSelector examines the CallIntentBuilder, and if the PhoneAccountHandle is missing on a multi-SIM device while the default is not set, it will show a dialog to let the user select it. This step used to be after the in call UI is launched and telecom wants dialer to disambiguate. This step is moved to pre call as dialer need more control, like voicemail calls should always prompt, or the preferred SIM info might be available. This also allows telecom to send the selected PhoneAccountHandle to other apps so they have more information on how to rewrite numbers. AssistedDialAction replaces the step previously in CallIntentBuilder.build(), and rewrites the URI. Pre-call actions are not hooked up for dialing in this CL yet, assisted dialing will still be broken. Bug: 64216442 Test: CallingAccountSelectorTest, AssistedDialActionTest PiperOrigin-RevId: 174917321 Change-Id: Iba2e9092f83c036b402d4044a48ff5c44e806210 --- .../widget/SelectPhoneAccountDialogFragment.java | 7 ++ .../dialer/assisteddialing/ConcreteCreator.java | 3 +- .../dialer/precall/impl/AssistedDialAction.java | 73 +++++++++++++ .../precall/impl/CallingAccountSelector.java | 114 +++++++++++++++++++++ .../android/dialer/precall/impl/PreCallImpl.java | 2 +- .../dialer/precall/impl/res/values/strings.xml | 22 ++++ 6 files changed, 219 insertions(+), 2 deletions(-) create mode 100644 java/com/android/dialer/precall/impl/AssistedDialAction.java create mode 100644 java/com/android/dialer/precall/impl/CallingAccountSelector.java create mode 100644 java/com/android/dialer/precall/impl/res/values/strings.xml (limited to 'java/com/android') diff --git a/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java b/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java index 8156d97cf..6c6aebc0b 100644 --- a/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java +++ b/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java @@ -26,6 +26,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.ResultReceiver; import android.support.annotation.Nullable; +import android.support.annotation.VisibleForTesting; import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; @@ -116,6 +117,12 @@ public class SelectPhoneAccountDialogFragment extends DialogFragment { mListener = listener; } + @Nullable + @VisibleForTesting + public SelectPhoneAccountListener getListener() { + return mListener; + } + @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); diff --git a/java/com/android/dialer/assisteddialing/ConcreteCreator.java b/java/com/android/dialer/assisteddialing/ConcreteCreator.java index c3721a7a8..806764567 100644 --- a/java/com/android/dialer/assisteddialing/ConcreteCreator.java +++ b/java/com/android/dialer/assisteddialing/ConcreteCreator.java @@ -22,6 +22,7 @@ import android.os.Build; import android.os.Build.VERSION_CODES; import android.preference.PreferenceManager; import android.support.annotation.NonNull; +import android.support.annotation.VisibleForTesting; import android.support.v4.os.UserManagerCompat; import android.telephony.TelephonyManager; import com.android.dialer.assisteddialing.ui.R; @@ -41,7 +42,7 @@ public final class ConcreteCreator { // Floor set at N due to use of Optional. protected static final int BUILD_CODE_FLOOR = Build.VERSION_CODES.N; // Ceiling set at O because this feature will ship as part of the framework in P. - protected static final int BUILD_CODE_CEILING = Build.VERSION_CODES.O; + @VisibleForTesting public static final int BUILD_CODE_CEILING = Build.VERSION_CODES.O; /** * Creates a new AssistedDialingMediator diff --git a/java/com/android/dialer/precall/impl/AssistedDialAction.java b/java/com/android/dialer/precall/impl/AssistedDialAction.java new file mode 100644 index 000000000..edf97cce3 --- /dev/null +++ b/java/com/android/dialer/precall/impl/AssistedDialAction.java @@ -0,0 +1,73 @@ +/* + * 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.dialer.precall.impl; + +import android.annotation.TargetApi; +import android.os.Build; +import android.os.Bundle; +import android.telecom.PhoneAccount; +import android.telephony.TelephonyManager; +import com.android.dialer.assisteddialing.AssistedDialingMediator; +import com.android.dialer.assisteddialing.ConcreteCreator; +import com.android.dialer.assisteddialing.TransformationInfo; +import com.android.dialer.callintent.CallIntentBuilder; +import com.android.dialer.common.Assert; +import com.android.dialer.compat.telephony.TelephonyManagerCompat; +import com.android.dialer.precall.PreCallAction; +import com.android.dialer.precall.PreCallCoordinator; +import com.android.dialer.util.CallUtil; +import java.util.Optional; + +/** Rewrites the call URI with country code. TODO(erfanian): use phone account for multi SIM */ +public class AssistedDialAction implements PreCallAction { + + @SuppressWarnings("AndroidApiChecker") // Use of optional + @TargetApi(Build.VERSION_CODES.N) + @Override + public void run(PreCallCoordinator coordinator) { + CallIntentBuilder builder = coordinator.getBuilder(); + if (!builder.isAssistedDialAllowed()) { + return; + } + AssistedDialingMediator assistedDialingMediator = + ConcreteCreator.createNewAssistedDialingMediator( + coordinator.getActivity().getSystemService(TelephonyManager.class), + coordinator.getActivity()); + if (!assistedDialingMediator.isPlatformEligible()) { + return; + } + builder.getOutgoingCallExtras().putBoolean(TelephonyManagerCompat.ALLOW_ASSISTED_DIAL, true); + String phoneNumber = + builder.getUri().getScheme().equals(PhoneAccount.SCHEME_TEL) + ? builder.getUri().getSchemeSpecificPart() + : ""; + Optional transformedNumber = + assistedDialingMediator.attemptAssistedDial(phoneNumber); + if (transformedNumber.isPresent()) { + Bundle assistedDialingExtras = transformedNumber.get().toBundle(); + builder.getOutgoingCallExtras().putBoolean(TelephonyManagerCompat.IS_ASSISTED_DIALED, true); + builder + .getOutgoingCallExtras() + .putBundle(TelephonyManagerCompat.ASSISTED_DIALING_EXTRAS, assistedDialingExtras); + builder.setUri( + CallUtil.getCallUri(Assert.isNotNull(transformedNumber.get().transformedNumber()))); + } + } + + @Override + public void onDiscard() {} +} diff --git a/java/com/android/dialer/precall/impl/CallingAccountSelector.java b/java/com/android/dialer/precall/impl/CallingAccountSelector.java new file mode 100644 index 000000000..ca8798c5d --- /dev/null +++ b/java/com/android/dialer/precall/impl/CallingAccountSelector.java @@ -0,0 +1,114 @@ +/* + * 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.dialer.precall.impl; + +import android.app.Activity; +import android.support.annotation.MainThread; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.VisibleForTesting; +import android.telecom.PhoneAccount; +import android.telecom.PhoneAccountHandle; +import android.telecom.TelecomManager; +import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment; +import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment.SelectPhoneAccountListener; +import com.android.dialer.callintent.CallIntentBuilder; +import com.android.dialer.common.Assert; +import com.android.dialer.precall.PreCallAction; +import com.android.dialer.precall.PreCallCoordinator; +import java.util.List; + +/** PreCallAction to select which phone account to call with. Ignored if there's only one account */ +@SuppressWarnings("MissingPermission") +public class CallingAccountSelector implements PreCallAction { + + @VisibleForTesting static final String TAG_CALLING_ACCOUNT_SELECTOR = "CallingAccountSelector"; + + private SelectPhoneAccountDialogFragment selectPhoneAccountDialogFragment; + + private boolean isDiscarding; + + @Override + public void run(PreCallCoordinator coordinator) { + CallIntentBuilder builder = coordinator.getBuilder(); + if (builder.getPhoneAccountHandle() != null) { + return; + } + Activity activity = coordinator.getActivity(); + TelecomManager telecomManager = activity.getSystemService(TelecomManager.class); + List accounts = telecomManager.getCallCapablePhoneAccounts(); + if (accounts.size() <= 1) { + return; + } + boolean isVoicemail = builder.getUri().getScheme().equals(PhoneAccount.SCHEME_VOICEMAIL); + + if (!isVoicemail) { + PhoneAccountHandle defaultPhoneAccount = + telecomManager.getDefaultOutgoingPhoneAccount(builder.getUri().getScheme()); + if (defaultPhoneAccount != null) { + builder.setPhoneAccountHandle(defaultPhoneAccount); + return; + } + } + + selectPhoneAccountDialogFragment = + SelectPhoneAccountDialogFragment.newInstance( + R.string.pre_call_select_phone_account, + false /* canSetDefault */, // TODO(twyen): per contact defaults + accounts, + new SelectedListener(coordinator, coordinator.startPendingAction()), + null /* call ID */); + selectPhoneAccountDialogFragment.show( + activity.getFragmentManager(), TAG_CALLING_ACCOUNT_SELECTOR); + } + + @Override + public void onDiscard() { + isDiscarding = true; + selectPhoneAccountDialogFragment.dismiss(); + } + + private class SelectedListener extends SelectPhoneAccountListener { + + private final PreCallCoordinator coordinator; + private final PreCallCoordinator.PendingAction listener; + + public SelectedListener( + @NonNull PreCallCoordinator builder, @NonNull PreCallCoordinator.PendingAction listener) { + this.coordinator = Assert.isNotNull(builder); + this.listener = Assert.isNotNull(listener); + } + + @MainThread + @Override + public void onPhoneAccountSelected( + PhoneAccountHandle selectedAccountHandle, boolean setDefault, @Nullable String callId) { + coordinator.getBuilder().setPhoneAccountHandle(selectedAccountHandle); + listener.finish(); + } + + @MainThread + @Override + public void onDialogDismissed(@Nullable String callId) { + if (isDiscarding) { + return; + } + coordinator.abortCall(); + listener.finish(); + } + } +} diff --git a/java/com/android/dialer/precall/impl/PreCallImpl.java b/java/com/android/dialer/precall/impl/PreCallImpl.java index ac9750ef2..fc2eff8b1 100644 --- a/java/com/android/dialer/precall/impl/PreCallImpl.java +++ b/java/com/android/dialer/precall/impl/PreCallImpl.java @@ -33,7 +33,7 @@ public class PreCallImpl implements PreCall { @Override public ImmutableList getActions() { - return ImmutableList.of(); + return ImmutableList.of(new CallingAccountSelector(), new AssistedDialAction()); } @NonNull diff --git a/java/com/android/dialer/precall/impl/res/values/strings.xml b/java/com/android/dialer/precall/impl/res/values/strings.xml new file mode 100644 index 000000000..894394662 --- /dev/null +++ b/java/com/android/dialer/precall/impl/res/values/strings.xml @@ -0,0 +1,22 @@ + + + + + Call with + + \ No newline at end of file -- cgit v1.2.3