summaryrefslogtreecommitdiff
path: root/java/com/android/dialer/precall
diff options
context:
space:
mode:
authortwyen <twyen@google.com>2018-03-07 12:12:24 -0800
committerEric Erfanian <erfanian@google.com>2018-03-07 12:50:21 -0800
commit73a74c3c709c87d4ad9860c1fbda585c139235e0 (patch)
treea998b9dae213f71b989f533245ca399c06e08178 /java/com/android/dialer/precall
parent28b252f6e0e4d42551a31d1b197f2eedf7b6a7d5 (diff)
Handle preferred SIM for ACTION_CALL
Previously preferred SIM is handled only by precall, which covers dialing with dialer or with the special receiver contacts uses. If a third party app uses ACTION_CALL or telecomManager.placeCall(), then the in call UI will be launched directly and the old account selection dialog will be used without preferred SIM support. In this CL logic from CallingAccountSelector is refactored out so InCallActivity can use it for the dialog. Bug: 73718976 Test: Unit tests, In call UI not covered. PiperOrigin-RevId: 188214007 Change-Id: Ifaacf982a3e98601dc362b649c3501d4ee96e63e
Diffstat (limited to 'java/com/android/dialer/precall')
-rw-r--r--java/com/android/dialer/precall/impl/CallingAccountSelector.java386
-rw-r--r--java/com/android/dialer/precall/impl/res/values/strings.xml8
2 files changed, 23 insertions, 371 deletions
diff --git a/java/com/android/dialer/precall/impl/CallingAccountSelector.java b/java/com/android/dialer/precall/impl/CallingAccountSelector.java
index afc1eadf1..b7f071d58 100644
--- a/java/com/android/dialer/precall/impl/CallingAccountSelector.java
+++ b/java/com/android/dialer/precall/impl/CallingAccountSelector.java
@@ -17,27 +17,11 @@
package com.android.dialer.precall.impl;
import android.app.Activity;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.PhoneLookup;
-import android.provider.ContactsContract.QuickContact;
-import android.provider.ContactsContract.RawContacts;
import android.support.annotation.MainThread;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
-import android.support.annotation.WorkerThread;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
@@ -46,7 +30,6 @@ import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment.Selec
import com.android.dialer.callintent.CallIntentBuilder;
import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
-import com.android.dialer.common.concurrent.DialerExecutor.Worker;
import com.android.dialer.common.concurrent.DialerExecutorComponent;
import com.android.dialer.configprovider.ConfigProviderBindings;
import com.android.dialer.logging.DialerImpression;
@@ -55,16 +38,11 @@ import com.android.dialer.logging.Logger;
import com.android.dialer.precall.PreCallAction;
import com.android.dialer.precall.PreCallCoordinator;
import com.android.dialer.precall.PreCallCoordinator.PendingAction;
-import com.android.dialer.preferredsim.PreferredAccountUtil;
-import com.android.dialer.preferredsim.PreferredSimFallbackContract;
-import com.android.dialer.preferredsim.PreferredSimFallbackContract.PreferredSim;
-import com.android.dialer.preferredsim.suggestion.SimSuggestionComponent;
+import com.android.dialer.preferredsim.PreferredAccountRecorder;
+import com.android.dialer.preferredsim.PreferredAccountWorker;
+import com.android.dialer.preferredsim.suggestion.SuggestionProvider;
import com.android.dialer.preferredsim.suggestion.SuggestionProvider.Suggestion;
import com.android.dialer.telecom.TelecomUtil;
-import com.android.dialer.util.PermissionsUtil;
-import com.google.common.base.Optional;
-import com.google.common.collect.ImmutableSet;
-import java.util.ArrayList;
import java.util.List;
/** PreCallAction to select which phone account to call with. Ignored if there's only one account */
@@ -73,9 +51,6 @@ public class CallingAccountSelector implements PreCallAction {
@VisibleForTesting static final String TAG_CALLING_ACCOUNT_SELECTOR = "CallingAccountSelector";
- @VisibleForTesting
- static final String METADATA_SUPPORTS_PREFERRED_SIM = "supports_per_number_preferred_account";
-
private SelectPhoneAccountDialogFragment selectPhoneAccountDialogFragment;
private boolean isDiscarding;
@@ -153,10 +128,12 @@ public class CallingAccountSelector implements PreCallAction {
if (isDiscarding) {
return;
}
- if (result.phoneAccountHandle.isPresent()) {
+ if (result.getPhoneAccountHandle().isPresent()) {
Logger.get(coordinator.getActivity())
.logImpression(DialerImpression.Type.DUAL_SIM_SELECTION_PREFERRED_USED);
- coordinator.getBuilder().setPhoneAccountHandle(result.phoneAccountHandle.get());
+ coordinator
+ .getBuilder()
+ .setPhoneAccountHandle(result.getPhoneAccountHandle().get());
pendingAction.finish();
return;
}
@@ -171,17 +148,17 @@ public class CallingAccountSelector implements PreCallAction {
pendingAction.finish();
return;
}
- if (result.suggestion.isPresent()) {
+ if (result.getSuggestion().isPresent()) {
LogUtil.i(
"CallingAccountSelector.processPreferredAccount",
- "SIM suggested: " + result.suggestion.get().reason);
- if (result.suggestion.get().shouldAutoSelect) {
+ "SIM suggested: " + result.getSuggestion().get().reason);
+ if (result.getSuggestion().get().shouldAutoSelect) {
Logger.get(coordinator.getActivity())
.logImpression(
DialerImpression.Type.DUAL_SIM_SELECTION_SUGGESTION_AUTO_SELECTED);
LogUtil.i(
"CallingAccountSelector.processPreferredAccount", "Auto selected suggestion");
- builder.setPhoneAccountHandle(result.suggestion.get().phoneAccountHandle);
+ builder.setPhoneAccountHandle(result.getSuggestion().get().phoneAccountHandle);
pendingAction.finish();
return;
}
@@ -189,9 +166,9 @@ public class CallingAccountSelector implements PreCallAction {
showDialog(
coordinator,
pendingAction,
- result.dataId.orNull(),
+ result.getDataId().orNull(),
phoneNumber,
- result.suggestion.orNull());
+ result.getSuggestion().orNull());
}))
.build()
.executeParallel(activity);
@@ -235,41 +212,17 @@ public class CallingAccountSelector implements PreCallAction {
dataId != null /* canSetDefault */,
R.string.pre_call_select_phone_account_remember,
phoneAccountHandles,
- new SelectedListener(coordinator, pendingAction, dataId, number, suggestion),
+ new SelectedListener(
+ coordinator,
+ pendingAction,
+ new PreferredAccountRecorder(number, suggestion, dataId)),
null /* call ID */,
- buildHint(coordinator.getActivity(), phoneAccountHandles, suggestion));
+ SuggestionProvider.buildHint(
+ coordinator.getActivity(), phoneAccountHandles, suggestion));
selectPhoneAccountDialogFragment.show(
coordinator.getActivity().getFragmentManager(), TAG_CALLING_ACCOUNT_SELECTOR);
}
- @Nullable
- private static List<String> buildHint(
- Context context,
- List<PhoneAccountHandle> phoneAccountHandles,
- @Nullable Suggestion suggestion) {
- if (suggestion == null) {
- return null;
- }
- List<String> hints = new ArrayList<>();
- for (PhoneAccountHandle phoneAccountHandle : phoneAccountHandles) {
- if (!phoneAccountHandle.equals(suggestion.phoneAccountHandle)) {
- hints.add(null);
- continue;
- }
- switch (suggestion.reason) {
- case INTRA_CARRIER:
- hints.add(context.getString(R.string.pre_call_select_phone_account_hint_intra_carrier));
- break;
- case FREQUENT:
- hints.add(context.getString(R.string.pre_call_select_phone_account_hint_frequent));
- break;
- default:
- LogUtil.w("CallingAccountSelector.buildHint", "unhandled reason " + suggestion.reason);
- }
- }
- return hints;
- }
-
@MainThread
@Override
public void onDiscard() {
@@ -279,221 +232,27 @@ public class CallingAccountSelector implements PreCallAction {
}
}
- private static class PreferredAccountWorkerResult {
-
- /** The preferred phone account for the number. Absent if not set or invalid. */
- Optional<PhoneAccountHandle> phoneAccountHandle = Optional.absent();
-
- /**
- * {@link android.provider.ContactsContract.Data#_ID} of the row matching the number. If the
- * preferred account is to be set it should be stored in this row
- */
- Optional<String> dataId = Optional.absent();
-
- Optional<Suggestion> suggestion = Optional.absent();
- }
-
- private static class PreferredAccountWorker
- implements Worker<Context, PreferredAccountWorkerResult> {
-
- private final String phoneNumber;
-
- public PreferredAccountWorker(String phoneNumber) {
- this.phoneNumber = phoneNumber;
- }
-
- @NonNull
- @Override
- @WorkerThread
- public PreferredAccountWorkerResult doInBackground(Context context) throws Throwable {
- PreferredAccountWorkerResult result = new PreferredAccountWorkerResult();
- if (!isPreferredSimEnabled(context)) {
- return result;
- }
- if (!PermissionsUtil.hasContactsReadPermissions(context)) {
- LogUtil.i(
- "CallingAccountSelector.PreferredAccountWorker.doInBackground",
- "missing READ_CONTACTS permission");
- return result;
- }
- result.dataId = getDataId(context, phoneNumber);
- if (result.dataId.isPresent()) {
- result.phoneAccountHandle = getPreferredAccount(context, result.dataId.get());
- }
- if (!result.phoneAccountHandle.isPresent()) {
- result.suggestion =
- SimSuggestionComponent.get(context)
- .getSuggestionProvider()
- .getSuggestion(context, phoneNumber);
- }
- return result;
- }
- }
-
- @WorkerThread
- @NonNull
- private static Optional<String> getDataId(
- @NonNull Context context, @Nullable String phoneNumber) {
- Assert.isWorkerThread();
- if (VERSION.SDK_INT < VERSION_CODES.N) {
- return Optional.absent();
- }
- try (Cursor cursor =
- context
- .getContentResolver()
- .query(
- Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber)),
- new String[] {PhoneLookup.DATA_ID},
- null,
- null,
- null)) {
- if (cursor == null) {
- return Optional.absent();
- }
- ImmutableSet<String> validAccountTypes = PreferredAccountUtil.getValidAccountTypes(context);
- String result = null;
- while (cursor.moveToNext()) {
- Optional<String> accountType =
- getAccountType(context.getContentResolver(), cursor.getLong(0));
- if (accountType.isPresent() && !validAccountTypes.contains(accountType.get())) {
- // Empty accountType is treated as writable
- LogUtil.i("CallingAccountSelector.getDataId", "ignoring non-writable " + accountType);
- continue;
- }
- if (result != null && !result.equals(cursor.getString(0))) {
- // TODO(twyen): if there are multiple entries attempt to grab from the contact that
- // initiated the call.
- LogUtil.i("CallingAccountSelector.getDataId", "lookup result not unique, ignoring");
- return Optional.absent();
- }
- result = cursor.getString(0);
- }
- return Optional.fromNullable(result);
- }
- }
-
- @WorkerThread
- private static Optional<String> getAccountType(ContentResolver contentResolver, long dataId) {
- Assert.isWorkerThread();
- Optional<Long> rawContactId = getRawContactId(contentResolver, dataId);
- if (!rawContactId.isPresent()) {
- return Optional.absent();
- }
- try (Cursor cursor =
- contentResolver.query(
- ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId.get()),
- new String[] {RawContacts.ACCOUNT_TYPE},
- null,
- null,
- null)) {
- if (cursor == null || !cursor.moveToFirst()) {
- return Optional.absent();
- }
- return Optional.fromNullable(cursor.getString(0));
- }
- }
-
- @WorkerThread
- private static Optional<Long> getRawContactId(ContentResolver contentResolver, long dataId) {
- Assert.isWorkerThread();
- try (Cursor cursor =
- contentResolver.query(
- ContentUris.withAppendedId(Data.CONTENT_URI, dataId),
- new String[] {Data.RAW_CONTACT_ID},
- null,
- null,
- null)) {
- if (cursor == null || !cursor.moveToFirst()) {
- return Optional.absent();
- }
- return Optional.of(cursor.getLong(0));
- }
- }
-
- @WorkerThread
- @NonNull
- private static Optional<PhoneAccountHandle> getPreferredAccount(
- @NonNull Context context, @NonNull String dataId) {
- Assert.isWorkerThread();
- Assert.isNotNull(dataId);
- try (Cursor cursor =
- context
- .getContentResolver()
- .query(
- PreferredSimFallbackContract.CONTENT_URI,
- new String[] {
- PreferredSim.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME,
- PreferredSim.PREFERRED_PHONE_ACCOUNT_ID
- },
- PreferredSim.DATA_ID + " = ?",
- new String[] {dataId},
- null)) {
- if (cursor == null) {
- return Optional.absent();
- }
- if (!cursor.moveToFirst()) {
- return Optional.absent();
- }
- return PreferredAccountUtil.getValidPhoneAccount(
- context, cursor.getString(0), cursor.getString(1));
- }
- }
-
private class SelectedListener extends SelectPhoneAccountListener {
private final PreCallCoordinator coordinator;
private final PreCallCoordinator.PendingAction listener;
- private final String dataId;
- private final String number;
- private final Suggestion suggestion;
+ private final PreferredAccountRecorder recorder;
public SelectedListener(
@NonNull PreCallCoordinator builder,
@NonNull PreCallCoordinator.PendingAction listener,
- @Nullable String dataId,
- @Nullable String number,
- @Nullable Suggestion suggestion) {
+ @NonNull PreferredAccountRecorder recorder) {
this.coordinator = Assert.isNotNull(builder);
this.listener = Assert.isNotNull(listener);
- this.dataId = dataId;
- this.number = number;
- this.suggestion = suggestion;
+ this.recorder = Assert.isNotNull(recorder);
}
@MainThread
@Override
public void onPhoneAccountSelected(
PhoneAccountHandle selectedAccountHandle, boolean setDefault, @Nullable String callId) {
- if (suggestion != null) {
- if (suggestion.phoneAccountHandle.equals(selectedAccountHandle)) {
- Logger.get(coordinator.getActivity())
- .logImpression(DialerImpression.Type.DUAL_SIM_SELECTION_SUGGESTED_SIM_SELECTED);
- } else {
- Logger.get(coordinator.getActivity())
- .logImpression(DialerImpression.Type.DUAL_SIM_SELECTION_NON_SUGGESTED_SIM_SELECTED);
- }
- }
coordinator.getBuilder().setPhoneAccountHandle(selectedAccountHandle);
-
- if (dataId != null && setDefault) {
- Logger.get(coordinator.getActivity())
- .logImpression(DialerImpression.Type.DUAL_SIM_SELECTION_PREFERRED_SET);
- DialerExecutorComponent.get(coordinator.getActivity())
- .dialerExecutorFactory()
- .createNonUiTaskBuilder(new WritePreferredAccountWorker())
- .build()
- .executeParallel(
- new WritePreferredAccountWorkerInput(
- coordinator.getActivity(), dataId, selectedAccountHandle));
- }
- if (number != null) {
- DialerExecutorComponent.get(coordinator.getActivity())
- .dialerExecutorFactory()
- .createNonUiTaskBuilder(
- new UserSelectionReporter(selectedAccountHandle, number, setDefault))
- .build()
- .executeParallel(coordinator.getActivity());
- }
+ recorder.record(coordinator.getActivity(), selectedAccountHandle, setDefault);
listener.finish();
}
@@ -507,103 +266,4 @@ public class CallingAccountSelector implements PreCallAction {
listener.finish();
}
}
-
- private static class UserSelectionReporter implements Worker<Context, Void> {
-
- private final String number;
- private final PhoneAccountHandle phoneAccountHandle;
- private final boolean remember;
-
- public UserSelectionReporter(
- @NonNull PhoneAccountHandle phoneAccountHandle, @Nullable String number, boolean remember) {
- this.phoneAccountHandle = Assert.isNotNull(phoneAccountHandle);
- this.number = Assert.isNotNull(number);
- this.remember = remember;
- }
-
- @Nullable
- @Override
- public Void doInBackground(@NonNull Context context) throws Throwable {
- SimSuggestionComponent.get(context)
- .getSuggestionProvider()
- .reportUserSelection(context, number, phoneAccountHandle, remember);
- return null;
- }
- }
-
- private static class WritePreferredAccountWorkerInput {
- private final Context context;
- private final String dataId;
- private final PhoneAccountHandle phoneAccountHandle;
-
- WritePreferredAccountWorkerInput(
- @NonNull Context context,
- @NonNull String dataId,
- @NonNull PhoneAccountHandle phoneAccountHandle) {
- this.context = Assert.isNotNull(context);
- this.dataId = Assert.isNotNull(dataId);
- this.phoneAccountHandle = Assert.isNotNull(phoneAccountHandle);
- }
- }
-
- private static class WritePreferredAccountWorker
- implements Worker<WritePreferredAccountWorkerInput, Void> {
-
- @Nullable
- @Override
- @WorkerThread
- public Void doInBackground(WritePreferredAccountWorkerInput input) throws Throwable {
- ContentValues values = new ContentValues();
- values.put(
- PreferredSim.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME,
- input.phoneAccountHandle.getComponentName().flattenToString());
- values.put(PreferredSim.PREFERRED_PHONE_ACCOUNT_ID, input.phoneAccountHandle.getId());
- input
- .context
- .getContentResolver()
- .update(
- PreferredSimFallbackContract.CONTENT_URI,
- values,
- PreferredSim.DATA_ID + " = ?",
- new String[] {String.valueOf(input.dataId)});
- return null;
- }
- }
-
- @WorkerThread
- private static boolean isPreferredSimEnabled(Context context) {
- Assert.isWorkerThread();
- if (!ConfigProviderBindings.get(context).getBoolean("preferred_sim_enabled", true)) {
- return false;
- }
-
- Intent quickContactIntent = getQuickContactIntent();
- ResolveInfo resolveInfo =
- context
- .getPackageManager()
- .resolveActivity(quickContactIntent, PackageManager.GET_META_DATA);
- if (resolveInfo == null
- || resolveInfo.activityInfo == null
- || resolveInfo.activityInfo.applicationInfo == null
- || resolveInfo.activityInfo.applicationInfo.metaData == null) {
- LogUtil.e("CallingAccountSelector.isPreferredSimEnabled", "cannot resolve quick contact app");
- return false;
- }
- if (!resolveInfo.activityInfo.applicationInfo.metaData.getBoolean(
- METADATA_SUPPORTS_PREFERRED_SIM, false)) {
- LogUtil.i(
- "CallingAccountSelector.isPreferredSimEnabled",
- "system contacts does not support preferred SIM");
- return false;
- }
- return true;
- }
-
- @VisibleForTesting
- static Intent getQuickContactIntent() {
- Intent intent = new Intent(QuickContact.ACTION_QUICK_CONTACT);
- intent.addCategory(Intent.CATEGORY_DEFAULT);
- intent.setData(Contacts.CONTENT_URI.buildUpon().appendPath("1").build());
- return intent;
- }
}
diff --git a/java/com/android/dialer/precall/impl/res/values/strings.xml b/java/com/android/dialer/precall/impl/res/values/strings.xml
index 0b59607b6..4bd5d36f2 100644
--- a/java/com/android/dialer/precall/impl/res/values/strings.xml
+++ b/java/com/android/dialer/precall/impl/res/values/strings.xml
@@ -26,12 +26,4 @@
same contact and never ask again [CHAR LIMIT=40]-->
<string name="pre_call_select_phone_account_remember">Remember this choice</string>
- <!-- Hint text under a SIM when selecting SIM to call, indicating the SIM is on the same carrier
- as the outgoing call.[CHAR LIMIT=40]-->
- <string name="pre_call_select_phone_account_hint_intra_carrier">Uses same carrier</string>
-
- <!-- Hint text under a SIM when selecting SIM to call, indicating user often use the SIM to call
- the contact.[CHAR LIMIT=40]-->
- <string name="pre_call_select_phone_account_hint_frequent">Recently used</string>
-
</resources> \ No newline at end of file