diff options
13 files changed, 242 insertions, 20 deletions
diff --git a/java/com/android/dialer/app/AccountSelectionActivity.java b/java/com/android/dialer/app/AccountSelectionActivity.java new file mode 100644 index 000000000..88dfaf49f --- /dev/null +++ b/java/com/android/dialer/app/AccountSelectionActivity.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2018 The LineageOS 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.app; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.telecom.PhoneAccount; +import android.telecom.PhoneAccountHandle; +import android.text.TextUtils; + +import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment; +import com.android.dialer.callintent.CallInitiationType; +import com.android.dialer.callintent.CallIntentBuilder; +import com.android.dialer.util.CallUtil; + +import java.util.ArrayList; +import java.util.List; + +public class AccountSelectionActivity extends AppCompatActivity { + public static Intent createIntent(Context context, String number, + CallInitiationType.Type initiationType) { + if (TextUtils.isEmpty(number)) { + return null; + } + + List<PhoneAccount> accounts = + CallUtil.getCallCapablePhoneAccounts(context, PhoneAccount.SCHEME_TEL); + if (accounts == null || accounts.size() <= 1) { + return null; + } + ArrayList<PhoneAccountHandle> accountHandles = new ArrayList<>(); + for (PhoneAccount account : accounts) { + accountHandles.add(account.getAccountHandle()); + } + + return new Intent(context, AccountSelectionActivity.class) + .putExtra("number", number) + .putExtra("accountHandles", accountHandles) + .putExtra("type", initiationType.ordinal()); + } + + private String mNumber; + private CallInitiationType.Type mInitiationType; + + private SelectPhoneAccountDialogFragment.SelectPhoneAccountListener mListener = + new SelectPhoneAccountDialogFragment.SelectPhoneAccountListener() { + @Override + public void onPhoneAccountSelected(PhoneAccountHandle selectedAccountHandle, + boolean setDefault, String callId) { + Intent intent = new CallIntentBuilder(mNumber, mInitiationType) + .setPhoneAccountHandle(selectedAccountHandle) + .build(); + startActivity(intent); + finish(); + } + + @Override + public void onDialogDismissed(String callId) { + finish(); + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mNumber = getIntent().getStringExtra("number"); + mInitiationType = CallInitiationType.Type.values()[getIntent().getIntExtra("type", 0)]; + + if (getFragmentManager().findFragmentByTag("dialog") == null) { + List<PhoneAccountHandle> handles = getIntent().getParcelableArrayListExtra("accountHandles"); + SelectPhoneAccountDialogFragment dialog = SelectPhoneAccountDialogFragment.newInstance( + R.string.call_via_dialog_title, false, handles, mListener, null); + + dialog.show(getFragmentManager(), "dialog"); + } + } +} diff --git a/java/com/android/dialer/app/AndroidManifest.xml b/java/com/android/dialer/app/AndroidManifest.xml index 4200082a6..8e347d13d 100644 --- a/java/com/android/dialer/app/AndroidManifest.xml +++ b/java/com/android/dialer/app/AndroidManifest.xml @@ -78,6 +78,10 @@ android:theme="@style/DialtactsThemeWithoutActionBarOverlay"> </activity> + <activity android:name="com.android.dialer.app.AccountSelectionActivity" + android:theme="@style/TransparentTheme" + android:exported="false" /> + <receiver android:name="com.android.dialer.app.calllog.CallLogReceiver"> <intent-filter> <action android:name="android.intent.action.NEW_VOICEMAIL"/> diff --git a/java/com/android/dialer/app/DialtactsActivity.java b/java/com/android/dialer/app/DialtactsActivity.java index b6025d354..a96a7535d 100644 --- a/java/com/android/dialer/app/DialtactsActivity.java +++ b/java/com/android/dialer/app/DialtactsActivity.java @@ -799,9 +799,10 @@ public class DialtactsActivity extends TransactionSafeActivity String number = data.getStringExtra(CallDetailsActivity.EXTRA_PHONE_NUMBER); int snackbarDurationMillis = 5_000; Snackbar.make(mParentLayout, getString(R.string.ec_data_deleted), snackbarDurationMillis) - .setAction( - R.string.view_conversation, - v -> startActivity(IntentProvider.getSendSmsIntentProvider(number).getIntent(this))) + .setAction(R.string.view_conversation, v -> { + IntentProvider provider = IntentProvider.getSendSmsIntentProvider(number); + startActivity(provider.getClickIntent(this)); + }) .setActionTextColor(getResources().getColor(R.color.dialer_snackbar_action_text_color)) .show(); } diff --git a/java/com/android/dialer/app/calllog/CallLogActivity.java b/java/com/android/dialer/app/calllog/CallLogActivity.java index 35e05bc39..393c0cda1 100644 --- a/java/com/android/dialer/app/calllog/CallLogActivity.java +++ b/java/com/android/dialer/app/calllog/CallLogActivity.java @@ -251,9 +251,10 @@ public class CallLogActivity extends TransactionSafeActivity && data.getBooleanExtra(CallDetailsActivity.EXTRA_HAS_ENRICHED_CALL_DATA, false)) { String number = data.getStringExtra(CallDetailsActivity.EXTRA_PHONE_NUMBER); Snackbar.make(findViewById(R.id.calllog_frame), getString(R.string.ec_data_deleted), 5_000) - .setAction( - R.string.view_conversation, - v -> startActivity(IntentProvider.getSendSmsIntentProvider(number).getIntent(this))) + .setAction(R.string.view_conversation, v -> { + IntentProvider provider = IntentProvider.getSendSmsIntentProvider(number); + startActivity(provider.getClickIntent(this)); + }) .setActionTextColor(getResources().getColor(R.color.dialer_snackbar_action_text_color)) .show(); } diff --git a/java/com/android/dialer/app/calllog/CallLogAdapter.java b/java/com/android/dialer/app/calllog/CallLogAdapter.java index e0cd1706d..c696f1c05 100644 --- a/java/com/android/dialer/app/calllog/CallLogAdapter.java +++ b/java/com/android/dialer/app/calllog/CallLogAdapter.java @@ -390,7 +390,7 @@ public class CallLogAdapter extends GroupingListAdapter if (packageName == null) { return false; } - return packageName.equals(intentProvider.getIntent(mActivity).getPackage()); + return packageName.equals(intentProvider.getClickIntent(mActivity).getPackage()); } }; diff --git a/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java b/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java index 99c49b7af..3bf7db5f0 100644 --- a/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java +++ b/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java @@ -103,6 +103,7 @@ import java.lang.annotation.RetentionPolicy; */ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, + View.OnLongClickListener, MenuItem.OnMenuItemClickListener, View.OnCreateContextMenuListener { /** The root view of the call log list item */ @@ -300,6 +301,7 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder quickContactView.setPrioritizedMimeType(Phone.CONTENT_ITEM_TYPE); } primaryActionButtonView.setOnClickListener(this); + primaryActionButtonView.setOnLongClickListener(this); primaryActionView.setOnClickListener(mExpandCollapseListener); if (mVoicemailPlaybackPresenter != null && ConfigProviderBindings.get(mContext) @@ -504,6 +506,7 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder primaryActionButtonView.setContentDescription( TextUtils.expandTemplate( mContext.getString(R.string.description_voicemail_action), validNameOrNumber)); + primaryActionButtonView.setTag(null); primaryActionButtonView.setVisibility(View.VISIBLE); } else { primaryActionButtonView.setVisibility(View.GONE); @@ -880,7 +883,7 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder return; } - final Intent intent = intentProvider.getIntent(mContext); + final Intent intent = intentProvider.getClickIntent(mContext); // See IntentProvider.getCallDetailIntentProvider() for why this may be null. if (intent == null) { return; @@ -909,6 +912,18 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder } } + @Override + public boolean onLongClick(View view) { + final IntentProvider intentProvider = (IntentProvider) view.getTag(); + final Intent intent = intentProvider != null + ? intentProvider.getLongClickIntent(mContext) : null; + if (intent != null) { + DialerUtils.startActivityWithErrorToast(mContext, intent); + return true; + } + return false; + } + private void startLightbringerActivity(Intent intent) { try { Activity activity = (Activity) mContext; diff --git a/java/com/android/dialer/app/calllog/IntentProvider.java b/java/com/android/dialer/app/calllog/IntentProvider.java index 55fdbbace..2c4510ab0 100644 --- a/java/com/android/dialer/app/calllog/IntentProvider.java +++ b/java/com/android/dialer/app/calllog/IntentProvider.java @@ -24,6 +24,7 @@ import android.provider.ContactsContract; import android.telecom.PhoneAccountHandle; import com.android.contacts.common.model.Contact; import com.android.contacts.common.model.ContactLoader; +import com.android.dialer.app.AccountSelectionActivity; import com.android.dialer.calldetails.CallDetailsActivity; import com.android.dialer.calldetails.CallDetailsEntries; import com.android.dialer.callintent.CallInitiationType; @@ -51,11 +52,17 @@ public abstract class IntentProvider { final String number, final PhoneAccountHandle accountHandle) { return new IntentProvider() { @Override - public Intent getIntent(Context context) { + public Intent getClickIntent(Context context) { return new CallIntentBuilder(number, CallInitiationType.Type.CALL_LOG) .setPhoneAccountHandle(accountHandle) .build(); } + + @Override + public Intent getLongClickIntent(Context context) { + return AccountSelectionActivity.createIntent(context, number, + CallInitiationType.Type.CALL_LOG); + } }; } @@ -67,7 +74,7 @@ public abstract class IntentProvider { final String number, final PhoneAccountHandle accountHandle) { return new IntentProvider() { @Override - public Intent getIntent(Context context) { + public Intent getClickIntent(Context context) { return new CallIntentBuilder(number, CallInitiationType.Type.CALL_LOG) .setPhoneAccountHandle(accountHandle) .setIsVideoCall(true) @@ -79,7 +86,7 @@ public abstract class IntentProvider { public static IntentProvider getLightbringerIntentProvider(String number) { return new IntentProvider() { @Override - public Intent getIntent(Context context) { + public Intent getClickIntent(Context context) { return LightbringerComponent.get(context).getLightbringer().getIntent(context, number); } }; @@ -88,7 +95,7 @@ public abstract class IntentProvider { public static IntentProvider getReturnVoicemailCallIntentProvider() { return new IntentProvider() { @Override - public Intent getIntent(Context context) { + public Intent getClickIntent(Context context) { return new CallIntentBuilder(CallUtil.getVoicemailUri(), CallInitiationType.Type.CALL_LOG) .build(); } @@ -98,7 +105,7 @@ public abstract class IntentProvider { public static IntentProvider getSendSmsIntentProvider(final String number) { return new IntentProvider() { @Override - public Intent getIntent(Context context) { + public Intent getClickIntent(Context context) { return IntentUtil.getSendSmsIntent(number); } }; @@ -115,7 +122,7 @@ public abstract class IntentProvider { CallDetailsEntries callDetailsEntries, DialerContact contact, boolean canReportCallerId) { return new IntentProvider() { @Override - public Intent getIntent(Context context) { + public Intent getClickIntent(Context context) { return CallDetailsActivity.newInstance( context, callDetailsEntries, contact, canReportCallerId); } @@ -131,7 +138,7 @@ public abstract class IntentProvider { final boolean isNewContact) { return new IntentProvider() { @Override - public Intent getIntent(Context context) { + public Intent getClickIntent(Context context) { Contact contactToSave = null; if (lookupUri != null) { @@ -192,5 +199,8 @@ public abstract class IntentProvider { }; } - public abstract Intent getIntent(Context context); + public abstract Intent getClickIntent(Context context); + public Intent getLongClickIntent(Context context) { + return null; + } } diff --git a/java/com/android/dialer/app/dialpad/DialpadFragment.java b/java/com/android/dialer/app/dialpad/DialpadFragment.java index 3cd3ac27c..0a86148dc 100644 --- a/java/com/android/dialer/app/dialpad/DialpadFragment.java +++ b/java/com/android/dialer/app/dialpad/DialpadFragment.java @@ -47,6 +47,7 @@ import android.support.design.widget.FloatingActionButton; import android.support.v4.content.ContextCompat; import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; +import android.telecom.TelecomManager; import android.telephony.PhoneNumberFormattingTextWatcher; import android.telephony.PhoneNumberUtils; import android.telephony.TelephonyManager; @@ -60,6 +61,7 @@ import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; +import android.view.SubMenu; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; @@ -178,6 +180,8 @@ public class DialpadFragment extends Fragment private boolean mFirstLaunch = false; private boolean mAnimate = false; + private PhoneAccountHandle mSelectedAccount; + /** * Determines whether an add call operation is requested. * @@ -883,6 +887,37 @@ public class DialpadFragment extends Fragment item.setVisible(CallUtil.isCallWithSubjectSupported(getContext())); } } + + final MenuItem callWithItem = menu.findItem(R.id.call_with); + List<PhoneAccount> accounts = + CallUtil.getCallCapablePhoneAccounts(getContext(), PhoneAccount.SCHEME_TEL); + if (accounts != null && accounts.size() > 1) { + final PhoneAccountHandle selected; + if (mSelectedAccount != null) { + selected = mSelectedAccount; + } else { + selected = TelecomUtil.getDefaultOutgoingPhoneAccount(getContext(), + PhoneAccount.SCHEME_TEL); + } + + SubMenu callWithMenu = callWithItem.getSubMenu(); + callWithMenu.clear(); + + for (PhoneAccount account : accounts) { + final PhoneAccountHandle handle = account.getAccountHandle(); + final Intent intent = new Intent() + .putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, handle); + + callWithMenu.add(Menu.FIRST, Menu.NONE, Menu.NONE, account.getLabel()) + .setIntent(intent) + .setChecked(handle.equals(selected)); + } + callWithMenu.setGroupCheckable(Menu.FIRST, true, true); + callWithItem.setVisible(callWithMenu.hasVisibleItems()); + } else { + callWithItem.setVisible(false); + } + super.show(); } }; @@ -1042,8 +1077,9 @@ public class DialpadFragment extends Fragment // Clear the digits just in case. clearDialpad(); } else { - final Intent intent = - new CallIntentBuilder(number, CallInitiationType.Type.DIALPAD).build(); + final Intent intent = new CallIntentBuilder(number, CallInitiationType.Type.DIALPAD) + .setPhoneAccountHandle(mSelectedAccount) + .build(); DialerUtils.startActivityWithErrorToast(getActivity(), intent); hideAndClearDialpad(false); } @@ -1054,6 +1090,7 @@ public class DialpadFragment extends Fragment if (mDigits != null) { mDigits.getText().clear(); } + mSelectedAccount = null; } private void handleDialButtonClickWithEmptyDigits() { @@ -1282,6 +1319,11 @@ public class DialpadFragment extends Fragment @Override public boolean onMenuItemClick(MenuItem item) { + if (item.getGroupId() == Menu.FIRST) { + Intent intent = item.getIntent(); + mSelectedAccount = intent.getParcelableExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE); + return true; + } int resId = item.getItemId(); if (resId == R.id.menu_2s_pause) { updateDialString(PAUSE); diff --git a/java/com/android/dialer/app/res/menu/dialpad_options.xml b/java/com/android/dialer/app/res/menu/dialpad_options.xml index 2921ea3bb..760a004b4 100644 --- a/java/com/android/dialer/app/res/menu/dialpad_options.xml +++ b/java/com/android/dialer/app/res/menu/dialpad_options.xml @@ -14,7 +14,11 @@ limitations under the License. --> <menu xmlns:android="http://schemas.android.com/apk/res/android"> - + <item + android:id="@+id/call_with" + android:title="@string/call_via"> + <menu /> + </item> <item android:id="@+id/menu_2s_pause" android:showAsAction="withText" diff --git a/java/com/android/dialer/app/res/values/cm_strings.xml b/java/com/android/dialer/app/res/values/cm_strings.xml index b28dcaeb2..1e872c4a0 100644 --- a/java/com/android/dialer/app/res/values/cm_strings.xml +++ b/java/com/android/dialer/app/res/values/cm_strings.xml @@ -38,4 +38,7 @@ <string name="call_recording_format">Audio format</string> <string name="wb_amr_format" translatable="false">AMR-WB</string> <string name="aac_format" translatable="false">AAC</string> + + <string name="call_via">Call via</string> + <string name="call_via_dialog_title">Call via\u2026</string> </resources> diff --git a/java/com/android/dialer/app/res/values/styles.xml b/java/com/android/dialer/app/res/values/styles.xml index e0122e81c..66a0a1b19 100644 --- a/java/com/android/dialer/app/res/values/styles.xml +++ b/java/com/android/dialer/app/res/values/styles.xml @@ -87,6 +87,16 @@ <item name="android:textColorPrimary">#FFFFFF</item> </style> + <style name="TransparentTheme" parent="DialtactsTheme"> + <item name="android:alertDialogTheme">@style/AlertDialogTheme</item> + <item name="android:windowBackground">@android:color/transparent</item> + <item name="android:windowAnimationStyle">@android:style/Animation.Translucent</item> + <item name="android:windowContentOverlay">@null</item> + <item name="android:windowIsTranslucent">true</item> + <item name="android:windowNoTitle">true</item> + <item name="android:windowIsFloating">true</item> + </style> + <style name="DialtactsThemeWithoutActionBarOverlay" parent="DialtactsTheme"> <!-- Styles that require AppCompat compatibility, remember to update both sets --> <item name="android:windowActionBarOverlay">false</item> diff --git a/java/com/android/dialer/calldetails/CallDetailsHeaderViewHolder.java b/java/com/android/dialer/calldetails/CallDetailsHeaderViewHolder.java index ea12c4f95..22b740d38 100644 --- a/java/com/android/dialer/calldetails/CallDetailsHeaderViewHolder.java +++ b/java/com/android/dialer/calldetails/CallDetailsHeaderViewHolder.java @@ -17,15 +17,18 @@ package com.android.dialer.calldetails; import android.content.Context; +import android.content.Intent; import android.net.Uri; import android.support.v7.widget.RecyclerView; import android.telecom.PhoneAccount; import android.text.TextUtils; import android.view.View; import android.view.View.OnClickListener; +import android.view.View.OnLongClickListener; import android.widget.QuickContactBadge; import android.widget.TextView; import com.android.contacts.common.ContactPhotoManager; +import com.android.dialer.app.AccountSelectionActivity; import com.android.dialer.callintent.CallInitiationType; import com.android.dialer.callintent.CallIntentBuilder; import com.android.dialer.common.Assert; @@ -37,7 +40,7 @@ import com.android.dialer.util.DialerUtils; /** ViewHolder for Header/Contact in {@link CallDetailsActivity}. */ public class CallDetailsHeaderViewHolder extends RecyclerView.ViewHolder - implements OnClickListener { + implements OnClickListener, OnLongClickListener { private final View callBackButton; private final TextView nameView; @@ -58,6 +61,7 @@ public class CallDetailsHeaderViewHolder extends RecyclerView.ViewHolder contactPhoto = container.findViewById(R.id.quick_contact_photo); callBackButton.setOnClickListener(this); + callBackButton.setOnLongClickListener(this); Logger.get(context) .logQuickContactOnTouch( contactPhoto, InteractionEvent.Type.OPEN_QUICK_CONTACT_FROM_CALL_DETAILS, true); @@ -115,4 +119,17 @@ public class CallDetailsHeaderViewHolder extends RecyclerView.ViewHolder throw Assert.createIllegalStateFailException("View OnClickListener not implemented: " + view); } } + + @Override + public boolean onLongClick(View view) { + if (view == callBackButton) { + Intent intent = AccountSelectionActivity.createIntent(view.getContext(), + contact.getNumber(), CallInitiationType.Type.CALL_DETAILS); + if (intent != null) { + DialerUtils.startActivityWithErrorToast(view.getContext(), intent); + return true; + } + } + return false; + } } diff --git a/java/com/android/dialer/util/CallUtil.java b/java/com/android/dialer/util/CallUtil.java index 0afe930c9..99fd21f4f 100644 --- a/java/com/android/dialer/util/CallUtil.java +++ b/java/com/android/dialer/util/CallUtil.java @@ -24,6 +24,8 @@ import android.telecom.TelecomManager; import com.android.dialer.common.LogUtil; import com.android.dialer.compat.CompatUtils; import com.android.dialer.phonenumberutil.PhoneNumberHelper; + +import java.util.ArrayList; import java.util.List; /** Utilities related to calls that can be used by non system apps. */ @@ -99,6 +101,25 @@ public class CallUtil { } /** + * Returns a list of phone accounts that are able to call to numbers with the supplied scheme + */ + public static List<PhoneAccount> getCallCapablePhoneAccounts(Context context, String scheme) { + if (!PermissionsUtil.hasPermission(context, android.Manifest.permission.READ_PHONE_STATE)) { + return null; + } + TelecomManager tm = (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE); + final ArrayList<PhoneAccount> accounts = new ArrayList<>(); + + for (PhoneAccountHandle handle : tm.getCallCapablePhoneAccounts()) { + final PhoneAccount account = tm.getPhoneAccount(handle); + if (account != null && account.supportsUriScheme(scheme)) { + accounts.add(account); + } + } + return accounts; + } + + /** * Determines if one of the call capable phone accounts defined supports video calling. * * @param context The context. |