diff options
Diffstat (limited to 'src')
40 files changed, 856 insertions, 743 deletions
diff --git a/src/com/android/dialer/CallDetailActivity.java b/src/com/android/dialer/CallDetailActivity.java index f12e81cd3..d169c5d04 100644 --- a/src/com/android/dialer/CallDetailActivity.java +++ b/src/com/android/dialer/CallDetailActivity.java @@ -16,6 +16,7 @@ package com.android.dialer; +import android.app.Activity; import android.content.ComponentName; import android.content.ContentResolver; import android.content.ContentUris; @@ -34,10 +35,11 @@ import android.provider.ContactsContract.Contacts; import android.provider.ContactsContract.RawContacts; import android.provider.VoicemailContract.Voicemails; import android.telecom.PhoneAccount; -import android.telephony.SubscriptionManager; import android.telecom.PhoneAccountHandle; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import android.text.BidiFormatter; +import android.text.TextDirectionHeuristics; import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; @@ -47,6 +49,7 @@ import android.view.MenuItem; import android.view.View; import android.widget.LinearLayout; import android.widget.ListView; +import android.widget.QuickContactBadge; import android.widget.TextView; import android.widget.Toast; @@ -69,7 +72,7 @@ import com.android.dialer.voicemail.VoicemailPlaybackFragment; import com.android.dialer.voicemail.VoicemailStatusHelper; import com.android.dialer.voicemail.VoicemailStatusHelper.StatusMessage; import com.android.dialer.voicemail.VoicemailStatusHelperImpl; -import com.android.dialerbind.analytics.AnalyticsActivity; + import com.android.internal.telephony.PhoneConstants; import com.android.services.callrecorder.CallRecordingDataStore; @@ -81,12 +84,15 @@ import java.util.List; * This activity can be either started with the URI of a single call log entry, or with the * {@link #EXTRA_CALL_LOG_IDS} extra to specify a group of call log entries. */ -public class CallDetailActivity extends AnalyticsActivity implements ProximitySensorAware { +public class CallDetailActivity extends Activity implements ProximitySensorAware { private static final String TAG = "CallDetail"; private static final int LOADER_ID = 0; private static final String BUNDLE_CONTACT_URI_EXTRA = "contact_uri_extra"; + private static final char LEFT_TO_RIGHT_EMBEDDING = '\u202A'; + private static final char POP_DIRECTIONAL_FORMATTING = '\u202C'; + /** The time to wait before enabling the blank the screen due to the proximity sensor. */ private static final long PROXIMITY_BLANK_DELAY_MILLIS = 100; /** The time to wait before disabling the blank the screen due to the proximity sensor. */ @@ -114,6 +120,10 @@ public class CallDetailActivity extends AnalyticsActivity implements ProximitySe private CallDetailHeader mCallDetailHeader; private CallTypeHelper mCallTypeHelper; private PhoneNumberDisplayHelper mPhoneNumberHelper; + private QuickContactBadge mQuickContactBadge; + private TextView mCallerName; + private TextView mCallerNumber; + private TextView mAccountLabel; private AsyncTaskExecutor mAsyncTaskExecutor; private ContactInfoHelper mContactInfoHelper; @@ -134,6 +144,7 @@ public class CallDetailActivity extends AnalyticsActivity implements ProximitySe private LinearLayout mVoicemailHeader; private Uri mVoicemailUri; + private BidiFormatter mBidiFormatter = BidiFormatter.getInstance(); /** Whether we should show "edit number before call" in the options menu. */ private boolean mHasEditNumberBeforeCallOption; @@ -242,7 +253,7 @@ public class CallDetailActivity extends AnalyticsActivity implements ProximitySe mResources = getResources(); mCallTypeHelper = new CallTypeHelper(getResources()); - mPhoneNumberHelper = new PhoneNumberDisplayHelper(mResources); + mPhoneNumberHelper = new PhoneNumberDisplayHelper(this, mResources); mCallDetailHeader = new CallDetailHeader(this, mPhoneNumberHelper); mVoicemailStatusHelper = new VoicemailStatusHelperImpl(); mAsyncQueryHandler = new CallDetailActivityQueryHandler(this); @@ -375,7 +386,7 @@ public class CallDetailActivity extends AnalyticsActivity implements ProximitySe /** * Update user interface with details of given call. * - * @param callUris URIs into {@link CallLog.Calls} of the calls to be displayed + * @param callUris URIs into {@link android.provider.CallLog.Calls} of the calls to be displayed */ private void updateData(final Uri... callUris) { class UpdateContactDetailsTask extends AsyncTask<Void, Void, PhoneCallDetails[]> { @@ -399,9 +410,11 @@ public class CallDetailActivity extends AnalyticsActivity implements ProximitySe @Override public void onPostExecute(PhoneCallDetails[] details) { + Context context = CallDetailActivity.this; + if (details == null) { // Somewhere went wrong: we're going to bail out and show error to users. - Toast.makeText(CallDetailActivity.this, R.string.toast_call_detail_error, + Toast.makeText(context, R.string.toast_call_detail_error, Toast.LENGTH_SHORT).show(); finish(); return; @@ -412,17 +425,53 @@ public class CallDetailActivity extends AnalyticsActivity implements ProximitySe PhoneCallDetails firstDetails = details[0]; mNumber = firstDetails.number.toString(); final int numberPresentation = firstDetails.numberPresentation; - final int subId = firstDetails.accountId; // Set the details header, based on the first phone call. mCallDetailHeader.updateViews(firstDetails); + final Uri contactUri = firstDetails.contactUri; + final Uri photoUri = firstDetails.photoUri; + final PhoneAccountHandle accountHandle = firstDetails.accountHandle; + // Cache the details about the phone number. final boolean canPlaceCallsTo = PhoneNumberUtilsWrapper.canPlaceCallsTo(mNumber, numberPresentation); - final PhoneNumberUtilsWrapper phoneUtils = new PhoneNumberUtilsWrapper(); - final boolean isVoicemailNumber = phoneUtils.isVoicemailNumber(subId, mNumber); - final boolean isSipNumber = phoneUtils.isSipNumber(mNumber); + final PhoneNumberUtilsWrapper phoneUtils = new PhoneNumberUtilsWrapper(context); + final boolean isVoicemailNumber = + phoneUtils.isVoicemailNumber(accountHandle, mNumber); + final boolean isSipNumber = PhoneNumberUtilsWrapper.isSipNumber(mNumber); + + final CharSequence callLocationOrType = getNumberTypeOrLocation(firstDetails); + + final CharSequence displayNumber = + mPhoneNumberHelper.getDisplayNumber( + firstDetails.accountHandle, + firstDetails.number, + firstDetails.numberPresentation, + firstDetails.formattedNumber); + final String displayNumberStr = mBidiFormatter.unicodeWrap( + displayNumber.toString(), TextDirectionHeuristics.LTR); + + if (!TextUtils.isEmpty(firstDetails.name)) { + mCallerName.setText(firstDetails.name); + mCallerNumber.setText(callLocationOrType + " " + displayNumberStr); + } else { + mCallerName.setText(displayNumberStr); + if (!TextUtils.isEmpty(callLocationOrType)) { + mCallerNumber.setText(callLocationOrType); + mCallerNumber.setVisibility(View.VISIBLE); + } else { + mCallerNumber.setVisibility(View.GONE); + } + } + + String accountLabel = PhoneAccountUtils.getAccountLabel(context, accountHandle); + if (!TextUtils.isEmpty(accountLabel)) { + mAccountLabel.setText(accountLabel); + mAccountLabel.setVisibility(View.VISIBLE); + } else { + mAccountLabel.setVisibility(View.GONE); + } mHasEditNumberBeforeCallOption = canPlaceCallsTo && !isSipNumber && !isVoicemailNumber; @@ -430,10 +479,8 @@ public class CallDetailActivity extends AnalyticsActivity implements ProximitySe mHasRemoveFromCallLogOption = !hasVoicemail(); invalidateOptionsMenu(); - if (hasVoicemail() && !TextUtils.isEmpty(firstDetails.transcription)) { - mVoicemailTranscription.setText(firstDetails.transcription); - mVoicemailTranscription.setVisibility(View.VISIBLE); - } + String lookupKey = contactUri == null ? null + : ContactInfoHelper.getLookupKeyFromUri(contactUri); final boolean isBusiness = mContactInfoHelper.isBusiness(firstDetails.sourceType); @@ -448,6 +495,22 @@ public class CallDetailActivity extends AnalyticsActivity implements ProximitySe mCallTypeHelper, details, mCallRecordingDataStore, mCallRecordingPlayer)); mCallDetailHeader.loadContactPhotos(firstDetails, contactType); findViewById(R.id.call_detail).setVisibility(View.VISIBLE); + + String nameForDefaultImage; + if (TextUtils.isEmpty(firstDetails.name)) { + nameForDefaultImage = mPhoneNumberHelper.getDisplayNumber( + firstDetails.accountHandle, + firstDetails.number, + firstDetails.numberPresentation, + firstDetails.formattedNumber).toString(); + } else { + nameForDefaultImage = firstDetails.name.toString(); + } + + if (hasVoicemail() && !TextUtils.isEmpty(firstDetails.transcription)) { + mVoicemailTranscription.setText(firstDetails.transcription); + mVoicemailTranscription.setVisibility(View.VISIBLE); + } } /** @@ -490,15 +553,9 @@ public class CallDetailActivity extends AnalyticsActivity implements ProximitySe final String transcription = callCursor.getString(TRANSCRIPTION_COLUMN_INDEX); final int durationType = callCursor.getInt(DURATION_TYPE_COLUMN_INDEX); - final String accountLabel = PhoneAccountUtils.getAccountLabel(this, - PhoneAccountUtils.getAccount( + final PhoneAccountHandle accountHandle = PhoneAccountUtils.getAccount( callCursor.getString(ACCOUNT_COMPONENT_NAME), - callCursor.getString(ACCOUNT_ID))); - String accId = callCursor.getString(ACCOUNT_ID); - int subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; - if (accId!=null && !accId.equals("E") && !accId.toLowerCase().contains("sip")) { - subId = Integer.parseInt(accId); - } + callCursor.getString(ACCOUNT_ID)); if (TextUtils.isEmpty(countryIso)) { countryIso = mDefaultCountryIso; @@ -516,11 +573,11 @@ public class CallDetailActivity extends AnalyticsActivity implements ProximitySe // If this is not a regular number, there is no point in looking it up in the contacts. ContactInfo info = PhoneNumberUtilsWrapper.canPlaceCallsTo(number, numberPresentation) - && !new PhoneNumberUtilsWrapper().isVoicemailNumber(subId, number) + && !new PhoneNumberUtilsWrapper(this).isVoicemailNumber(accountHandle, number) ? mContactInfoHelper.lookupNumber(number, countryIso) : null; if (info == null) { - formattedNumber = mPhoneNumberHelper.getDisplayNumber(subId, number, + formattedNumber = mPhoneNumberHelper.getDisplayNumber(accountHandle, number, numberPresentation, null); nameText = ""; numberType = 0; @@ -546,7 +603,7 @@ public class CallDetailActivity extends AnalyticsActivity implements ProximitySe formattedNumber, countryIso, geocode, new int[]{ callType }, date, duration, nameText, numberType, numberLabel, lookupUri, photoUri, sourceType, - accountLabel, null, features, dataUsage, transcription, subId, durationType); + accountHandle, features, dataUsage, transcription, durationType); } finally { if (callCursor != null) { callCursor.close(); diff --git a/src/com/android/dialer/CallDetailHeader.java b/src/com/android/dialer/CallDetailHeader.java index 43ab26737..16942417a 100644 --- a/src/com/android/dialer/CallDetailHeader.java +++ b/src/com/android/dialer/CallDetailHeader.java @@ -30,6 +30,7 @@ import android.provider.ContactsContract.CommonDataKinds.Phone; import android.provider.ContactsContract.Contacts; import android.provider.ContactsContract.RawContacts; import android.telecom.PhoneAccount; +import android.telecom.PhoneAccountHandle; import android.telephony.PhoneNumberUtils; import android.telephony.TelephonyManager; import android.text.BidiFormatter; @@ -50,6 +51,7 @@ import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest; import com.android.contacts.common.format.FormatUtils; import com.android.contacts.common.util.Constants; import com.android.dialer.calllog.ContactInfoHelper; +import com.android.dialer.calllog.PhoneAccountUtils; import com.android.dialer.calllog.PhoneNumberDisplayHelper; import com.android.dialer.calllog.PhoneNumberUtilsWrapper; @@ -86,8 +88,7 @@ public class CallDetailHeader { CharSequence getFormattedNumber(); Uri getContactUri(); Uri getPhotoUri(); - int getAccountId(); - CharSequence getAccountLabel(); + PhoneAccountHandle getAccountHandle(); CharSequence getGeocode(); } @@ -107,13 +108,14 @@ public class CallDetailHeader { public void updateViews(Data data) { // Cache the details about the phone number. - final PhoneNumberUtilsWrapper phoneUtils = new PhoneNumberUtilsWrapper(); + final PhoneNumberUtilsWrapper phoneUtils = new PhoneNumberUtilsWrapper(mActivity); final CharSequence dataName = data.getName(); final CharSequence dataNumber = data.getNumber(); - final CharSequence dataAccount = data.getAccountLabel(); + final CharSequence dataAccount = PhoneAccountUtils.getAccountLabel( + mActivity, data.getAccountHandle()); final CharSequence callLocationOrType = getNumberTypeOrLocation(data); - final CharSequence displayNumber = mPhoneNumberHelper.getDisplayNumber(data.getAccountId(), + final CharSequence displayNumber = mPhoneNumberHelper.getDisplayNumber(data.getAccountHandle(), dataNumber, data.getNumberPresentation(), data.getFormattedNumber()); final String displayNumberStr = mBidiFormatter.unicodeWrap( displayNumber.toString(), TextDirectionHeuristics.LTR); @@ -174,7 +176,7 @@ public class CallDetailHeader { String nameForDefaultImage; if (TextUtils.isEmpty(data.getName())) { nameForDefaultImage = mPhoneNumberHelper.getDisplayNumber( - data.getAccountId(), data.getNumber(), + data.getAccountHandle(), data.getNumber(), data.getNumberPresentation(), data.getFormattedNumber()).toString(); } else { nameForDefaultImage = data.getName().toString(); diff --git a/src/com/android/dialer/DialerApplication.java b/src/com/android/dialer/DialerApplication.java index e7881441a..c64530829 100644 --- a/src/com/android/dialer/DialerApplication.java +++ b/src/com/android/dialer/DialerApplication.java @@ -20,6 +20,7 @@ import android.app.Application; import com.android.contacts.common.ContactPhotoManager; import com.android.contacts.common.extensions.ExtensionsFactory; +import com.android.contacts.commonbind.analytics.AnalyticsUtil; public class DialerApplication extends Application { @@ -29,6 +30,7 @@ public class DialerApplication extends Application { public void onCreate() { super.onCreate(); ExtensionsFactory.init(getApplicationContext()); + AnalyticsUtil.initialize(this); } @Override diff --git a/src/com/android/dialer/DialtactsActivity.java b/src/com/android/dialer/DialtactsActivity.java index d8119e68b..d0b6ecfd7 100644 --- a/src/com/android/dialer/DialtactsActivity.java +++ b/src/com/android/dialer/DialtactsActivity.java @@ -66,12 +66,13 @@ import android.widget.Toast; import com.android.contacts.common.CallUtil; import com.android.contacts.common.SimContactsConstants; +import com.android.contacts.common.activity.TransactionSafeActivity; import com.android.contacts.common.dialog.ClearFrequentsDialog; import com.android.contacts.common.interactions.ImportExportDialogFragment; import com.android.contacts.common.interactions.TouchPointManager; import com.android.contacts.common.list.OnPhoneNumberPickerActionListener; import com.android.contacts.common.widget.FloatingActionButtonController; -import com.android.dialer.activity.TransactionSafeActivity; +import com.android.contacts.commonbind.analytics.AnalyticsUtil; import com.android.dialer.calllog.CallLogActivity; import com.android.dialer.database.DialerDatabaseHelper; import com.android.dialer.dialpad.DialpadFragment; @@ -93,7 +94,6 @@ import com.android.dialer.widget.ActionBarController; import com.android.dialer.widget.SearchEditTextLayout; import com.android.dialer.widget.SearchEditTextLayout.OnBackButtonClickedListener; import com.android.dialerbind.DatabaseHelperManager; -import com.android.incallui.CallCardFragment; import com.android.phone.common.animation.AnimUtils; import com.android.phone.common.util.SettingsUtil; import com.android.ims.ImsManager; @@ -156,7 +156,7 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O /** * Fragment containing the dialpad that slides into view */ - private DialpadFragment mDialpadFragment; + protected DialpadFragment mDialpadFragment; /** * Fragment for searching phone numbers using the alphanumeric keyboard. @@ -200,6 +200,7 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O * be commited. */ private boolean mStateSaved; + private boolean mIsRestarting; private boolean mInDialpadSearch; private boolean mInRegularSearch; private boolean mClearSearchOnPause; @@ -540,6 +541,15 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O } mFirstLaunch = false; + + if (mIsRestarting) { + // This is only called when the activity goes from resumed -> paused -> resumed, so it + // will not cause an extra view to be sent out on rotation + if (mIsDialpadShown) { + AnalyticsUtil.sendScreenView(mDialpadFragment, this); + } + mIsRestarting = false; + } prepareVoiceSearchButton(); updateFloatingActionButtonControllerAlignment(false /* animate */); setConferenceDialButtonImage(false); @@ -547,6 +557,12 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O } @Override + protected void onRestart() { + super.onRestart(); + mIsRestarting = true; + } + + @Override protected void onPause() { if (mClearSearchOnPause) { hideDialpadAndSearchUi(); @@ -754,7 +770,8 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O } mIsDialpadShown = true; mDialpadFragment.setAnimate(animate); - mDialpadFragment.sendScreenView(); + mListsFragment.setUserVisibleHint(false); + AnalyticsUtil.sendScreenView(mDialpadFragment); final FragmentTransaction ft = getFragmentManager().beginTransaction(); ft.show(mDialpadFragment); @@ -826,6 +843,8 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O } mIsDialpadShown = false; mDialpadFragment.setAnimate(animate); + mListsFragment.setUserVisibleHint(true); + mListsFragment.sendScreenViewForCurrentPosition(); updateSearchFragmentPosition(); mFloatingActionButton.setImageResource(R.drawable.fab_ic_dial); @@ -1054,6 +1073,7 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O transaction.commit(); mListsFragment.getView().animate().alpha(0).withLayer(); + mListsFragment.setUserVisibleHint(false); } /** @@ -1079,14 +1099,15 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O transaction.commit(); mListsFragment.getView().animate().alpha(1).withLayer(); - mActionBarController.onSearchUiExited(); - } + if (!mDialpadFragment.isVisible()) { + // If the dialpad fragment wasn't previously visible, then send a screen view because + // we are exiting regular search. Otherwise, the screen view will be sent by + // {@link #hideDialpadFragment}. + mListsFragment.sendScreenViewForCurrentPosition(); + mListsFragment.setUserVisibleHint(true); + } - /** Returns an Intent to launch Call Settings screen */ - public static Intent getCallSettingsIntent() { - final Intent intent = new Intent(TelecomManager.ACTION_SHOW_CALL_SETTINGS); - intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - return intent; + mActionBarController.onSearchUiExited(); } @Override @@ -1358,6 +1379,11 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O return mActionBarController.isActionBarShowing(); } + @Override + public ActionBarController getActionBarController() { + return mActionBarController; + } + public boolean isDialpadShown() { return mIsDialpadShown; } @@ -1368,13 +1394,13 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O } @Override - public int getActionBarHeight() { - return mActionBarHeight; + public void setActionBarHideOffset(int offset) { + getActionBar().setHideOffset(offset); } @Override - public void setActionBarHideOffset(int hideOffset) { - mActionBarController.setHideOffset(hideOffset); + public int getActionBarHeight() { + return mActionBarHeight; } /** diff --git a/src/com/android/dialer/PhoneCallDetails.java b/src/com/android/dialer/PhoneCallDetails.java index 37c619888..bf1ed5635 100755 --- a/src/com/android/dialer/PhoneCallDetails.java +++ b/src/com/android/dialer/PhoneCallDetails.java @@ -22,6 +22,7 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.provider.CallLog.Calls; import android.provider.ContactsContract.CommonDataKinds.Phone; +import android.telecom.PhoneAccountHandle; import android.telephony.SubscriptionManager; /** @@ -70,15 +71,7 @@ public class PhoneCallDetails implements CallDetailHeader.Data { /** * The unique identifier for the account associated with the call. */ - public final String accountLabel; - /** - * The icon for the account associated with the call. - */ - public final Drawable accountIcon; - /** - * The account id associated with the call. - */ - public final int accountId; + public final PhoneAccountHandle accountHandle; /** * Features applicable to this call. */ @@ -110,39 +103,29 @@ public class PhoneCallDetails implements CallDetailHeader.Data { CharSequence formattedNumber, String countryIso, String geocode, int[] callTypes, long date, long duration) { this (number, numberPresentation, formattedNumber, countryIso, geocode, - callTypes, date, duration, "", 0, "", null, null, 0, null, null, 0, null, null, - DEFAULT_PHONE_ID); - } - - /** Create the details for a call with a number not associated with a contact. */ - public PhoneCallDetails(CharSequence number, int numberPresentation, - CharSequence formattedNumber, String countryIso, String geocode, - int[] callTypes, long date, long duration, String accountLabel, Drawable accountIcon, - int features, Long dataUsage, String transcription) { - this(number, numberPresentation, formattedNumber, countryIso, geocode, - callTypes, date, duration, "", 0, "", null, null, 0, accountLabel, accountIcon, - features, dataUsage, transcription, DEFAULT_PHONE_ID); + callTypes, date, duration, "", 0, "", null, null, 0, null, 0, null, null); } /** Create the details for a call with a number not associated with a contact. */ public PhoneCallDetails(CharSequence number, int numberPresentation, CharSequence formattedNumber, String countryIso, String geocode, - int[] callTypes, long date, long duration, String accountLabel, Drawable accountIcon, - int features, Long dataUsage, String transcription, int accountId) { + int[] callTypes, long date, long duration, + PhoneAccountHandle accountHandle, int features, Long dataUsage, String transcription) { this(number, numberPresentation, formattedNumber, countryIso, geocode, - callTypes, date, duration, "", 0, "", null, null, 0, accountLabel, accountIcon, - features, dataUsage, transcription, accountId); + callTypes, date, duration, "", 0, "", null, null, 0, accountHandle, + features, dataUsage, transcription); } public PhoneCallDetails(CharSequence number, int numberPresentation, CharSequence formattedNumber, String countryIso, String geocode, int[] callTypes, long date, long duration, CharSequence name, int numberType, CharSequence numberLabel, Uri contactUri, - Uri photoUri, int sourceType, String accountLabel, Drawable accountIcon, int features, - Long dataUsage, String transcription, int accountId) { + Uri photoUri, int sourceType, + PhoneAccountHandle accountHandle, int features, + Long dataUsage, String transcription) { this(number, numberPresentation, formattedNumber, countryIso, geocode, callTypes, date, duration, name, numberType, numberLabel, contactUri, photoUri, sourceType, - accountLabel, accountIcon, features, dataUsage, transcription, accountId, + accountHandle, features, dataUsage, transcription, Calls.DURATION_TYPE_ACTIVE); } @@ -151,8 +134,9 @@ public class PhoneCallDetails implements CallDetailHeader.Data { CharSequence formattedNumber, String countryIso, String geocode, int[] callTypes, long date, long duration, CharSequence name, int numberType, CharSequence numberLabel, Uri contactUri, - Uri photoUri, int sourceType, String accountLabel, Drawable accountIcon, int features, - Long dataUsage, String transcription, int accountId, int durationType) { + Uri photoUri, int sourceType, + PhoneAccountHandle accountHandle, int features, + Long dataUsage, String transcription, int durationType) { this.number = number; this.numberPresentation = numberPresentation; this.formattedNumber = formattedNumber; @@ -167,12 +151,10 @@ public class PhoneCallDetails implements CallDetailHeader.Data { this.contactUri = contactUri; this.photoUri = photoUri; this.sourceType = sourceType; - this.accountLabel = accountLabel; - this.accountIcon = accountIcon; + this.accountHandle = accountHandle; this.features = features; this.dataUsage = dataUsage; this.transcription = transcription; - this.accountId = accountId; this.durationType = durationType; } @@ -209,12 +191,8 @@ public class PhoneCallDetails implements CallDetailHeader.Data { return photoUri; } @Override - public int getAccountId() { - return accountId; - } - @Override - public CharSequence getAccountLabel() { - return accountLabel; + public PhoneAccountHandle getAccountHandle() { + return accountHandle; } @Override public CharSequence getGeocode() { diff --git a/src/com/android/dialer/PhoneCallDetailsHelper.java b/src/com/android/dialer/PhoneCallDetailsHelper.java index b1f7fd105..a63674ef6 100644 --- a/src/com/android/dialer/PhoneCallDetailsHelper.java +++ b/src/com/android/dialer/PhoneCallDetailsHelper.java @@ -16,12 +16,15 @@ package com.android.dialer; +import android.content.Context; import android.content.res.Resources; +import android.graphics.drawable.Drawable; import android.provider.CallLog; import android.provider.CallLog.Calls; import android.provider.ContactsContract.CommonDataKinds.Phone; import android.telephony.SubscriptionManager; import android.graphics.Typeface; +import android.telecom.PhoneAccount; import android.text.SpannableString; import android.text.Spanned; import android.text.TextUtils; @@ -33,11 +36,12 @@ import android.widget.TextView; import com.android.contacts.common.CallUtil; import com.android.contacts.common.testing.NeededForTesting; import com.android.contacts.common.util.PhoneNumberHelper; -import com.android.dialer.calllog.CallTypeHelper; import com.android.dialer.calllog.ContactInfo; +import com.android.dialer.calllog.PhoneAccountUtils; import com.android.dialer.calllog.PhoneNumberDisplayHelper; import com.android.dialer.calllog.PhoneNumberUtilsWrapper; import com.android.dialer.util.DialerUtils; + import com.google.common.collect.Lists; import java.util.ArrayList; @@ -49,6 +53,7 @@ public class PhoneCallDetailsHelper { /** The maximum number of icons will be shown to represent the call types in a group. */ private static final int MAX_CALL_TYPE_ICONS = 3; + private final Context mContext; private final Resources mResources; /** The injected current time in milliseconds since the epoch. Used only by tests. */ private Long mCurrentTimeMillisForTest; @@ -68,11 +73,12 @@ public class PhoneCallDetailsHelper { * * @param resources used to look up strings */ - public PhoneCallDetailsHelper(Resources resources, CallTypeHelper callTypeHelper, + public PhoneCallDetailsHelper(Context context, Resources resources, PhoneNumberUtilsWrapper phoneUtils) { + mContext = context; mResources = resources; mPhoneNumberUtilsWrapper = phoneUtils; - mPhoneNumberHelper = new PhoneNumberDisplayHelper(mPhoneNumberUtilsWrapper, resources); + mPhoneNumberHelper = new PhoneNumberDisplayHelper(context, resources, phoneUtils); } /** Fills the call details views with content. */ @@ -113,17 +119,26 @@ public class PhoneCallDetailsHelper { // Set the call count, location and date. setCallCountAndDate(views, callCount, callLocationAndDate); - // set the account icon if it exists - if (details.accountIcon != null) { - views.callAccountIcon.setVisibility(View.VISIBLE); - views.callAccountIcon.setImageDrawable(details.accountIcon); + // Set the account label if it exists. + String accountLabel = PhoneAccountUtils.getAccountLabel(mContext, details.accountHandle); + + if (accountLabel != null) { + views.callAccountLabel.setVisibility(View.VISIBLE); + views.callAccountLabel.setText(accountLabel); + int color = PhoneAccountUtils.getAccountColor(mContext, details.accountHandle); + if (color == PhoneAccount.NO_HIGHLIGHT_COLOR) { + int defaultColor = R.color.dialtacts_secondary_text_color; + views.callAccountLabel.setTextColor(mContext.getResources().getColor(defaultColor)); + } else { + views.callAccountLabel.setTextColor(color); + } } else { - views.callAccountIcon.setVisibility(View.GONE); + views.callAccountLabel.setVisibility(View.GONE); } CharSequence nameText; CharSequence displayNumber = - mPhoneNumberHelper.getDisplayNumber(details.accountId, details.number, + mPhoneNumberHelper.getDisplayNumber(details.accountHandle, details.number, details.numberPresentation, details.formattedNumber); String phoneNum = (String) details.number; if (!TextUtils.isEmpty(filter) && phoneNum.contains(filter)) { @@ -199,7 +214,8 @@ public class PhoneCallDetailsHelper { // Only show a label if the number is shown and it is not a SIP address. if (!TextUtils.isEmpty(details.number) && !PhoneNumberHelper.isUriNumber(details.number.toString()) - && !mPhoneNumberUtilsWrapper.isVoicemailNumber(details.accountId, details.number)) { + && !mPhoneNumberUtilsWrapper.isVoicemailNumber(details.accountHandle, + details.number)) { if (details.numberLabel == ContactInfo.GEOCODE_AS_LABEL) { numberFormattedLabel = details.geocode; @@ -210,7 +226,7 @@ public class PhoneCallDetailsHelper { } if (!TextUtils.isEmpty(details.name) && TextUtils.isEmpty(numberFormattedLabel)) { - numberFormattedLabel = mPhoneNumberHelper.getDisplayNumber(details.accountId, + numberFormattedLabel = mPhoneNumberHelper.getDisplayNumber(details.accountHandle, details.number, details.numberPresentation, details.formattedNumber); } return numberFormattedLabel; @@ -234,9 +250,9 @@ public class PhoneCallDetailsHelper { public void setCallDetailsHeader(TextView nameView, PhoneCallDetails details) { final CharSequence nameText; final CharSequence displayNumber = - mPhoneNumberHelper.getDisplayNumber(details.accountId, details.number, - details.numberPresentation, - mResources.getString(R.string.recentCalls_addToContact)); + mPhoneNumberHelper.getDisplayNumber(details.accountHandle, details.number, + details.numberPresentation, + mResources.getString(R.string.recentCalls_addToContact)); if (TextUtils.isEmpty(details.name)) { nameText = displayNumber; } else { diff --git a/src/com/android/dialer/PhoneCallDetailsViews.java b/src/com/android/dialer/PhoneCallDetailsViews.java index 67babc1f7..05026d6ee 100644 --- a/src/com/android/dialer/PhoneCallDetailsViews.java +++ b/src/com/android/dialer/PhoneCallDetailsViews.java @@ -30,19 +30,19 @@ public final class PhoneCallDetailsViews { public final TextView nameView; public final View callTypeView; public final CallTypeIconsView callTypeIcons; - public final ImageView callAccountIcon; public final TextView callLocationAndDate; public final TextView voicemailTranscriptionView; + public final TextView callAccountLabel; private PhoneCallDetailsViews(TextView nameView, View callTypeView, - CallTypeIconsView callTypeIcons, ImageView callAccountIcon, - TextView callLocationAndDate, TextView voicemailTranscriptionView) { + CallTypeIconsView callTypeIcons, TextView callLocationAndDate, + TextView voicemailTranscriptionView, TextView callAccountLabel) { this.nameView = nameView; this.callTypeView = callTypeView; this.callTypeIcons = callTypeIcons; - this.callAccountIcon = callAccountIcon; this.callLocationAndDate = callLocationAndDate; this.voicemailTranscriptionView = voicemailTranscriptionView; + this.callAccountLabel = callAccountLabel; } /** @@ -56,9 +56,9 @@ public final class PhoneCallDetailsViews { return new PhoneCallDetailsViews((TextView) view.findViewById(R.id.name), view.findViewById(R.id.call_type), (CallTypeIconsView) view.findViewById(R.id.call_type_icons), - (ImageView) view.findViewById(R.id.call_account_icon), (TextView) view.findViewById(R.id.call_location_and_date), - (TextView) view.findViewById(R.id.voicemail_transcription)); + (TextView) view.findViewById(R.id.voicemail_transcription), + (TextView) view.findViewById(R.id.call_account_label)); } public static PhoneCallDetailsViews createForTest(Context context) { @@ -66,7 +66,7 @@ public final class PhoneCallDetailsViews { new TextView(context), new View(context), new CallTypeIconsView(context), - new ImageView(context), + new TextView(context), new TextView(context), new TextView(context)); } diff --git a/src/com/android/dialer/SpecialCharSequenceMgr.java b/src/com/android/dialer/SpecialCharSequenceMgr.java index c3436021e..0c6054b89 100644 --- a/src/com/android/dialer/SpecialCharSequenceMgr.java +++ b/src/com/android/dialer/SpecialCharSequenceMgr.java @@ -16,6 +16,7 @@ package com.android.dialer; +import android.app.Activity; import android.app.AlertDialog; import android.app.KeyguardManager; import android.app.ProgressDialog; @@ -30,6 +31,7 @@ import android.os.Looper; import android.os.RemoteException; import android.os.ServiceManager; import android.provider.Settings; +import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.telephony.PhoneNumberUtils; import android.telephony.SubscriptionManager; @@ -41,7 +43,15 @@ import android.widget.Toast; import com.android.common.io.MoreCloseables; import com.android.contacts.common.database.NoNullCursorAsyncQueryHandler; +import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment; +import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment.SelectPhoneAccountListener; +import com.android.dialer.calllog.PhoneAccountUtils; import com.android.internal.telephony.ITelephony; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; + /** * Helper class to listen for some magic character sequences * that are handled specially by the dialer. @@ -87,23 +97,13 @@ public class SpecialCharSequenceMgr { } public static boolean handleChars(Context context, String input, EditText textField) { - return handleChars(context, input, false, textField); - } - - static boolean handleChars(Context context, String input) { - return handleChars(context, input, false, null); - } - - static boolean handleChars(Context context, String input, boolean useSystemWindow, - EditText textField) { - //get rid of the separators so that the string gets parsed correctly String dialString = PhoneNumberUtils.stripSeparators(input); if (context.getResources().getBoolean(R.bool.def_dialer_secretcode_enabled) || context.getResources().getBoolean(R.bool.def_dialer_settings_diagport_enabled)) { if (handlePRLVersion(context, dialString) - || handleIMEIDisplay(context, dialString, useSystemWindow) + || handleDeviceIdDisplay(context, dialString) || handleRegulatoryInfoDisplay(context, dialString) || handleEngineerModeDisplay(context, dialString) || handlePinEntry(context, dialString) @@ -115,7 +115,7 @@ public class SpecialCharSequenceMgr { } } else { if (handlePRLVersion(context, dialString) - || handleIMEIDisplay(context, dialString, useSystemWindow) + || handleDeviceIdDisplay(context, dialString) || handleRegulatoryInfoDisplay(context, dialString) || handleEngineerModeDisplay(context, dialString) || handlePinEntry(context, dialString) @@ -210,7 +210,7 @@ public class SpecialCharSequenceMgr { * This code works alongside the Asynchronous query handler {@link QueryHandler} * and query cancel handler implemented in {@link SimContactQueryCookie}. */ - static boolean handleAdnEntry(Context context, String input, EditText textField) { + static boolean handleAdnEntry(final Context context, String input, EditText textField) { /* ADN entries are of the form "N(N)(N)#" */ TelephonyManager telephonyManager = @@ -234,7 +234,7 @@ public class SpecialCharSequenceMgr { if ((len > 1) && (len < 5) && (input.endsWith("#"))) { try { // get the ordinal number of the sim contact - int index = Integer.parseInt(input.substring(0, len-1)); + final int index = Integer.parseInt(input.substring(0, len-1)); // The original code that navigated to a SIM Contacts list view did not // highlight the requested contact correctly, a requirement for PTCRB @@ -244,10 +244,10 @@ public class SpecialCharSequenceMgr { // the dialer text field. // create the async query handler - QueryHandler handler = new QueryHandler (context.getContentResolver()); + final QueryHandler handler = new QueryHandler (context.getContentResolver()); // create the cookie object - SimContactQueryCookie sc = new SimContactQueryCookie(index - 1, handler, + final SimContactQueryCookie sc = new SimContactQueryCookie(index - 1, handler, ADN_QUERY_TOKEN); // setup the cookie fields @@ -264,20 +264,38 @@ public class SpecialCharSequenceMgr { sc.progressDialog.getWindow().addFlags( WindowManager.LayoutParams.FLAG_BLUR_BEHIND); - // display the progress dialog - sc.progressDialog.show(); - - // run the query. - int subId = SubscriptionManager.getDefaultVoiceSubId(); - Uri uri = Uri.parse("content://icc/adn/subId/" + subId); - handler.startQuery(ADN_QUERY_TOKEN, sc, uri, - new String[]{ADN_PHONE_NUMBER_COLUMN_NAME}, null, null, null); - - if (sPreviousAdnQueryHandler != null) { - // It is harmless to call cancel() even after the handler's gone. - sPreviousAdnQueryHandler.cancel(); + final TelecomManager telecomManager = + (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE); + List<PhoneAccountHandle> subscriptionAccountHandles = + PhoneAccountUtils.getSubscriptionPhoneAccounts(context); + + boolean hasUserSelectedDefault = subscriptionAccountHandles.contains( + telecomManager.getUserSelectedOutgoingPhoneAccount()); + + if (subscriptionAccountHandles.size() == 1 || hasUserSelectedDefault) { + Uri uri = telecomManager.getAdnUriForPhoneAccount(null); + handleAdnQuery(handler, sc, uri); + } else if (subscriptionAccountHandles.size() > 1){ + SelectPhoneAccountListener listener = new SelectPhoneAccountListener() { + @Override + public void onPhoneAccountSelected(PhoneAccountHandle selectedAccountHandle, + boolean setDefault) { + Uri uri = + telecomManager.getAdnUriForPhoneAccount(selectedAccountHandle); + handleAdnQuery(handler, sc, uri); + //TODO: show error dialog if result isn't valid + } + @Override + public void onDialogDismissed() {} + }; + + SelectPhoneAccountDialogFragment.showAccountDialog( + ((Activity) context).getFragmentManager(), subscriptionAccountHandles, + listener); + } else { + return false; } - sPreviousAdnQueryHandler = handler; + return true; } catch (NumberFormatException ex) { // Ignore @@ -286,40 +304,84 @@ public class SpecialCharSequenceMgr { return false; } - static boolean handlePinEntry(Context context, String input) { + private static void handleAdnQuery(QueryHandler handler, SimContactQueryCookie cookie, + Uri uri) { + if (handler == null || cookie == null || uri == null) { + Log.w(TAG, "queryAdn parameters incorrect"); + return; + } + + // display the progress dialog + cookie.progressDialog.show(); + + // run the query. + handler.startQuery(ADN_QUERY_TOKEN, cookie, uri, new String[]{ADN_PHONE_NUMBER_COLUMN_NAME}, + null, null, null); + + if (sPreviousAdnQueryHandler != null) { + // It is harmless to call cancel() even after the handler's gone. + sPreviousAdnQueryHandler.cancel(); + } + sPreviousAdnQueryHandler = handler; + } + + static boolean handlePinEntry(Context context, final String input) { if ((input.startsWith("**04") || input.startsWith("**05")) && input.endsWith("#")) { - int subId = SubscriptionManager.getDefaultVoiceSubId(); - try { - return ITelephony.Stub.asInterface(ServiceManager.getService( - Context.TELEPHONY_SERVICE)).handlePinMmiForSubscriber(subId, input); - } catch(RemoteException ex) { - Log.e(TAG, "Remote Exception "+ex); - return false; + final TelecomManager telecomManager = + (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE); + List<PhoneAccountHandle> subscriptionAccountHandles = + PhoneAccountUtils.getSubscriptionPhoneAccounts(context); + boolean hasUserSelectedDefault = subscriptionAccountHandles.contains( + telecomManager.getUserSelectedOutgoingPhoneAccount()); + + if (subscriptionAccountHandles.size() == 1 || hasUserSelectedDefault) { + // Don't bring up the dialog for single-SIM or if the default outgoing account is + // a subscription account. + return telecomManager.handleMmi(input); + } else if (subscriptionAccountHandles.size() > 1){ + SelectPhoneAccountListener listener = new SelectPhoneAccountListener() { + @Override + public void onPhoneAccountSelected(PhoneAccountHandle selectedAccountHandle, + boolean setDefault) { + telecomManager.handleMmi(selectedAccountHandle, input); + //TODO: show error dialog if result isn't valid + } + @Override + public void onDialogDismissed() {} + }; + + SelectPhoneAccountDialogFragment.showAccountDialog( + ((Activity) context).getFragmentManager(), subscriptionAccountHandles, + listener); } + return true; } return false; } - static boolean handleIMEIDisplay(Context context, String input, boolean useSystemWindow) { + // TODO: Use TelephonyCapabilities.getDeviceIdLabel() to get the device id label instead of a + // hard-coded string. + static boolean handleDeviceIdDisplay(Context context, String input) { TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + if (telephonyManager != null && input.equals(MMI_IMEI_DISPLAY)) { - int phoneType; - int subId = SubscriptionManager.getDefaultVoiceSubId(); - phoneType = telephonyManager.getCurrentPhoneType(subId); - if (telephonyManager.isMultiSimEnabled()) { - return handleMSimIMEIDisplay(context, telephonyManager); - } + int labelResId = (telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) ? + R.string.imei : R.string.meid; - if (phoneType == TelephonyManager.PHONE_TYPE_GSM) { - showIMEIPanel(context, useSystemWindow, telephonyManager); - return true; - } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) { - showMEIDPanel(context, useSystemWindow, telephonyManager); - return true; + List<String> deviceIds = new ArrayList<String>(); + for (int slot = 0; slot < telephonyManager.getPhoneCount(); slot++) { + deviceIds.add(telephonyManager.getDeviceId(slot)); } - } + AlertDialog alert = new AlertDialog.Builder(context) + .setTitle(labelResId) + .setItems(deviceIds.toArray(new String[deviceIds.size()]), null) + .setPositiveButton(R.string.ok, null) + .setCancelable(false) + .show(); + return true; + } return false; } @@ -365,46 +427,6 @@ public class SpecialCharSequenceMgr { return false; } - // TODO: Combine showIMEIPanel() and showMEIDPanel() into a single - // generic "showDeviceIdPanel()" method, like in the apps/Phone - // version of SpecialCharSequenceMgr.java. (This will require moving - // the phone app's TelephonyCapabilities.getDeviceIdLabel() method - // into the telephony framework, though.) - - private static void showIMEIPanel(Context context, boolean useSystemWindow, - TelephonyManager telephonyManager) { - String imeiStr = null; - int subId = SubscriptionManager.getDefaultVoiceSubId(); - int slotId = SubscriptionManager.getSlotId(subId); - //In case of no-sim, slotId will be -1. - if (slotId < 0) slotId = 0; - imeiStr = telephonyManager.getDeviceId(slotId); - - AlertDialog alert = new AlertDialog.Builder(context) - .setTitle(R.string.imei) - .setMessage(imeiStr) - .setPositiveButton(android.R.string.ok, null) - .setCancelable(false) - .show(); - } - - private static void showMEIDPanel(Context context, boolean useSystemWindow, - TelephonyManager telephonyManager) { - String meidStr = null; - int subId = SubscriptionManager.getDefaultVoiceSubId(); - int slotId = SubscriptionManager.getSlotId(subId); - //In case of no-sim, slotId will be -1. - if (slotId < 0) slotId = 0; - meidStr = telephonyManager.getDeviceId(slotId); - - AlertDialog alert = new AlertDialog.Builder(context) - .setTitle(R.string.meid) - .setMessage(meidStr) - .setPositiveButton(android.R.string.ok, null) - .setCancelable(false) - .show(); - } - static boolean handleEngineerModeDisplay(Context context, String input) { if (input.equals(MMI_ENGINEER_MODE_DISPLAY)) { Intent intent = new Intent(SECRET_CODE_ACTION, @@ -513,12 +535,13 @@ public class SpecialCharSequenceMgr { // get the EditText to update or see if the request was cancelled. EditText text = sc.getTextField(); - // if the textview is valid, and the cursor is valid and postionable - // on the Nth number, then we update the text field and display a - // toast indicating the caller name. + // if the TextView is valid, and the cursor is valid and positionable on the + // Nth number, then we update the text field and display a toast indicating the + // caller name. if ((c != null) && (text != null) && (c.moveToPosition(sc.contactNum))) { String name = c.getString(c.getColumnIndexOrThrow(ADN_NAME_COLUMN_NAME)); - String number = c.getString(c.getColumnIndexOrThrow(ADN_PHONE_NUMBER_COLUMN_NAME)); + String number = + c.getString(c.getColumnIndexOrThrow(ADN_PHONE_NUMBER_COLUMN_NAME)); // fill the text in. text.getText().replace(0, 0, number); @@ -536,8 +559,8 @@ public class SpecialCharSequenceMgr { public void cancel() { mCanceled = true; - // Ask AsyncQueryHandler to cancel the whole request. This will fails when the - // query already started. + // Ask AsyncQueryHandler to cancel the whole request. This will fail when the query is + // already started. cancelOperation(ADN_QUERY_TOKEN); } } diff --git a/src/com/android/dialer/activity/TransactionSafeActivity.java b/src/com/android/dialer/activity/TransactionSafeActivity.java deleted file mode 100644 index d7a212021..000000000 --- a/src/com/android/dialer/activity/TransactionSafeActivity.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2014 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.activity; - -import android.app.Activity; -import android.os.Bundle; - -import com.android.dialerbind.analytics.AnalyticsActivity; - -/** - * A common superclass that keeps track of whether an {@link Activity} has saved its state yet or - * not. - */ -public abstract class TransactionSafeActivity extends AnalyticsActivity { - - private boolean mIsSafeToCommitTransactions; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mIsSafeToCommitTransactions = true; - } - - @Override - protected void onStart() { - super.onStart(); - mIsSafeToCommitTransactions = true; - } - - @Override - protected void onResume() { - super.onResume(); - mIsSafeToCommitTransactions = true; - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - mIsSafeToCommitTransactions = false; - } - - /** - * Returns true if it is safe to commit {@link FragmentTransaction}s at this time, based on - * whether {@link Activity#onSaveInstanceState} has been called or not. - * - * Make sure that the current activity calls into - * {@link super.onSaveInstanceState(Bundle outState)} (if that method is overridden), - * so the flag is properly set. - */ - public boolean isSafeToCommitTransactions() { - return mIsSafeToCommitTransactions; - } -} diff --git a/src/com/android/dialer/calllog/CallLogActivity.java b/src/com/android/dialer/calllog/CallLogActivity.java index bc3996360..ae2d12e94 100755 --- a/src/com/android/dialer/calllog/CallLogActivity.java +++ b/src/com/android/dialer/calllog/CallLogActivity.java @@ -17,12 +17,15 @@ package com.android.dialer.calllog; import android.app.ActionBar; import android.app.ActionBar.LayoutParams; +import android.app.Activity; import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentTransaction; +import android.app.ListFragment; import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.os.Handler; import android.support.v13.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; import android.text.TextUtils; @@ -40,14 +43,18 @@ import android.widget.SearchView.OnQueryTextListener; import com.android.contacts.common.interactions.TouchPointManager; import com.android.contacts.common.list.ViewPagerTabs; +import com.android.contacts.commonbind.analytics.AnalyticsUtil; import com.android.dialer.DialtactsActivity; import com.android.dialer.R; -import com.android.dialerbind.analytics.AnalyticsActivity; import com.android.dialer.callstats.CallStatsFragment; import com.android.dialer.widget.DoubleDatePickerDialog; -public class CallLogActivity extends AnalyticsActivity implements - DoubleDatePickerDialog.OnDateSetListener { +import com.android.dialer.voicemail.VoicemailStatusHelper; +import com.android.dialer.voicemail.VoicemailStatusHelperImpl; + +public class CallLogActivity extends Activity implements + ViewPager.OnPageChangeListener, DoubleDatePickerDialog.OnDateSetListener { + private Handler mHandler; private ViewPager mViewPager; private ViewPagerTabs mViewPagerTabs; private FragmentPagerAdapter mViewPagerAdapter; @@ -77,9 +84,9 @@ public class CallLogActivity extends AnalyticsActivity implements public Fragment getItem(int position) { switch (position) { case TAB_INDEX_MSIM: - mMSimCallsFragment = new MSimCallLogFragment(); - mMSimCallsFragment.setHasOptionsMenu(true); - return mMSimCallsFragment; + MSimCallLogFragment ms = new MSimCallLogFragment(); + ms.setHasOptionsMenu(true); + return ms; case TAB_INDEX_MSIM_STATS: return new CallStatsFragment(); } @@ -87,6 +94,21 @@ public class CallLogActivity extends AnalyticsActivity implements } @Override + public Object instantiateItem(ViewGroup container, int position) { + final ListFragment fragment = + (ListFragment) super.instantiateItem(container, position); + switch (position) { + case TAB_INDEX_MSIM: + mMSimCallsFragment = (MSimCallLogFragment)fragment; + break; + case TAB_INDEX_MSIM_STATS: + mStatsFragment = (CallStatsFragment)fragment; + break; + } + return fragment; + } + + @Override public CharSequence getPageTitle(int position) { return mTabTitles[position]; } @@ -404,4 +426,41 @@ public class CallLogActivity extends AnalyticsActivity implements break; } } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + mViewPagerTabs.onPageScrolled(position, positionOffset, positionOffsetPixels); + } + + @Override + public void onPageSelected(int position) { + if (isResumed()) { + sendScreenViewForChildFragment(position); + } + mViewPagerTabs.onPageSelected(position); + } + + @Override + public void onPageScrollStateChanged(int state) { + mViewPagerTabs.onPageScrollStateChanged(state); + } + + private void sendScreenViewForChildFragment(int position) { + AnalyticsUtil.sendScreenView(CallLogFragment.class.getSimpleName(), this, + getFragmentTagForPosition(position)); + } + + /** + * Returns the fragment located at the given position in the {@link ViewPagerAdapter}. May + * be null if the position is invalid. + */ + private String getFragmentTagForPosition(int position) { + switch (position) { + case TAB_INDEX_MSIM: + return "All"; + case TAB_INDEX_MSIM_STATS: + return "Stats"; + } + return null; + } } diff --git a/src/com/android/dialer/calllog/CallLogAdapter.java b/src/com/android/dialer/calllog/CallLogAdapter.java index 92dcf0d9e..f33668386 100755 --- a/src/com/android/dialer/calllog/CallLogAdapter.java +++ b/src/com/android/dialer/calllog/CallLogAdapter.java @@ -30,6 +30,7 @@ import android.provider.CallLog.Calls; import android.provider.ContactsContract; import android.provider.ContactsContract.PhoneLookup; import android.telecom.PhoneAccountHandle; +import android.telephony.PhoneNumberUtils; import android.telephony.SubscriptionManager; import android.text.TextUtils; import android.util.Log; @@ -48,6 +49,7 @@ import com.android.common.widget.GroupingListAdapter; import com.android.contacts.common.CallUtil; import com.android.contacts.common.ContactPhotoManager; import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest; +import com.android.contacts.common.util.PhoneNumberHelper; import com.android.contacts.common.model.Contact; import com.android.contacts.common.model.ContactLoader; import com.android.contacts.common.util.UriUtils; @@ -83,10 +85,10 @@ public class CallLogAdapter extends GroupingListAdapter /** Interface used to inform a parent UI element that a list item has been expanded. */ public interface CallItemExpandedListener { /** - * @param view The {@link CallLogListItemView} that represents the item that was clicked + * @param view The {@link View} that represents the item that was clicked * on. */ - public void onItemExpanded(CallLogListItemView view); + public void onItemExpanded(View view); /** * Retrieves the call log view for the specified call Id. If the view is not currently @@ -95,7 +97,7 @@ public class CallLogAdapter extends GroupingListAdapter * @param callId The call Id. * @return The call log view. */ - public CallLogListItemView getViewForCallId(long callId); + public View getViewForCallId(long callId); } /** Interface used to initiate a refresh of the content. */ @@ -153,6 +155,8 @@ public class CallLogAdapter extends GroupingListAdapter private final ContactPhotoManager mContactPhotoManager; /** Helper to parse and process phone numbers. */ private PhoneNumberDisplayHelper mPhoneNumberHelper; + /** Helper to access Telephony phone number utils class */ + protected final PhoneNumberUtilsWrapper mPhoneNumberUtilsWrapper; /** Helper to group call log entries. */ private final CallLogGroupBuilder mCallLogGroupBuilder; @@ -169,6 +173,7 @@ public class CallLogAdapter extends GroupingListAdapter private int mCallLogBackgroundColor; private int mExpandedBackgroundColor; private float mExpandedTranslationZ; + private int mPhotoSize; /** Listener for the primary or secondary actions in the list. * Primary opens the call details. @@ -188,7 +193,7 @@ public class CallLogAdapter extends GroupingListAdapter private final View.OnClickListener mExpandCollapseListener = new View.OnClickListener() { @Override public void onClick(View v) { - final CallLogListItemView callLogItem = (CallLogListItemView) v.getParent().getParent(); + final View callLogItem = (View) v.getParent().getParent(); handleRowExpanded(callLogItem, true /* animate */, false /* forceExpand */); } }; @@ -198,7 +203,7 @@ public class CallLogAdapter extends GroupingListAdapter public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, AccessibilityEvent event) { if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED) { - handleRowExpanded((CallLogListItemView) host, false /* animate */, + handleRowExpanded(host, false /* animate */, true /* forceExpand */); } return super.onRequestSendAccessibilityEvent(host, child, event); @@ -236,13 +241,15 @@ public class CallLogAdapter extends GroupingListAdapter mCallLogBackgroundColor = resources.getColor(R.color.background_dialer_list_items); mExpandedBackgroundColor = resources.getColor(R.color.call_log_expanded_background_color); mExpandedTranslationZ = resources.getDimension(R.dimen.call_log_expanded_translation_z); + mPhotoSize = resources.getDimensionPixelSize(R.dimen.contact_photo_size); mContactPhotoManager = ContactPhotoManager.getInstance(mContext); - mPhoneNumberHelper = new PhoneNumberDisplayHelper(resources); + mPhoneNumberHelper = new PhoneNumberDisplayHelper(mContext, resources); mAdapterHelper = new CallLogAdapterHelper(context, this, contactInfoHelper, mPhoneNumberHelper); - PhoneCallDetailsHelper phoneCallDetailsHelper = new PhoneCallDetailsHelper( - resources, callTypeHelper, new PhoneNumberUtilsWrapper()); + mPhoneNumberUtilsWrapper = new PhoneNumberUtilsWrapper(mContext); + PhoneCallDetailsHelper phoneCallDetailsHelper = + new PhoneCallDetailsHelper(mContext, resources, mPhoneNumberUtilsWrapper); mCallLogViewsHelper = new CallLogListItemHelper( phoneCallDetailsHelper, mPhoneNumberHelper, resources); @@ -289,8 +296,7 @@ public class CallLogAdapter extends GroupingListAdapter @Override protected View newChildView(Context context, ViewGroup parent) { LayoutInflater inflater = LayoutInflater.from(context); - CallLogListItemView view = - (CallLogListItemView) inflater.inflate(R.layout.call_log_list_item, parent, false); + View view = inflater.inflate(R.layout.call_log_list_item, parent, false); // Get the views to bind to and cache them. CallLogListItemViews views = CallLogListItemViews.fromView(view); @@ -325,14 +331,13 @@ public class CallLogAdapter extends GroupingListAdapter /** * Binds the views in the entry to the data in the call log. * - * @param view the view corresponding to this entry + * @param callLogItemView the view corresponding to this entry * @param c the cursor pointing to the entry in the call log * @param count the number of entries in the current item, greater than 1 if it is a group */ - private void bindView(View view, Cursor c, int count) { - view.setAccessibilityDelegate(mAccessibilityDelegate); - final CallLogListItemView callLogItemView = (CallLogListItemView) view; - final CallLogListItemViews views = (CallLogListItemViews) view.getTag(); + private void bindView(View callLogItemView, Cursor c, int count) { + callLogItemView.setAccessibilityDelegate(mAccessibilityDelegate); + final CallLogListItemViews views = (CallLogListItemViews) callLogItemView.getTag(); // Default case: an item in the call log. views.primaryActionView.setVisibility(View.VISIBLE); @@ -345,8 +350,6 @@ public class CallLogAdapter extends GroupingListAdapter final PhoneAccountHandle accountHandle = PhoneAccountUtils.getAccount( c.getString(CallLogQuery.ACCOUNT_COMPONENT_NAME), c.getString(CallLogQuery.ACCOUNT_ID)); - final Drawable accountIcon = PhoneAccountUtils.getAccountIcon(mContext, - accountHandle); final String countryIso = c.getString(CallLogQuery.COUNTRY_ISO); final long rowId = c.getLong(CallLogQuery.ID); @@ -378,7 +381,6 @@ public class CallLogAdapter extends GroupingListAdapter views.number = number; views.numberPresentation = numberPresentation; views.callType = callType; - // NOTE: This is currently not being used, but can be used in future versions. views.accountHandle = accountHandle; views.voicemailUri = c.getString(CallLogQuery.VOICEMAIL_URI); // Stash away the Ids of the calls so that we can support deleting a row in the call log. @@ -387,7 +389,7 @@ public class CallLogAdapter extends GroupingListAdapter final ContactInfo cachedContactInfo = getContactInfoFromCallLog(c); final boolean isVoicemailNumber = - PhoneNumberUtilsWrapper.INSTANCE.isVoicemailNumber(subId, number); + mPhoneNumberUtilsWrapper.isVoicemailNumber(accountHandle, number); // Where binding and not in the call log, use default behaviour of invoking a call when // tapping the primary view. @@ -397,7 +399,13 @@ public class CallLogAdapter extends GroupingListAdapter // Set return call intent, otherwise null. if (PhoneNumberUtilsWrapper.canPlaceCallsTo(number, numberPresentation)) { // Sets the primary action to call the number. - views.primaryActionView.setTag(IntentProvider.getReturnCallIntentProvider(number)); + if (isVoicemailNumber) { + views.primaryActionView.setTag( + IntentProvider.getReturnVoicemailCallIntentProvider()); + } else { + views.primaryActionView.setTag( + IntentProvider.getReturnCallIntentProvider(number)); + } } else { // Number is not callable, so hide button. views.primaryActionView.setTag(null); @@ -412,7 +420,7 @@ public class CallLogAdapter extends GroupingListAdapter } // Lookup contacts with this number - final ContactInfo info = mAdapterHelper.lookupContact( + final ContactInfo info = mAdapterHelper.lookupContact(accountHandle, number, numberPresentation, countryIso, cachedContactInfo); final Uri lookupUri = info.lookupUri; final String name = info.name; @@ -420,7 +428,8 @@ public class CallLogAdapter extends GroupingListAdapter final String label = info.label; final long photoId = info.photoId; final Uri photoUri = info.photoUri; - CharSequence formattedNumber = info.formattedNumber; + CharSequence formattedNumber = info.formattedNumber == null + ? null : PhoneNumberUtils.ttsSpanAsPhoneNumber(info.formattedNumber); final int[] callTypes = getCallTypes(c, count); final String geocode = c.getString(CallLogQuery.GEOCODED_LOCATION); final int sourceType = info.sourceType; @@ -448,14 +457,13 @@ public class CallLogAdapter extends GroupingListAdapter expandOrCollapseActions(callLogItemView, isExpanded(rowId)); if (TextUtils.isEmpty(name)) { - details = new PhoneCallDetails(number, numberPresentation, - formattedNumber, countryIso, geocode, callTypes, date, - duration, null, accountIcon, features, dataUsage, transcription, subId); + details = new PhoneCallDetails(number, numberPresentation, formattedNumber, countryIso, + geocode, callTypes, date, duration, accountHandle, features, dataUsage, + transcription); } else { - details = new PhoneCallDetails(number, numberPresentation, - formattedNumber, countryIso, geocode, callTypes, date, - duration, name, ntype, label, lookupUri, photoUri, sourceType, - null, accountIcon, features, dataUsage, transcription, subId); + details = new PhoneCallDetails(number, numberPresentation, formattedNumber, countryIso, + geocode, callTypes, date, duration, name, ntype, label, lookupUri, photoUri, + sourceType, accountHandle, features, dataUsage, transcription); } mCallLogViewsHelper.setPhoneCallDetails(mContext, views, details); @@ -473,9 +481,8 @@ public class CallLogAdapter extends GroupingListAdapter String nameForDefaultImage = null; if (TextUtils.isEmpty(name)) { - nameForDefaultImage = mPhoneNumberHelper.getDisplayNumber(details.accountId, - details.number, details.numberPresentation, - details.formattedNumber).toString(); + nameForDefaultImage = mPhoneNumberHelper.getDisplayNumber(details.accountHandle, + details.number, details.numberPresentation, details.formattedNumber).toString(); } else { nameForDefaultImage = name; } @@ -493,10 +500,9 @@ public class CallLogAdapter extends GroupingListAdapter contactAccount); } - // Listen for the first draw - mAdapterHelper.registerOnPreDrawListener(view); + mAdapterHelper.registerOnPreDrawListener(callLogItemView); - bindBadge(view, info, details, callType); + bindBadge(callLogItemView, info, details, callType); } /** @@ -565,12 +571,13 @@ public class CallLogAdapter extends GroupingListAdapter } /** - * Expands or collapses the view containing the CALLBACK, VOICEMAIL and DETAILS action buttons. + * Expands or collapses the view containing the CALLBACK/REDIAL, VOICEMAIL and DETAILS action + * buttons. * * @param callLogItem The call log entry parent view. * @param isExpanded The new expansion state of the view. */ - private void expandOrCollapseActions(CallLogListItemView callLogItem, boolean isExpanded) { + private void expandOrCollapseActions(View callLogItem, boolean isExpanded) { final CallLogListItemViews views = (CallLogListItemViews)callLogItem.getTag(); expandVoicemailTranscriptionView(views, isExpanded); @@ -660,7 +667,8 @@ public class CallLogAdapter extends GroupingListAdapter } /*** - * Binds click handlers and intents to the voicemail, details and callback action buttons. + * Binds text titles, click handlers and intents to the voicemail, details and callback action + * buttons. * * @param views The call log item views. */ @@ -669,11 +677,28 @@ public class CallLogAdapter extends GroupingListAdapter PhoneNumberUtilsWrapper.canPlaceCallsTo(views.number, views.numberPresentation); // Set return call intent, otherwise null. if (canPlaceCallToNumber) { - // Sets the primary action to call the number. - views.callBackButtonView.setTag( - IntentProvider.getReturnCallIntentProvider(views.number)); + boolean isVoicemailNumber = + mPhoneNumberUtilsWrapper.isVoicemailNumber(views.accountHandle, views.number); + if (isVoicemailNumber) { + // Make a general call to voicemail to ensure that if there are multiple accounts + // it does not call the voicemail number of a specific phone account. + views.callBackButtonView.setTag( + IntentProvider.getReturnVoicemailCallIntentProvider()); + } else { + // Sets the primary action to call the number. + views.callBackButtonView.setTag( + IntentProvider.getReturnCallIntentProvider(views.number)); + } views.callBackButtonView.setVisibility(View.VISIBLE); views.callBackButtonView.setOnClickListener(mActionListener); + + final int titleId; + if (views.callType == Calls.VOICEMAIL_TYPE || views.callType == Calls.OUTGOING_TYPE) { + titleId = R.string.call_log_action_redial; + } else { + titleId = R.string.call_log_action_call_back; + } + views.callBackButtonView.setText(mContext.getString(titleId)); } else { // Number is not callable, so hide button. views.callBackButtonView.setTag(null); @@ -739,16 +764,20 @@ public class CallLogAdapter extends GroupingListAdapter final ViewStub stub = (ViewStub) view.findViewById(R.id.link_stub); if (UriUtils.isEncodedContactUri(info.lookupUri)) { if (stub != null) { - final View inflated = stub.inflate(); - inflated.setVisibility(View.VISIBLE); - mBadgeContainer = inflated.findViewById(R.id.badge_link_container); - mBadgeImageView = (ImageView) inflated.findViewById(R.id.badge_image); - mBadgeText = (TextView) inflated.findViewById(R.id.badge_text); + mBadgeContainer = stub.inflate(); + } else { + mBadgeContainer = view.findViewById(R.id.badge_container); } - mBadgeContainer.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { + mBadgeContainer.setVisibility(View.VISIBLE); + mBadgeImageView = (ImageView) mBadgeContainer.findViewById(R.id.badge_image); + mBadgeText = (TextView) mBadgeContainer.findViewById(R.id.badge_text); + + final View clickableArea = mBadgeContainer.findViewById(R.id.badge_link_container); + if (clickableArea != null) { + clickableArea.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { // If no lookup uri is provided, we need to rely on what information // we have available; namely the phone number and name. if (info.lookupUri == null) { @@ -761,17 +790,16 @@ public class CallLogAdapter extends GroupingListAdapter } else { addContactFromLookupUri(info.lookupUri); } - } - }); + } + }); + } mBadgeImageView.setImageResource(R.drawable.ic_person_add_24dp); mBadgeText.setText(R.string.recentCalls_addToContact); } else { // Hide badge if it was previously shown. - if (stub == null) { - final View container = view.findViewById(R.id.badge_container); - if (container != null) { - container.setVisibility(View.GONE); - } + mBadgeContainer = view.findViewById(R.id.badge_container); + if (mBadgeContainer != null) { + mBadgeContainer.setVisibility(View.GONE); } } } @@ -925,7 +953,7 @@ public class CallLogAdapter extends GroupingListAdapter views.quickContactView.setOverlay(null); DefaultImageRequest request = new DefaultImageRequest(displayName, identifier, contactType, true /* isCircular */); - mContactPhotoManager.loadDirectoryPhoto(views.quickContactView, photoUri, account, + mContactPhotoManager.loadPhoto(views.quickContactView, photoUri, mPhotoSize, false /* darkTheme */, true /* isCircular */, request); } @@ -1051,7 +1079,7 @@ public class CallLogAdapter extends GroupingListAdapter * @param forceExpand Whether or not to force the call log row into an expanded state regardless * of its previous state */ - private void handleRowExpanded(CallLogListItemView view, boolean animate, boolean forceExpand) { + private void handleRowExpanded(View view, boolean animate, boolean forceExpand) { final CallLogListItemViews views = (CallLogListItemViews) view.getTag(); if (forceExpand && isExpanded(views.rowId)) { @@ -1072,7 +1100,7 @@ public class CallLogAdapter extends GroupingListAdapter // Animate the collapse of the previous item if it is still visible on screen. if (mPreviouslyExpanded != NONE_EXPANDED) { - CallLogListItemView previousItem = mCallItemExpandedListener.getViewForCallId( + View previousItem = mCallItemExpandedListener.getViewForCallId( mPreviouslyExpanded); if (previousItem != null) { diff --git a/src/com/android/dialer/calllog/CallLogAdapterHelper.java b/src/com/android/dialer/calllog/CallLogAdapterHelper.java index a16935cfe..31f9c2799 100644 --- a/src/com/android/dialer/calllog/CallLogAdapterHelper.java +++ b/src/com/android/dialer/calllog/CallLogAdapterHelper.java @@ -22,6 +22,7 @@ import android.net.Uri; import android.os.Handler; import android.os.Message; import android.provider.ContactsContract.PhoneLookup; +import android.telecom.PhoneAccountHandle; import android.text.TextUtils; import android.view.View; import android.view.ViewTreeObserver; @@ -402,14 +403,14 @@ public class CallLogAdapterHelper implements ViewTreeObserver.OnPreDrawListener } - public ContactInfo lookupContact(String number, int numberPresentation, + public ContactInfo lookupContact(PhoneAccountHandle accountHandle, String number, int numberPresentation, String countryIso, ContactInfo cachedContactInfo) { NumberWithCountryIso numberCountryIso = new NumberWithCountryIso(number, countryIso); ExpirableCache.CachedValue<ContactInfo> cachedInfo = mContactInfoCache.getCachedValue(numberCountryIso); ContactInfo info = cachedInfo == null ? null : cachedInfo.getValue(); if (!PhoneNumberUtilsWrapper.canPlaceCallsTo(number, numberPresentation) - || new PhoneNumberUtilsWrapper().isVoicemailNumber(number)) { + || new PhoneNumberUtilsWrapper(mContext).isVoicemailNumber(accountHandle, number)) { // If this is a number that cannot be dialed, there is no point in looking up a contact // for it. info = ContactInfo.EMPTY; diff --git a/src/com/android/dialer/calllog/CallLogFragment.java b/src/com/android/dialer/calllog/CallLogFragment.java index 16f64aaaf..de772dfd4 100644 --- a/src/com/android/dialer/calllog/CallLogFragment.java +++ b/src/com/android/dialer/calllog/CallLogFragment.java @@ -22,6 +22,7 @@ import android.animation.ValueAnimator; import android.app.Activity; import android.app.DialogFragment; import android.app.KeyguardManager; +import android.app.ListFragment; import android.content.Context; import android.content.Intent; import android.database.ContentObserver; @@ -51,7 +52,6 @@ import com.android.dialer.voicemail.VoicemailStatusHelper; import com.android.dialer.voicemail.VoicemailStatusHelper.StatusMessage; import com.android.dialer.voicemail.VoicemailStatusHelperImpl; import com.android.dialerbind.ObjectFactory; -import com.android.dialerbind.analytics.AnalyticsListFragment; import java.util.List; @@ -59,7 +59,7 @@ import java.util.List; * Displays a list of call log entries. To filter for a particular kind of call * (all, missed or voicemails), specify it in the constructor. */ -public class CallLogFragment extends AnalyticsListFragment +public class CallLogFragment extends ListFragment implements CallLogQueryHandler.Listener, CallLogAdapter.OnReportButtonClickListener, CallLogAdapter.CallFetcher, CallLogAdapter.CallItemExpandedListener { @@ -552,7 +552,7 @@ public class CallLogFragment extends AnalyticsListFragment } @Override - public void onItemExpanded(final CallLogListItemView view) { + public void onItemExpanded(final View view) { final int startingHeight = view.getHeight(); final CallLogListItemViews viewHolder = (CallLogListItemViews) view.getTag(); final ViewTreeObserver observer = getListView().getViewTreeObserver(); @@ -665,7 +665,7 @@ public class CallLogFragment extends AnalyticsListFragment * @return The call log view. */ @Override - public CallLogListItemView getViewForCallId(long callId) { + public View getViewForCallId(long callId) { ListView listView = getListView(); int firstPosition = listView.getFirstVisiblePosition(); @@ -677,7 +677,7 @@ public class CallLogFragment extends AnalyticsListFragment if (view != null) { final CallLogListItemViews viewHolder = (CallLogListItemViews) view.getTag(); if (viewHolder != null && viewHolder.rowId == callId) { - return (CallLogListItemView)view; + return view; } } } diff --git a/src/com/android/dialer/calllog/CallLogListItemHelper.java b/src/com/android/dialer/calllog/CallLogListItemHelper.java index 37c922c69..77ad333d9 100644 --- a/src/com/android/dialer/calllog/CallLogListItemHelper.java +++ b/src/com/android/dialer/calllog/CallLogListItemHelper.java @@ -19,6 +19,7 @@ package com.android.dialer.calllog; import android.content.Context; import android.content.res.Resources; import android.provider.CallLog.Calls; +import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.util.Log; @@ -121,7 +122,7 @@ import com.android.dialer.R; * Returns the accessibility description of the "return call/call" action for a call log * entry. * Accessibility text is a combination of: - * {Voicemail Prefix}. {Number of Calls}. {Caller information}. + * {Voicemail Prefix}. {Number of Calls}. {Caller information} {Phone Account}. * If most recent call is a voicemail, {Voicemail Prefix} is "New Voicemail.", otherwise "". * * If more than one call for the caller, {Number of Calls} is: @@ -140,9 +141,13 @@ import com.android.dialer.R; * {Call type} is the contact phone number type (eg mobile) or location. * {Call Time} is the time since the last call for the contact occurred. * + * The {Phone Account} refers to the account/SIM through which the call was placed or received + * in multi-SIM devices. + * * Examples: - * 3 calls. New Voicemail. Missed call from Joe Smith mobile 2 hours ago. - * 2 calls. Answered call from John Doe mobile. Last called 1 hour ago. + * 3 calls. New Voicemail. Missed call from Joe Smith mobile 2 hours ago on SIM 1. + * + * 2 calls. Answered call from John Doe mobile 1 hour ago. * * @param context The application context. * @param details Details of call. @@ -161,7 +166,7 @@ import com.android.dialer.R; // Get the time/date of the call final CharSequence timeOfCall = mPhoneCallDetailsHelper.getCallDate(details); - StringBuilder callDescription = new StringBuilder(); + SpannableStringBuilder callDescription = new SpannableStringBuilder(); // Prepend the voicemail indication. if (isVoiceMail) { @@ -181,13 +186,22 @@ import com.android.dialer.R; } int stringID = getCallDescriptionStringID(details); + String accountLabel = PhoneAccountUtils.getAccountLabel(context, details.accountHandle); // Use chosen string resource to build up the message. - callDescription.append(mResources.getString(stringID, - nameOrNumber, - // If no type or location can be determined, sub in empty string. - typeOrLocation == null ? "" : typeOrLocation, - timeOfCall)); + CharSequence onAccountLabel = accountLabel == null + ? "" + : TextUtils.expandTemplate( + mResources.getString(R.string.description_phone_account), + accountLabel); + callDescription.append( + TextUtils.expandTemplate( + mResources.getString(stringID), + nameOrNumber, + // If no type or location can be determined, sub in empty string. + typeOrLocation == null ? "" : typeOrLocation, + timeOfCall, + onAccountLabel)); return callDescription; } @@ -203,13 +217,15 @@ import com.android.dialer.R; int stringID; if (lastCallType == Calls.VOICEMAIL_TYPE || lastCallType == Calls.MISSED_TYPE) { - //Message: Missed call from <NameOrNumber>, <TypeOrLocation>, <TimeOfCall>. + //Message: Missed call from <NameOrNumber>, <TypeOrLocation>, <TimeOfCall>, + //<PhoneAccount>. stringID = R.string.description_incoming_missed_call; } else if (lastCallType == Calls.INCOMING_TYPE) { - //Message: Answered call from <NameOrNumber>, <TypeOrLocation>, <TimeOfCall>. + //Message: Answered call from <NameOrNumber>, <TypeOrLocation>, <TimeOfCall>, + //<PhoneAccount>. stringID = R.string.description_incoming_answered_call; } else { - //Message: Call to <NameOrNumber>, <TypeOrLocation>, <TimeOfCall>. + //Message: Call to <NameOrNumber>, <TypeOrLocation>, <TimeOfCall>, <PhoneAccount>. stringID = R.string.description_outgoing_call; } return stringID; @@ -238,7 +254,7 @@ import com.android.dialer.R; if (!TextUtils.isEmpty(details.name)) { recipient = details.name; } else { - recipient = mPhoneNumberHelper.getDisplayNumber(details.accountId, + recipient = mPhoneNumberHelper.getDisplayNumber(details.accountHandle, details.number, details.numberPresentation, details.formattedNumber); } return recipient; diff --git a/src/com/android/dialer/calllog/CallLogListItemView.java b/src/com/android/dialer/calllog/CallLogListItemView.java deleted file mode 100644 index b8990f50a..000000000 --- a/src/com/android/dialer/calllog/CallLogListItemView.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2011 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.calllog; - -import android.content.Context; -import android.util.AttributeSet; -import android.widget.LinearLayout; - -/** - * An entry in the call log. - */ -public class CallLogListItemView extends LinearLayout { - public CallLogListItemView(Context context) { - super(context); - } - - public CallLogListItemView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public CallLogListItemView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } -} diff --git a/src/com/android/dialer/calllog/DefaultVoicemailNotifier.java b/src/com/android/dialer/calllog/DefaultVoicemailNotifier.java index 71825da27..970cad6a6 100644 --- a/src/com/android/dialer/calllog/DefaultVoicemailNotifier.java +++ b/src/com/android/dialer/calllog/DefaultVoicemailNotifier.java @@ -28,12 +28,14 @@ import android.database.Cursor; import android.net.Uri; import android.provider.CallLog.Calls; import android.provider.ContactsContract.PhoneLookup; +import android.telecom.PhoneAccountHandle; import android.text.TextUtils; import android.util.Log; import com.android.common.io.MoreCloseables; import com.android.dialer.CallDetailActivity; import com.android.dialer.R; +import com.android.dialer.calllog.PhoneAccountUtils; import com.google.common.collect.Maps; import java.util.Map; @@ -118,7 +120,10 @@ public class DefaultVoicemailNotifier implements VoicemailNotifier { // Check if we already know the name associated with this number. String name = names.get(newCall.number); if (name == null) { - name = mPhoneNumberHelper.getDisplayName(newCall.accountId, newCall.number, + PhoneAccountHandle accountHandle = PhoneAccountUtils.getAccount( + newCall.accountComponentName, + newCall.accountId); + name = mPhoneNumberHelper.getDisplayName(accountHandle, newCall.number, newCall.numberPresentation).toString(); // If we cannot lookup the contact, use the number instead. if (TextUtils.isEmpty(name)) { @@ -214,14 +219,16 @@ public class DefaultVoicemailNotifier implements VoicemailNotifier { public final Uri voicemailUri; public final String number; public final int numberPresentation; - public final int accountId; + public final String accountComponentName; + public final String accountId; public NewCall(Uri callsUri, Uri voicemailUri, String number, - int numberPresentation, int accountId) { + int numberPresentation, String accountComponentName, String accountId) { this.callsUri = callsUri; this.voicemailUri = voicemailUri; this.number = number; this.numberPresentation = numberPresentation; + this.accountComponentName = accountComponentName; this.accountId = accountId; } } @@ -246,12 +253,14 @@ public class DefaultVoicemailNotifier implements VoicemailNotifier { private static final class DefaultNewCallsQuery implements NewCallsQuery { private static final String[] PROJECTION = { Calls._ID, Calls.NUMBER, Calls.VOICEMAIL_URI, Calls.NUMBER_PRESENTATION, - Calls.PHONE_ACCOUNT_ID }; + Calls.PHONE_ACCOUNT_COMPONENT_NAME, Calls.PHONE_ACCOUNT_ID + }; private static final int ID_COLUMN_INDEX = 0; private static final int NUMBER_COLUMN_INDEX = 1; private static final int VOICEMAIL_URI_COLUMN_INDEX = 2; private static final int NUMBER_PRESENTATION_COLUMN_INDEX = 3; - private static final int ACCOUNT_ID_COLUMN_INDEX = 4; + private static final int PHONE_ACCOUNT_COMPONENT_NAME_COLUMN_INDEX = 4; + private static final int PHONE_ACCOUNT_ID_COLUMN_INDEX = 5; private final ContentResolver mContentResolver; @@ -288,7 +297,8 @@ public class DefaultVoicemailNotifier implements VoicemailNotifier { Uri voicemailUri = voicemailUriString == null ? null : Uri.parse(voicemailUriString); return new NewCall(callsUri, voicemailUri, cursor.getString(NUMBER_COLUMN_INDEX), cursor.getInt(NUMBER_PRESENTATION_COLUMN_INDEX), - cursor.getInt(ACCOUNT_ID_COLUMN_INDEX)); + cursor.getString(PHONE_ACCOUNT_COMPONENT_NAME_COLUMN_INDEX), + cursor.getString(PHONE_ACCOUNT_ID_COLUMN_INDEX)); } } @@ -347,6 +357,6 @@ public class DefaultVoicemailNotifier implements VoicemailNotifier { * called from the main thread. */ public static PhoneNumberDisplayHelper createPhoneNumberHelper(Context context) { - return new PhoneNumberDisplayHelper(context.getResources()); + return new PhoneNumberDisplayHelper(context, context.getResources()); } } diff --git a/src/com/android/dialer/calllog/IntentProvider.java b/src/com/android/dialer/calllog/IntentProvider.java index 76b458a68..8bf62725f 100644 --- a/src/com/android/dialer/calllog/IntentProvider.java +++ b/src/com/android/dialer/calllog/IntentProvider.java @@ -74,6 +74,15 @@ public abstract class IntentProvider { }; } + public static IntentProvider getReturnVoicemailCallIntentProvider() { + return new IntentProvider() { + @Override + public Intent getIntent(Context context) { + return CallUtil.getVoicemailIntent(); + } + }; + } + public static IntentProvider getPlayVoicemailIntentProvider(final long rowId, final String voicemailUri) { return new IntentProvider() { diff --git a/src/com/android/dialer/calllog/PhoneAccountUtils.java b/src/com/android/dialer/calllog/PhoneAccountUtils.java index 11c1b178e..f80ffd089 100644 --- a/src/com/android/dialer/calllog/PhoneAccountUtils.java +++ b/src/com/android/dialer/calllog/PhoneAccountUtils.java @@ -18,21 +18,40 @@ package com.android.dialer.calllog; import android.content.ComponentName; import android.content.Context; -import android.graphics.drawable.Drawable; import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.text.TextUtils; +import java.util.ArrayList; +import java.util.List; + /** * Methods to help extract {@code PhoneAccount} information from database and Telecomm sources */ public class PhoneAccountUtils { /** - * Generate account info from data in Telecomm database + * Return a list of phone accounts that are subscription/SIM accounts. + */ + public static List<PhoneAccountHandle> getSubscriptionPhoneAccounts(Context context) { + final TelecomManager telecomManager = + (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE); + + List<PhoneAccountHandle> subscriptionAccountHandles = new ArrayList<PhoneAccountHandle>(); + List<PhoneAccountHandle> accountHandles = telecomManager.getCallCapablePhoneAccounts(); + for (PhoneAccountHandle accountHandle : accountHandles) { + PhoneAccount account = telecomManager.getPhoneAccount(accountHandle); + if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) { + subscriptionAccountHandles.add(accountHandle); + } + } + return subscriptionAccountHandles; + } + + /** + * Compose PhoneAccount object from component name and account id. */ - public static PhoneAccountHandle getAccount(String componentString, - String accountId) { + public static PhoneAccountHandle getAccount(String componentString, String accountId) { if (TextUtils.isEmpty(componentString) || TextUtils.isEmpty(accountId)) { return null; } @@ -41,25 +60,27 @@ public class PhoneAccountUtils { } /** - * Generate account icon from data in Telecomm database + * Extract account label from PhoneAccount object. */ - public static Drawable getAccountIcon(Context context, PhoneAccountHandle phoneAccount) { - final PhoneAccount account = getAccountOrNull(context, phoneAccount); - if (account == null) { - return null; + public static String getAccountLabel(Context context, PhoneAccountHandle accountHandle) { + PhoneAccount account = getAccountOrNull(context, accountHandle); + if (account != null && account.getLabel() != null) { + return account.getLabel().toString(); } - return account.createIconDrawable(context); + return null; } /** - * Generate account label from data in Telecomm database + * Extract account color from PhoneAccount object. */ - public static String getAccountLabel(Context context, PhoneAccountHandle phoneAccount) { - final PhoneAccount account = getAccountOrNull(context, phoneAccount); - if (account == null) { - return null; - } - return account.getLabel().toString(); + public static int getAccountColor(Context context, PhoneAccountHandle accountHandle) { + TelecomManager telecomManager = + (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE); + final PhoneAccount account = telecomManager.getPhoneAccount(accountHandle); + + // For single-sim devices the PhoneAccount will be NO_HIGHLIGHT_COLOR by default, so it is + // safe to always use the account highlight color. + return account == null ? PhoneAccount.NO_HIGHLIGHT_COLOR : account.getHighlightColor(); } /** @@ -67,14 +88,13 @@ public class PhoneAccountUtils { * single registered and enabled account, return null. */ private static PhoneAccount getAccountOrNull(Context context, - PhoneAccountHandle phoneAccount) { - final TelecomManager telecomManager = + PhoneAccountHandle accountHandle) { + TelecomManager telecomManager = (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE); - final PhoneAccount account = telecomManager.getPhoneAccount(phoneAccount); - if (account == null || !telecomManager.hasMultipleCallCapableAccounts()) { + final PhoneAccount account = telecomManager.getPhoneAccount(accountHandle); + if (!telecomManager.hasMultipleCallCapableAccounts()) { return null; } return account; } - } diff --git a/src/com/android/dialer/calllog/PhoneNumberDisplayHelper.java b/src/com/android/dialer/calllog/PhoneNumberDisplayHelper.java index 31015e407..d082b9d39 100644 --- a/src/com/android/dialer/calllog/PhoneNumberDisplayHelper.java +++ b/src/com/android/dialer/calllog/PhoneNumberDisplayHelper.java @@ -16,9 +16,11 @@ package com.android.dialer.calllog; +import android.content.Context; import android.content.res.Resources; import android.provider.CallLog.Calls; import android.telephony.SubscriptionManager; +import android.telecom.PhoneAccountHandle; import android.text.TextUtils; import android.util.Log; @@ -28,20 +30,25 @@ import com.android.dialer.R; * Helper for formatting and managing the display of phone numbers. */ public class PhoneNumberDisplayHelper { - private final PhoneNumberUtilsWrapper mPhoneNumberUtils; + private final Context mContext; private final Resources mResources; + private final PhoneNumberUtilsWrapper mPhoneNumberUtilsWrapper; - public PhoneNumberDisplayHelper(Resources resources) { + public PhoneNumberDisplayHelper(Context context, Resources resources) { + mContext = context; mResources = resources; - mPhoneNumberUtils = new PhoneNumberUtilsWrapper(); + mPhoneNumberUtilsWrapper = new PhoneNumberUtilsWrapper(context); } - public PhoneNumberDisplayHelper(PhoneNumberUtilsWrapper phoneNumberUtils, Resources resources) { - mPhoneNumberUtils = phoneNumberUtils; + public PhoneNumberDisplayHelper(Context context, Resources resources, + PhoneNumberUtilsWrapper phoneNumberUtils) { + mContext = context; mResources = resources; + mPhoneNumberUtilsWrapper = phoneNumberUtils; } - /* package */ CharSequence getDisplayName(int subId, CharSequence number, int presentation) { + /* package */ CharSequence getDisplayName(PhoneAccountHandle accountHandle, CharSequence number, + int presentation) { if (presentation == Calls.PRESENTATION_UNKNOWN) { return mResources.getString(R.string.unknown); } @@ -51,7 +58,7 @@ public class PhoneNumberDisplayHelper { if (presentation == Calls.PRESENTATION_PAYPHONE) { return mResources.getString(R.string.payphone); } - if (mPhoneNumberUtils.isVoicemailNumber(subId, number)) { + if (mPhoneNumberUtilsWrapper.isVoicemailNumber(accountHandle, number)) { return mResources.getString(R.string.voicemail); } if (PhoneNumberUtilsWrapper.isLegacyUnknownNumbers(number)) { @@ -63,12 +70,14 @@ public class PhoneNumberDisplayHelper { /** * Returns the string to display for the given phone number. * + * @param accountHandle The handle for the account corresponding to the call * @param number the number to display * @param formattedNumber the formatted number if available, may be null */ - public CharSequence getDisplayNumber(int subId, CharSequence number, + public CharSequence getDisplayNumber(PhoneAccountHandle accountHandle, CharSequence number, int presentation, CharSequence formattedNumber) { - final CharSequence displayName = getDisplayName(subId, number, presentation); + + final CharSequence displayName = getDisplayName(accountHandle, number, presentation); if (!TextUtils.isEmpty(displayName)) { return displayName; } diff --git a/src/com/android/dialer/calllog/PhoneNumberUtilsWrapper.java b/src/com/android/dialer/calllog/PhoneNumberUtilsWrapper.java index 5f7c79448..17cd1ff9f 100644 --- a/src/com/android/dialer/calllog/PhoneNumberUtilsWrapper.java +++ b/src/com/android/dialer/calllog/PhoneNumberUtilsWrapper.java @@ -16,7 +16,10 @@ package com.android.dialer.calllog; +import android.content.Context; import android.provider.CallLog; +import android.telecom.PhoneAccountHandle; +import android.telecom.TelecomManager; import android.telephony.PhoneNumberUtils; import android.text.TextUtils; @@ -30,8 +33,12 @@ import java.util.Set; * */ public class PhoneNumberUtilsWrapper { - public static final PhoneNumberUtilsWrapper INSTANCE = new PhoneNumberUtilsWrapper(); private static final Set<String> LEGACY_UNKNOWN_NUMBERS = Sets.newHashSet("-1", "-2", "-3"); + private final Context mContext; + + public PhoneNumberUtilsWrapper(Context context) { + mContext = context; + } /** Returns true if it is possible to place a call to the given number. */ public static boolean canPlaceCallsTo(CharSequence number, int presentation) { @@ -40,19 +47,14 @@ public class PhoneNumberUtilsWrapper { } /** - * Returns true if it is possible to send an SMS to the given number. - */ - public boolean canSendSmsTo(CharSequence number, int presentation) { - return canPlaceCallsTo(number, presentation) && !isVoicemailNumber(number) && !isSipNumber( - number); - } - - /** * Returns true if the given number is the number of the configured voicemail. To be able to * mock-out this, it is not a static method. */ - public boolean isVoicemailNumber(CharSequence number) { - return number!= null && PhoneNumberUtils.isVoiceMailNumber(number.toString()); + public boolean isVoicemailNumber(PhoneAccountHandle accountHandle, + CharSequence number) { + final TelecomManager telecomManager = + (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE); + return number!= null && telecomManager.isVoiceMailNumber(accountHandle, number.toString()); } /** @@ -67,11 +69,12 @@ public class PhoneNumberUtilsWrapper { * Returns true if the given number is a SIP address. To be able to mock-out this, it is not a * static method. */ - public boolean isSipNumber(CharSequence number) { + public static boolean isSipNumber(CharSequence number) { return number != null && PhoneNumberHelper.isUriNumber(number.toString()); } - public static boolean isUnknownNumberThatCanBeLookedUp(CharSequence number, int presentation) { + public boolean isUnknownNumberThatCanBeLookedUp(PhoneAccountHandle accountHandle, + CharSequence number, int presentation) { if (presentation == CallLog.Calls.PRESENTATION_UNKNOWN) { return false; } @@ -84,7 +87,7 @@ public class PhoneNumberUtilsWrapper { if (TextUtils.isEmpty(number)) { return false; } - if (INSTANCE.isVoicemailNumber(number)) { + if (isVoicemailNumber(accountHandle, number)) { return false; } if (isLegacyUnknownNumbers(number)) { diff --git a/src/com/android/dialer/callstats/CallStatsAdapter.java b/src/com/android/dialer/callstats/CallStatsAdapter.java index fa59dd726..50d821b4f 100644 --- a/src/com/android/dialer/callstats/CallStatsAdapter.java +++ b/src/com/android/dialer/callstats/CallStatsAdapter.java @@ -20,6 +20,8 @@ package com.android.dialer.callstats; import android.content.Context; import android.content.res.Resources; import android.net.Uri; +import android.telecom.PhoneAccountHandle; +import android.telecom.TelecomManager; import android.telephony.SubscriptionManager; import android.text.TextUtils; import android.view.LayoutInflater; @@ -38,6 +40,7 @@ import com.android.dialer.calllog.ContactInfo; import com.android.dialer.calllog.ContactInfoHelper; import com.android.dialer.calllog.PhoneNumberDisplayHelper; import com.android.dialer.calllog.PhoneNumberUtilsWrapper; +import com.android.contacts.common.util.PhoneNumberHelper; import java.util.ArrayList; import java.util.Collections; @@ -70,6 +73,9 @@ class CallStatsAdapter extends ArrayAdapter<CallStatsDetails> private final CallLogAdapterHelper mAdapterHelper; private final CallStatsDetailHelper mCallStatsDetailHelper; + private final PhoneNumberDisplayHelper mPhoneNumberHelper; + private final ContactPhotoManager mContactPhotoManager; + private ArrayList<CallStatsDetails> mAllItems; private CallStatsDetails mTotalItem; private Map<ContactInfo, CallStatsDetails> mInfoLookup; @@ -79,8 +85,6 @@ class CallStatsAdapter extends ArrayAdapter<CallStatsDetails> private long mFilterTo; private boolean mSortByDuration; - private final ContactPhotoManager mContactPhotoManager; - private PhoneNumberDisplayHelper mPhoneNumberHelper; private final Comparator<CallStatsDetails> mDurationComparator = new Comparator<CallStatsDetails>() { @Override @@ -114,7 +118,8 @@ class CallStatsAdapter extends ArrayAdapter<CallStatsDetails> mInfoLookup = new ConcurrentHashMap<ContactInfo, CallStatsDetails>(); Resources resources = mContext.getResources(); - mPhoneNumberHelper = new PhoneNumberDisplayHelper(resources); + mPhoneNumberHelper = + new PhoneNumberDisplayHelper(mContext, resources); final String currentCountryIso = GeoUtil.getCurrentCountryIso(mContext); final ContactInfoHelper contactInfoHelper = @@ -123,8 +128,8 @@ class CallStatsAdapter extends ArrayAdapter<CallStatsDetails> mAdapterHelper = new CallLogAdapterHelper(mContext, this, contactInfoHelper, mPhoneNumberHelper); mContactPhotoManager = ContactPhotoManager.getInstance(mContext); - mCallStatsDetailHelper = new CallStatsDetailHelper(resources, - new PhoneNumberUtilsWrapper()); + mCallStatsDetailHelper = new CallStatsDetailHelper(mContext, resources, + new PhoneNumberUtilsWrapper(mContext)); } public void updateData(Map<ContactInfo, CallStatsDetails> calls, long from, long to) { @@ -136,11 +141,13 @@ class CallStatsAdapter extends ArrayAdapter<CallStatsDetails> mAllItems.clear(); mTotalItem.reset(); + PhoneAccountHandle accountHandle = getTelecomManager().getUserSelectedOutgoingPhoneAccount(); + for (Map.Entry<ContactInfo, CallStatsDetails> entry : calls.entrySet()) { final CallStatsDetails call = entry.getValue(); mAllItems.add(call); mTotalItem.mergeWith(call); - mAdapterHelper.lookupContact(call.number, call.numberPresentation, + mAdapterHelper.lookupContact(accountHandle, call.number, call.numberPresentation, call.countryIso, entry.getKey()); } } @@ -219,10 +226,13 @@ class CallStatsAdapter extends ArrayAdapter<CallStatsDetails> mCallStatsDetailHelper.setCallStatsDetails(views.callStatsDetailViews, details, first, mTotalItem, mType, mSortByDuration); + final PhoneAccountHandle accountHandle = + getTelecomManager().getUserSelectedOutgoingPhoneAccount(); + String nameForDefaultImage = null; if (TextUtils.isEmpty(details.name)) { nameForDefaultImage = mPhoneNumberHelper.getDisplayNumber( - SubscriptionManager.INVALID_SUBSCRIPTION_ID, details.number, + accountHandle, details.number, details.numberPresentation, details.formattedNumber).toString(); } else { nameForDefaultImage = details.name; @@ -266,4 +276,8 @@ class CallStatsAdapter extends ArrayAdapter<CallStatsDetails> details.updateFromInfo(updatedInfo); } } + + private TelecomManager getTelecomManager() { + return (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE); + } } diff --git a/src/com/android/dialer/callstats/CallStatsDetailActivity.java b/src/com/android/dialer/callstats/CallStatsDetailActivity.java index 165a5858a..df4a0fd9a 100644 --- a/src/com/android/dialer/callstats/CallStatsDetailActivity.java +++ b/src/com/android/dialer/callstats/CallStatsDetailActivity.java @@ -96,10 +96,10 @@ public class CallStatsDetailActivity extends Activity { mResources = getResources(); - PhoneNumberDisplayHelper phoneNumberHelper = new PhoneNumberDisplayHelper(mResources); + PhoneNumberDisplayHelper phoneNumberHelper = new PhoneNumberDisplayHelper(this, mResources); mCallDetailHeader = new CallDetailHeader(this, phoneNumberHelper); - mCallStatsDetailHelper = new CallStatsDetailHelper(mResources, - new PhoneNumberUtilsWrapper()); + mCallStatsDetailHelper = new CallStatsDetailHelper(this, mResources, + new PhoneNumberUtilsWrapper(this)); mContactInfoHelper = new ContactInfoHelper(this, GeoUtil.getCurrentCountryIso(this)); mTotalSummary = (TextView) findViewById(R.id.total_summary); diff --git a/src/com/android/dialer/callstats/CallStatsDetailHelper.java b/src/com/android/dialer/callstats/CallStatsDetailHelper.java index 848944060..8dd22c971 100644 --- a/src/com/android/dialer/callstats/CallStatsDetailHelper.java +++ b/src/com/android/dialer/callstats/CallStatsDetailHelper.java @@ -17,9 +17,12 @@ package com.android.dialer.callstats; +import android.content.Context; import android.content.res.Resources; import android.provider.CallLog.Calls; import android.provider.ContactsContract.CommonDataKinds.Phone; +import android.telecom.PhoneAccountHandle; +import android.telecom.TelecomManager; import android.telephony.PhoneNumberUtils; import android.telephony.SubscriptionManager; import android.text.TextUtils; @@ -39,10 +42,13 @@ public class CallStatsDetailHelper { private final Resources mResources; private final PhoneNumberDisplayHelper mPhoneNumberHelper; private final PhoneNumberUtilsWrapper mPhoneNumberUtilsWrapper; + private final Context mContext; - public CallStatsDetailHelper(Resources resources, PhoneNumberUtilsWrapper phoneUtils) { + public CallStatsDetailHelper(Context context, Resources resources, + PhoneNumberUtilsWrapper phoneUtils) { + mContext = context; mResources = resources; - mPhoneNumberHelper = new PhoneNumberDisplayHelper(resources); + mPhoneNumberHelper = new PhoneNumberDisplayHelper(context, resources); mPhoneNumberUtilsWrapper = phoneUtils; } @@ -58,17 +64,19 @@ public class CallStatsDetailHelper { details.numberType, details.numberLabel); } + final TelecomManager tm = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE); + final PhoneAccountHandle accountHandle = tm.getUserSelectedOutgoingPhoneAccount(); final CharSequence nameText; final CharSequence numberText; final CharSequence labelText; final CharSequence displayNumber = mPhoneNumberHelper.getDisplayNumber( - SubscriptionManager.INVALID_SUBSCRIPTION_ID, details.number, + accountHandle, details.number, details.numberPresentation, details.formattedNumber); if (TextUtils.isEmpty(details.name)) { nameText = displayNumber; if (TextUtils.isEmpty(details.geocode) - || mPhoneNumberUtilsWrapper.isVoicemailNumber(details.number)) { + || mPhoneNumberUtilsWrapper.isVoicemailNumber(accountHandle, details.number)) { numberText = mResources.getString(R.string.call_log_empty_geocode); } else { numberText = details.geocode; diff --git a/src/com/android/dialer/callstats/CallStatsDetails.java b/src/com/android/dialer/callstats/CallStatsDetails.java index e5d81cf1e..7bac35505 100644 --- a/src/com/android/dialer/callstats/CallStatsDetails.java +++ b/src/com/android/dialer/callstats/CallStatsDetails.java @@ -21,6 +21,7 @@ import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; import android.provider.CallLog.Calls; +import android.telecom.PhoneAccountHandle; import android.telephony.SubscriptionManager; import android.util.Log; @@ -98,11 +99,7 @@ public class CallStatsDetails implements CallDetailHeader.Data, Parcelable { return photoUri; } @Override - public int getAccountId() { - return SubscriptionManager.INVALID_SUBSCRIPTION_ID; - } - @Override - public CharSequence getAccountLabel() { + public PhoneAccountHandle getAccountHandle() { return null; } @Override diff --git a/src/com/android/dialer/dialpad/DialpadFragment.java b/src/com/android/dialer/dialpad/DialpadFragment.java index 089261f1f..82d4b8df9 100644 --- a/src/com/android/dialer/dialpad/DialpadFragment.java +++ b/src/com/android/dialer/dialpad/DialpadFragment.java @@ -20,12 +20,15 @@ import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.app.DialogFragment; +import android.app.Fragment; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.res.Configuration; +import android.content.IntentFilter; import android.content.res.Resources; import android.database.Cursor; import android.graphics.Bitmap; @@ -83,9 +86,10 @@ import com.android.dialer.SpecialCharSequenceMgr; import com.android.dialer.SpeedDialListActivity; import com.android.dialer.SpeedDialUtils; import com.android.dialer.util.DialerUtils; -import com.android.dialerbind.analytics.AnalyticsFragment; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyProperties; +import com.android.dialer.calllog.PhoneAccountUtils; +import com.android.dialer.util.DialerUtils; import com.android.phone.common.CallLogAsync; import com.android.phone.common.HapticFeedback; import com.android.phone.common.animation.AnimUtils; @@ -96,11 +100,12 @@ import com.google.common.annotations.VisibleForTesting; import java.util.HashSet; import java.util.Locale; +import java.util.List; /** * Fragment that displays a twelve-key phone dialpad. */ -public class DialpadFragment extends AnalyticsFragment +public class DialpadFragment extends Fragment implements View.OnClickListener, View.OnLongClickListener, View.OnKeyListener, AdapterView.OnItemClickListener, TextWatcher, @@ -248,17 +253,21 @@ public class DialpadFragment extends AnalyticsFragment private String mCurrentCountryIso; - private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() { + private CallStateReceiver mCallStateReceiver; + + private class CallStateReceiver extends BroadcastReceiver { /** - * Listen for phone state changes so that we can take down the + * Receive call state changes so that we can take down the * "dialpad chooser" if the phone becomes idle while the * chooser UI is visible. */ @Override - public void onCallStateChanged(int state, String incomingNumber) { - // Log.i(TAG, "PhoneStateListener.onCallStateChanged: " - // + state + ", '" + incomingNumber + "'"); - if ((state == TelephonyManager.CALL_STATE_IDLE) && isDialpadChooserVisible()) { + public void onReceive(Context context, Intent intent) { + // Log.i(TAG, "CallStateReceiver.onReceive"); + String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE); + if ((TextUtils.equals(state, TelephonyManager.EXTRA_STATE_IDLE) || + TextUtils.equals(state, TelephonyManager.EXTRA_STATE_OFFHOOK)) + && isDialpadChooserVisible()) { // Log.i(TAG, "Call ended with dialpad chooser visible! Taking it down..."); // Note there's a race condition in the UI here: the // dialpad chooser could conceivably disappear (on its @@ -268,14 +277,14 @@ public class DialpadFragment extends AnalyticsFragment // onscreen, but useless...) showDialpadChooser(false); } - if (state == TelephonyManager.CALL_STATE_IDLE) { + if (TextUtils.equals(state, TelephonyManager.EXTRA_STATE_IDLE)) { final Activity activity = getActivity(); if (activity != null) { ((HostInterface) activity).setConferenceDialButtonVisibility(true); } } } - }; + } private boolean mWasEmptyBeforeTextChange; @@ -294,13 +303,6 @@ public class DialpadFragment extends AnalyticsFragment private static final String PREF_DIGITS_FILLED_BY_INTENT = "pref_digits_filled_by_intent"; - /** - * Return an Intent for launching voicemail screen. - */ - private static Intent getVoicemailIntent() { - return CallUtil.getCallIntent(Uri.fromParts(PhoneAccount.SCHEME_VOICEMAIL, "", null)); - } - private TelephonyManager getTelephonyManager() { return (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE); } @@ -330,7 +332,7 @@ public class DialpadFragment extends AnalyticsFragment @Override public void afterTextChanged(Editable input) { - // When DTMF dialpad buttons are being pressed, we delay SpecialCharSequencMgr sequence, + // When DTMF dialpad buttons are being pressed, we delay SpecialCharSequenceMgr sequence, // since some of SpecialCharSequenceMgr's behavior is too abrupt for the "touch-down" // behavior. if (!mDigitsFilledByIntent && @@ -371,6 +373,13 @@ public class DialpadFragment extends AnalyticsFragment } mDialpadSlideInDuration = getResources().getInteger(R.integer.dialpad_slide_in_duration); + + if (mCallStateReceiver == null) { + IntentFilter callStateIntentFilter = new IntentFilter( + TelephonyManager.ACTION_PHONE_STATE_CHANGED); + mCallStateReceiver = new CallStateReceiver(); + ((Context) getActivity()).registerReceiver(mCallStateReceiver, callStateIntentFilter); + } } @Override @@ -575,6 +584,14 @@ public class DialpadFragment extends AnalyticsFragment mStartedFromNewIntent = value; } + public void clearCallRateInformation() { + setCallRateInformation(null, null); + } + + public void setCallRateInformation(String countryName, String displayRate) { + mDialpadView.setCallRateInformation(countryName, displayRate); + } + /** * Sets formatted digits to digits field. */ @@ -686,33 +703,8 @@ public class DialpadFragment extends AnalyticsFragment stopWatch.lap("fdin"); - // While we're in the foreground, listen for phone state changes, - // purely so that we can take down the "dialpad chooser" if the - // phone becomes idle while the chooser UI is visible. - getTelephonyManager().listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); - - stopWatch.lap("tm"); - - // Potentially show hint text in the mDigits field when the user - // hasn't typed any digits yet. (If there's already an active call, - // this hint text will remind the user that he's about to add a new - // call.) - // - // TODO: consider adding better UI for the case where *both* lines - // are currently in use. (Right now we let the user try to add - // another call, but that call is guaranteed to fail. Perhaps the - // entire dialer UI should be disabled instead.) - if (isPhoneInUse()) { - final SpannableString hint = new SpannableString( - getActivity().getString(R.string.dialerDialpadHintText)); - hint.setSpan(new RelativeSizeSpan(0.8f), 0, hint.length(), 0); - mDigits.setHint(hint); - } else { - // Common case; no hint necessary. - mDigits.setHint(null); - - // Also, a sanity-check: the "dialpad chooser" UI should NEVER - // be visible if the phone is idle! + if (!isPhoneInUse()) { + // A sanity-check: the "dialpad chooser" UI should not be visible if the phone is idle. showDialpadChooser(false); } @@ -742,9 +734,6 @@ public class DialpadFragment extends AnalyticsFragment public void onPause() { super.onPause(); - // Stop listening for phone state changes. - getTelephonyManager().listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE); - // Make sure we don't leave this activity with a tone still playing. stopTone(); mPressedDialpadKeys.clear(); @@ -779,6 +768,12 @@ public class DialpadFragment extends AnalyticsFragment outState.putBoolean(PREF_DIGITS_FILLED_BY_INTENT, mDigitsFilledByIntent); } + @Override + public void onDestroy() { + super.onDestroy(); + ((Context) getActivity()).unregisterReceiver(mCallStateReceiver); + } + private void keyPressed(int keyCode) { if (getView().getTranslationY() != 0) { return; @@ -1089,7 +1084,17 @@ public class DialpadFragment extends AnalyticsFragment // We'll try to initiate voicemail and thus we want to remove irrelevant string. removePreviousDigitIfPossible(); - if (isVoicemailAvailable()) { + List<PhoneAccountHandle> subscriptionAccountHandles = + PhoneAccountUtils.getSubscriptionPhoneAccounts(getActivity()); + boolean hasUserSelectedDefault = subscriptionAccountHandles.contains( + getTelecomManager().getUserSelectedOutgoingPhoneAccount()); + boolean needsAccountDisambiguation = subscriptionAccountHandles.size() > 1 + && !hasUserSelectedDefault; + + if (needsAccountDisambiguation || isVoicemailAvailable()) { + // On a multi-SIM phone, if the user has not selected a default + // subscription, initiate a call to voicemail so they can select an account + // from the "Call with" dialog. callVoicemail(); } else if (getActivity() != null) { // Voicemail is unavailable maybe because Airplane mode is turned on. @@ -1230,7 +1235,7 @@ public class DialpadFragment extends AnalyticsFragment } public void callVoicemail() { - DialerUtils.startActivityWithErrorToast(getActivity(), getVoicemailIntent()); + DialerUtils.startActivityWithErrorToast(getActivity(), CallUtil.getVoicemailIntent()); hideAndClearDialpad(false); } @@ -1486,7 +1491,7 @@ public class DialpadFragment extends AnalyticsFragment } if (enabled) { - Log.i(TAG, "Showing dialpad chooser!"); + Log.d(TAG, "Showing dialpad chooser!"); if (mDialpadView != null) { mDialpadView.setVisibility(View.GONE); } @@ -1501,7 +1506,7 @@ public class DialpadFragment extends AnalyticsFragment } mDialpadChooser.setAdapter(mDialpadChooserAdapter); } else { - Log.i(TAG, "Displaying normal Dialer UI."); + Log.d(TAG, "Displaying normal Dialer UI."); if (mDialpadView != null) { mDialpadView.setVisibility(View.VISIBLE); } else { @@ -1795,22 +1800,24 @@ public class DialpadFragment extends AnalyticsFragment /** * Check if voicemail is enabled/accessible. * - * @return true if voicemail is enabled and accessibly. Note that this can be false + * @return true if voicemail is enabled and accessible. Note that this can be false * "temporarily" after the app boot. - * @see TelephonyManager#getVoiceMailNumber() + * @see TelecomManager#hasVoiceMailNumber(PhoneAccountHandle) */ private boolean isVoicemailAvailable() { - boolean promptEnabled = SubscriptionManager.isVoicePromptEnabled(); - if (promptEnabled) { - return hasVMNumber(); - } else { - int subId = SubscriptionManager.getDefaultVoiceSubId(); - try { - return getTelephonyManager().getVoiceMailNumber(subId) != null; - } catch (SecurityException se) { - // Possibly no READ_PHONE_STATE privilege. - Log.w(TAG, "SecurityException is thrown. Maybe privilege isn't sufficient."); + try { + PhoneAccountHandle defaultUserSelectedAccount = + getTelecomManager().getUserSelectedOutgoingPhoneAccount(); + if (defaultUserSelectedAccount == null) { + // In a single-SIM phone, there is no default outgoing phone account selected by + // the user, so just call TelephonyManager#getVoicemailNumber directly. + return getTelephonyManager().getVoiceMailNumber() != null; + } else { + return getTelecomManager().hasVoiceMailNumber(defaultUserSelectedAccount); } + } catch (SecurityException se) { + // Possibly no READ_PHONE_STATE privilege. + Log.w(TAG, "SecurityException is thrown. Maybe privilege isn't sufficient."); } return false; } diff --git a/src/com/android/dialer/interactions/PhoneNumberInteraction.java b/src/com/android/dialer/interactions/PhoneNumberInteraction.java index b61a496c2..de217ce7b 100644 --- a/src/com/android/dialer/interactions/PhoneNumberInteraction.java +++ b/src/com/android/dialer/interactions/PhoneNumberInteraction.java @@ -49,9 +49,9 @@ import com.android.contacts.common.CallUtil; import com.android.contacts.common.Collapser; import com.android.contacts.common.Collapser.Collapsible; import com.android.contacts.common.MoreContactUtils; +import com.android.contacts.common.activity.TransactionSafeActivity; import com.android.contacts.common.util.ContactDisplayUtils; import com.android.dialer.R; -import com.android.dialer.activity.TransactionSafeActivity; import com.android.dialer.contact.ContactUpdateService; import com.android.dialer.util.DialerUtils; diff --git a/src/com/android/dialer/list/ListsFragment.java b/src/com/android/dialer/list/ListsFragment.java index 024e3d914..af82e4075 100644 --- a/src/com/android/dialer/list/ListsFragment.java +++ b/src/com/android/dialer/list/ListsFragment.java @@ -20,6 +20,7 @@ import android.widget.ListView; import com.android.contacts.common.GeoUtil; import com.android.contacts.common.list.ViewPagerTabs; +import com.android.contacts.commonbind.analytics.AnalyticsUtil; import com.android.dialer.DialtactsActivity; import com.android.dialer.R; import com.android.dialer.calllog.CallLogAdapter; @@ -29,9 +30,9 @@ import com.android.dialer.calllog.CallLogQueryHandler; import com.android.dialer.calllog.ContactInfoHelper; import com.android.dialer.list.ShortcutCardsAdapter.SwipeableShortcutCard; import com.android.dialer.util.DialerUtils; +import com.android.dialer.widget.ActionBarController; import com.android.dialer.widget.OverlappingPaneLayout; import com.android.dialer.widget.OverlappingPaneLayout.PanelSlideCallbacks; -import com.android.dialerbind.analytics.AnalyticsFragment; import com.android.dialerbind.ObjectFactory; import java.util.ArrayList; @@ -44,7 +45,7 @@ import java.util.ArrayList; * ViewPager containing the lists up above the shortcut cards and pin it against the top of the * screen. */ -public class ListsFragment extends AnalyticsFragment implements CallLogQueryHandler.Listener, +public class ListsFragment extends Fragment implements CallLogQueryHandler.Listener, CallLogAdapter.CallFetcher, ViewPager.OnPageChangeListener { private static final boolean DEBUG = DialtactsActivity.DEBUG; @@ -68,8 +69,7 @@ public class ListsFragment extends AnalyticsFragment implements CallLogQueryHand public interface HostInterface { public void showCallHistory(); - public int getActionBarHeight(); - public void setActionBarHideOffset(int offset); + public ActionBarController getActionBarController(); } private ActionBar mActionBar; @@ -90,6 +90,7 @@ public class ListsFragment extends AnalyticsFragment implements CallLogQueryHand private ShortcutCardsAdapter mMergedAdapter; private CallLogAdapter mCallLogAdapter; private CallLogQueryHandler mCallLogQueryHandler; + private OverlappingPaneLayout mOverlappingPaneLayout; private boolean mIsPanelOpen = true; @@ -124,8 +125,9 @@ public class ListsFragment extends AnalyticsFragment implements CallLogQueryHand final int availableActionBarHeight = Math.min(mActionBar.getHeight(), topPaneHeight); - ((HostInterface) getActivity()).setActionBarHideOffset( - mActionBar.getHeight() - availableActionBarHeight); + final ActionBarController controller = + ((HostInterface) getActivity()).getActionBarController(); + controller.setHideOffset(mActionBar.getHeight() - availableActionBarHeight); if (!mActionBar.isShowing()) { mActionBar.show(); @@ -247,11 +249,6 @@ public class ListsFragment extends AnalyticsFragment implements CallLogQueryHand } @Override - public void onStart() { - super.onStart(); - } - - @Override public void onResume() { super.onResume(); final SharedPreferences prefs = getActivity().getSharedPreferences( @@ -260,6 +257,9 @@ public class ListsFragment extends AnalyticsFragment implements CallLogQueryHand mActionBar = getActivity().getActionBar(); fetchCalls(); mCallLogAdapter.setLoading(true); + if (getUserVisibleHint()) { + sendScreenViewForPosition(mViewPager.getCurrentItem()); + } } @Override @@ -303,6 +303,7 @@ public class ListsFragment extends AnalyticsFragment implements CallLogQueryHand mRemoveViewContent = parentView.findViewById(R.id.remove_view_content); setupPaneLayout((OverlappingPaneLayout) parentView); + mOverlappingPaneLayout = (OverlappingPaneLayout) parentView; return parentView; } @@ -323,6 +324,11 @@ public class ListsFragment extends AnalyticsFragment implements CallLogQueryHand mCallLogAdapter.changeCursor(cursor); mMergedAdapter.notifyDataSetChanged(); + + // Refresh the overlapping pane to ensure that any changes in the shortcut card height + // are appropriately reflected in the overlap position. + mOverlappingPaneLayout.refresh(); + // Return true; took ownership of cursor return true; } @@ -358,17 +364,11 @@ public class ListsFragment extends AnalyticsFragment implements CallLogQueryHand @Override public void onPageSelected(int position) { - if (position == TAB_INDEX_SPEED_DIAL && mSpeedDialFragment != null) { - mSpeedDialFragment.sendScreenView(); - } else if (position == TAB_INDEX_RECENTS && mRecentsFragment != null) { - mRecentsFragment.sendScreenView(); - } else if (position == TAB_INDEX_ALL_CONTACTS && mAllContactsFragment != null) { - mAllContactsFragment.sendScreenView(); - } final int count = mOnPageChangeListeners.size(); for (int i = 0; i < count; i++) { mOnPageChangeListeners.get(i).onPageSelected(position); } + sendScreenViewForPosition(position); } @Override @@ -407,7 +407,7 @@ public class ListsFragment extends AnalyticsFragment implements CallLogQueryHand paneLayout.openPane(); paneLayout.setPanelSlideCallbacks(mPanelSlideCallbacks); paneLayout.setIntermediatePinnedOffset( - ((HostInterface) getActivity()).getActionBarHeight()); + ((HostInterface) getActivity()).getActionBarController().getActionBarHeight()); LayoutTransition transition = paneLayout.getLayoutTransition(); // Turns on animations for all types of layout changes so that they occur for @@ -429,4 +429,29 @@ public class ListsFragment extends AnalyticsFragment implements CallLogQueryHand } return position; } + + public void sendScreenViewForCurrentPosition() { + sendScreenViewForPosition(mViewPager.getCurrentItem()); + } + + private void sendScreenViewForPosition(int position) { + if (!isResumed()) { + return; + } + String fragmentName; + switch (getRtlPosition(position)) { + case TAB_INDEX_SPEED_DIAL: + fragmentName = SpeedDialFragment.class.getSimpleName(); + break; + case TAB_INDEX_RECENTS: + fragmentName = CallLogFragment.class.getSimpleName(); + break; + case TAB_INDEX_ALL_CONTACTS: + fragmentName = AllContactsFragment.class.getSimpleName(); + break; + default: + return; + } + AnalyticsUtil.sendScreenView(fragmentName, getActivity(), null); + } } diff --git a/src/com/android/dialer/list/RegularSearchFragment.java b/src/com/android/dialer/list/RegularSearchFragment.java index c4af4f570..1b4523331 100644 --- a/src/com/android/dialer/list/RegularSearchFragment.java +++ b/src/com/android/dialer/list/RegularSearchFragment.java @@ -20,6 +20,7 @@ import android.view.ViewGroup; import com.android.contacts.common.list.ContactEntryListAdapter; import com.android.contacts.common.list.PinnedHeaderListView; +import com.android.contacts.commonbind.analytics.AnalyticsUtil; import com.android.dialerbind.ObjectFactory; import com.android.dialer.lookup.LookupCache; import com.android.dialer.service.CachedNumberLookupService; @@ -35,6 +36,12 @@ public class RegularSearchFragment extends SearchFragment { configureDirectorySearch(); } + @Override + public void onStart() { + super.onStart(); + AnalyticsUtil.sendScreenView(this); + } + public void configureDirectorySearch() { setDirectorySearchEnabled(true); setDirectoryResultLimit(SEARCH_DIRECTORY_RESULT_LIMIT); diff --git a/src/com/android/dialer/list/SearchFragment.java b/src/com/android/dialer/list/SearchFragment.java index 3b55672c3..1d4c7c2d9 100644 --- a/src/com/android/dialer/list/SearchFragment.java +++ b/src/com/android/dialer/list/SearchFragment.java @@ -33,6 +33,7 @@ import com.android.contacts.common.list.PhoneNumberPickerFragment; import android.app.DialogFragment; import com.android.dialer.dialpad.DialpadFragment.ErrorDialogFragment; import com.android.contacts.common.util.ViewUtil; +import com.android.contacts.commonbind.analytics.AnalyticsUtil; import com.android.dialer.DialtactsActivity; import com.android.dialer.R; import com.android.dialer.util.DialerUtils; @@ -73,7 +74,6 @@ public class SearchFragment extends PhoneNumberPickerFragment { setDarkTheme(false); setPhotoPosition(ContactListItemView.getDefaultPhotoPosition(false /* opposite */)); setUseCallableUri(true); - sendScreenView(); try { mActivityScrollListener = (OnListFragmentScrolledListener) activity; diff --git a/src/com/android/dialer/list/ShortcutCardsAdapter.java b/src/com/android/dialer/list/ShortcutCardsAdapter.java index 4fe638ea1..6410eabf6 100644 --- a/src/com/android/dialer/list/ShortcutCardsAdapter.java +++ b/src/com/android/dialer/list/ShortcutCardsAdapter.java @@ -21,6 +21,7 @@ import android.content.res.Resources; import android.database.Cursor; import android.database.DataSetObserver; import android.graphics.Rect; +import android.text.TextUtils; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; @@ -32,7 +33,6 @@ import android.widget.TextView; import com.android.dialer.R; import com.android.dialer.calllog.CallLogAdapter; -import com.android.dialer.calllog.CallLogListItemView; import com.android.dialer.calllog.CallLogNotificationsHelper; import com.android.dialer.calllog.CallLogQueryHandler; import com.android.dialer.list.SwipeHelper.OnItemGestureListener; @@ -202,6 +202,7 @@ public class ShortcutCardsAdapter extends BaseAdapter { wrapper.removeAllViews(); wrapper.prepareChildView(view); wrapper.addView(view); + wrapper.setVisibility(View.VISIBLE); return wrapper; } @@ -259,15 +260,17 @@ public class ShortcutCardsAdapter extends BaseAdapter { // TODO: Set content description including type/location and time information. TextView nameView = (TextView) actionView.findViewById(R.id.name); - actionView.setContentDescription(getResources().getString( - R.string.description_call_back_action, nameView.getText())); + + actionView.setContentDescription( + TextUtils.expandTemplate( + getResources().getString(R.string.description_call_back_action), + nameView.getText())); mPreviousTranslationZ = getResources().getDimensionPixelSize( R.dimen.recent_call_log_item_translation_z); view.setTranslationZ(mPreviousTranslationZ); - final CallLogListItemView callLogItem = - (CallLogListItemView) view.findViewById(R.id.call_log_list_item); + final ViewGroup callLogItem = (ViewGroup) view.findViewById(R.id.call_log_list_item); // Reset the internal call log item view if it is being recycled callLogItem.setTranslationX(0); callLogItem.setTranslationY(0); diff --git a/src/com/android/dialer/list/SpeedDialFragment.java b/src/com/android/dialer/list/SpeedDialFragment.java index e0635516a..63f1f34c6 100644 --- a/src/com/android/dialer/list/SpeedDialFragment.java +++ b/src/com/android/dialer/list/SpeedDialFragment.java @@ -19,6 +19,7 @@ import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.app.Activity; +import android.app.Fragment; import android.app.LoaderManager; import android.content.CursorLoader; import android.content.Loader; @@ -48,7 +49,6 @@ import com.android.contacts.common.list.ContactTileView; import com.android.contacts.common.list.OnPhoneNumberPickerActionListener; import com.android.dialer.R; import com.android.dialer.util.DialerUtils; -import com.android.dialerbind.analytics.AnalyticsFragment; import java.util.ArrayList; import java.util.HashMap; @@ -56,7 +56,7 @@ import java.util.HashMap; /** * This fragment displays the user's favorite/frequent contacts in a grid. */ -public class SpeedDialFragment extends AnalyticsFragment implements OnItemClickListener, +public class SpeedDialFragment extends Fragment implements OnItemClickListener, PhoneFavoritesTileAdapter.OnDataSetChangedForAnimationListener { /** @@ -150,8 +150,6 @@ public class SpeedDialFragment extends AnalyticsFragment implements OnItemClickL private View mContactTileFrame; - private TileInteractionTeaserView mTileInteractionTeaserView; - private final HashMap<Long, Integer> mItemIdTopMap = new HashMap<Long, Integer>(); private final HashMap<Long, Integer> mItemIdLeftMap = new HashMap<Long, Integer>(); @@ -217,9 +215,6 @@ public class SpeedDialFragment extends AnalyticsFragment implements OnItemClickL mContactTileFrame = mParentView.findViewById(R.id.contact_tile_frame); - mTileInteractionTeaserView = (TileInteractionTeaserView) inflater.inflate( - R.layout.tile_interactions_teaser_view, mListView, false); - final LayoutAnimationController controller = new LayoutAnimationController( AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_in)); controller.setDelay(0); @@ -240,14 +235,16 @@ public class SpeedDialFragment extends AnalyticsFragment implements OnItemClickL /* package */ void setEmptyViewVisibility(final boolean visible) { final int previousVisibility = mEmptyView.getVisibility(); - final int newVisibility = visible ? View.VISIBLE : View.GONE; + final int emptyViewVisibility = visible ? View.VISIBLE : View.GONE; + final int listViewVisibility = visible ? View.GONE : View.VISIBLE; - if (previousVisibility != newVisibility) { + if (previousVisibility != emptyViewVisibility) { final RelativeLayout.LayoutParams params = (LayoutParams) mContactTileFrame .getLayoutParams(); params.height = visible ? LayoutParams.WRAP_CONTENT : LayoutParams.MATCH_PARENT; mContactTileFrame.setLayoutParams(params); - mEmptyView.setVisibility(newVisibility); + mEmptyView.setVisibility(emptyViewVisibility); + mListView.setVisibility(listViewVisibility); } } diff --git a/src/com/android/dialer/list/TileInteractionTeaserView.java b/src/com/android/dialer/list/TileInteractionTeaserView.java deleted file mode 100644 index fd5ed3425..000000000 --- a/src/com/android/dialer/list/TileInteractionTeaserView.java +++ /dev/null @@ -1,153 +0,0 @@ -package com.android.dialer.list; - -import android.animation.Animator; - -import android.animation.ValueAnimator; -import android.content.Context; -import android.content.SharedPreferences; -import android.content.res.Resources; -import android.util.AttributeSet; -import android.util.Log; -import android.view.View; -import android.view.animation.DecelerateInterpolator; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.android.dialer.DialtactsActivity; -import com.android.dialer.R; - -/** - * A teaser to introduce people to the contact photo check boxes - */ -public class TileInteractionTeaserView extends FrameLayout { - private static int sShrinkAnimationDuration; - - private static final String KEY_TILE_INTERACTION_TEASER_SHOWN = - "key_tile_interaction_teaser_shown"; - - private boolean mNeedLayout; - private int mTextTop; - private int mAnimatedHeight = -1; - - private ShortcutCardsAdapter mAdapter; - - public TileInteractionTeaserView(final Context context) { - this(context, null); - } - - public TileInteractionTeaserView(final Context context, final AttributeSet attrs) { - super(context, attrs); - final Resources resources = context.getResources(); - - mNeedLayout = true; - sShrinkAnimationDuration = resources.getInteger(R.integer.escape_animation_duration); - } - - @Override - protected void onFinishInflate() { - findViewById(R.id.dismiss_button).setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - startDestroyAnimation(); - } - }); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - - final TextView text = (TextView) findViewById(R.id.text); - final ImageView arrow = (ImageView) findViewById(R.id.arrow); - - // We post to avoid calling layout within layout - arrow.post(new Runnable() { - @Override - public void run() { - - // The text top is changed when we move the arrow, so we need to - // do multiple passes - int textTop = text.getTop(); - if (mNeedLayout || textTop != mTextTop) { - mNeedLayout = false; - mTextTop = textTop; - - final int lineHeight = text.getLineHeight(); - final LinearLayout.LayoutParams arrowParams = (LinearLayout.LayoutParams) arrow - .getLayoutParams(); - arrowParams.topMargin = mTextTop + lineHeight / 2; - arrow.setLayoutParams(arrowParams); - } - arrow.setVisibility(View.VISIBLE); - } - }); - } - - public boolean getShouldDisplayInList() { - final SharedPreferences prefs = getContext().getSharedPreferences( - DialtactsActivity.SHARED_PREFS_NAME, Context.MODE_PRIVATE); - return prefs.getBoolean(KEY_TILE_INTERACTION_TEASER_SHOWN, true); - } - - public void setAdapter(ShortcutCardsAdapter adapter) { - mAdapter = adapter; - } - - private void startDestroyAnimation() { - final int start = getHeight(); - final int end = 0; - mAnimatedHeight = start; - Log.v("Interaction", "Start from" + start); - - ValueAnimator heightAnimator = ValueAnimator.ofInt(start, end); - heightAnimator.setDuration(sShrinkAnimationDuration); - heightAnimator.setInterpolator(new DecelerateInterpolator(2.0f)); - heightAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - public void onAnimationUpdate(ValueAnimator animation) { - mAnimatedHeight = (Integer) animation.getAnimatedValue(); - requestLayout(); - } - }); - heightAnimator.addListener(new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animator) { - } - - @Override - public void onAnimationEnd(Animator animator) { - setVisibility(GONE); - setDismissed(); - if (mAdapter != null) { - mAdapter.notifyDataSetChanged(); - } - } - - @Override - public void onAnimationCancel(Animator animator) { - } - - @Override - public void onAnimationRepeat(Animator animator) { - } - }); - - heightAnimator.start(); - } - - private void setDismissed() { - final SharedPreferences prefs = getContext().getSharedPreferences( - DialtactsActivity.SHARED_PREFS_NAME, Context.MODE_PRIVATE); - prefs.edit().putBoolean(KEY_TILE_INTERACTION_TEASER_SHOWN, false).apply(); - } - - @Override - protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { - if (mAnimatedHeight == -1) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - } else { - setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), mAnimatedHeight); - } - } -} diff --git a/src/com/android/dialer/settings/DialerSettingsActivity.java b/src/com/android/dialer/settings/DialerSettingsActivity.java index 8a0f60d09..a0df667a9 100644 --- a/src/com/android/dialer/settings/DialerSettingsActivity.java +++ b/src/com/android/dialer/settings/DialerSettingsActivity.java @@ -3,29 +3,31 @@ package com.android.dialer.settings; import com.google.common.collect.Lists; import android.content.Context; +import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; +import android.preference.PreferenceActivity; import android.preference.PreferenceManager; import android.preference.PreferenceActivity.Header; +import android.telecom.TelecomManager; +import android.telephony.TelephonyManager; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; -import android.widget.ImageView; import android.widget.ListAdapter; import android.widget.TextView; import com.android.dialer.DialtactsActivity; import com.android.dialer.R; -import com.android.dialerbind.analytics.AnalyticsPreferenceActivity; import java.util.List; -public class DialerSettingsActivity extends AnalyticsPreferenceActivity { +public class DialerSettingsActivity extends PreferenceActivity { protected SharedPreferences mPreferences; private HeaderAdapter mHeaderAdapter; @@ -42,7 +44,6 @@ public class DialerSettingsActivity extends AnalyticsPreferenceActivity { public void onBuildHeaders(List<Header> target) { final Header generalSettingsHeader = new Header(); generalSettingsHeader.titleRes = R.string.general_settings_label; - generalSettingsHeader.summaryRes = R.string.general_settings_description; generalSettingsHeader.fragment = GeneralSettingsFragment.class.getName(); target.add(generalSettingsHeader); @@ -54,11 +55,27 @@ public class DialerSettingsActivity extends AnalyticsPreferenceActivity { // Only add the call settings header if the current user is the primary/owner user. if (isPrimaryUser()) { - final Header callSettingHeader = new Header(); - callSettingHeader.titleRes = R.string.call_settings_label; - callSettingHeader.summaryRes = R.string.call_settings_description; - callSettingHeader.intent = DialtactsActivity.getCallSettingsIntent(); - target.add(callSettingHeader); + final TelephonyManager telephonyManager = + (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); + // Show "Call Settings" if there is one SIM and "Phone Accounts" if there are more. + if (telephonyManager.getPhoneCount() <= 1) { + final Header callSettingsHeader = new Header(); + Intent callSettingsIntent = new Intent(TelecomManager.ACTION_SHOW_CALL_SETTINGS); + callSettingsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + + callSettingsHeader.titleRes = R.string.call_settings_label; + callSettingsHeader.intent = callSettingsIntent; + target.add(callSettingsHeader); + } else { + final Header phoneAccountSettingsHeader = new Header(); + Intent phoneAccountSettingsIntent = + new Intent(TelecomManager.ACTION_CHANGE_PHONE_ACCOUNTS); + phoneAccountSettingsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + + phoneAccountSettingsHeader.titleRes = R.string.phone_account_settings_label; + phoneAccountSettingsHeader.intent = phoneAccountSettingsIntent; + target.add(phoneAccountSettingsHeader); + } } } diff --git a/src/com/android/dialer/settings/GeneralSettingsFragment.java b/src/com/android/dialer/settings/GeneralSettingsFragment.java index 0745fc903..f839179dd 100644 --- a/src/com/android/dialer/settings/GeneralSettingsFragment.java +++ b/src/com/android/dialer/settings/GeneralSettingsFragment.java @@ -134,7 +134,7 @@ public class GeneralSettingsFragment extends PreferenceFragment mContext, mRingtoneLookupComplete, RingtoneManager.TYPE_RINGTONE, - mRingtonePreference, + mRingtonePreference.getKey(), MSG_UPDATE_RINGTONE_SUMMARY); } } diff --git a/src/com/android/dialer/util/DialerUtils.java b/src/com/android/dialer/util/DialerUtils.java index a747c74aa..d59deb4ef 100644 --- a/src/com/android/dialer/util/DialerUtils.java +++ b/src/com/android/dialer/util/DialerUtils.java @@ -71,8 +71,9 @@ public class DialerUtils { */ public static void startActivityWithErrorToast(Context context, Intent intent, int msgId) { try { - if (Intent.ACTION_CALL.equals(intent.getAction()) - || Intent.ACTION_CALL_PRIVILEGED.equals(intent.getAction())) { + if ((Intent.ACTION_CALL.equals(intent.getAction()) + || Intent.ACTION_CALL_PRIVILEGED.equals(intent.getAction())) + && context instanceof Activity) { // All dialer-initiated calls should pass the touch point to the InCallUI Point touchPoint = TouchPointManager.getInstance().getPoint(); if (touchPoint.x != 0 || touchPoint.y != 0) { @@ -124,7 +125,7 @@ public class DialerUtils { (ImageView) emptyListView.findViewById(R.id.emptyListViewImage); emptyListViewImage.setImageDrawable(res.getDrawable(imageResId)); - emptyListViewImage.setContentDescription(res.getString(strResId)); + emptyListViewImage.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); TextView emptyListViewMessage = (TextView) emptyListView.findViewById(R.id.emptyListViewMessage); diff --git a/src/com/android/dialer/voicemail/VoicemailPlaybackFragment.java b/src/com/android/dialer/voicemail/VoicemailPlaybackFragment.java index 133a98807..31db17720 100644 --- a/src/com/android/dialer/voicemail/VoicemailPlaybackFragment.java +++ b/src/com/android/dialer/voicemail/VoicemailPlaybackFragment.java @@ -20,6 +20,7 @@ import static com.android.dialer.CallDetailActivity.EXTRA_VOICEMAIL_START_PLAYBA import static com.android.dialer.CallDetailActivity.EXTRA_VOICEMAIL_URI; import android.app.Activity; +import android.app.Fragment; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -39,15 +40,15 @@ import android.widget.SeekBar; import android.widget.TextView; import com.android.common.io.MoreCloseables; +import com.android.contacts.commonbind.analytics.AnalyticsUtil; import com.android.dialer.ProximitySensorAware; import com.android.dialer.R; import com.android.dialer.util.AsyncTaskExecutors; -import com.android.dialerbind.analytics.AnalyticsFragment; import com.android.ex.variablespeed.MediaPlayerProxy; import com.android.ex.variablespeed.VariableSpeed; + import com.google.common.base.Preconditions; -import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -66,7 +67,7 @@ import javax.annotation.concurrent.NotThreadSafe; * methods on this class are expected to come from the main ui thread. */ @NotThreadSafe -public class VoicemailPlaybackFragment extends AnalyticsFragment { +public class VoicemailPlaybackFragment extends Fragment { private static final String TAG = "VoicemailPlayback"; private static final int NUMBER_OF_THREADS_IN_POOL = 2; private static final String[] HAS_CONTENT_PROJECTION = new String[] { @@ -113,6 +114,12 @@ public class VoicemailPlaybackFragment extends AnalyticsFragment { } @Override + public void onStart() { + super.onStart(); + AnalyticsUtil.sendScreenView(this); + } + + @Override public void onDestroy() { shutdownMediaPlayer(); mPresenter.onDestroy(); diff --git a/src/com/android/dialer/voicemail/VoicemailPlaybackPresenter.java b/src/com/android/dialer/voicemail/VoicemailPlaybackPresenter.java index 085ef669a..cb246f4c8 100644 --- a/src/com/android/dialer/voicemail/VoicemailPlaybackPresenter.java +++ b/src/com/android/dialer/voicemail/VoicemailPlaybackPresenter.java @@ -446,12 +446,10 @@ public class VoicemailPlaybackPresenter { @Override public Exception doInBackground(Void... params) { try { - if (!mPlayer.isReadyToPlay()) { - mPlayer.reset(); - mPlayer.setDataSource(mView.getDataSourceContext(), mVoicemailUri); - mPlayer.setAudioStreamType(PLAYBACK_STREAM); - mPlayer.prepare(); - } + mPlayer.reset(); + mPlayer.setDataSource(mView.getDataSourceContext(), mVoicemailUri); + mPlayer.setAudioStreamType(PLAYBACK_STREAM); + mPlayer.prepare(); return null; } catch (Exception e) { return e; diff --git a/src/com/android/dialer/widget/ActionBarController.java b/src/com/android/dialer/widget/ActionBarController.java index 265c03f6f..b9923d186 100644 --- a/src/com/android/dialer/widget/ActionBarController.java +++ b/src/com/android/dialer/widget/ActionBarController.java @@ -46,7 +46,8 @@ public class ActionBarController { public boolean hasSearchQuery(); public boolean shouldShowActionBar(); public int getActionBarHeight(); - public ActionBar getActionBar(); + public int getActionBarHideOffset(); + public void setActionBarHideOffset(int offset); } public ActionBarController(ActivityUi activityUi, SearchEditTextLayout searchBox) { @@ -166,14 +167,18 @@ public class ActionBarController { public void setHideOffset(int offset) { mIsActionBarSlidUp = offset >= mActivityUi.getActionBarHeight(); - mActivityUi.getActionBar().setHideOffset(offset); + mActivityUi.setActionBarHideOffset(offset); } /** * @return The offset the action bar is being translated upwards by */ public int getHideOffset() { - return mActivityUi.getActionBar().getHideOffset(); + return mActivityUi.getActionBarHideOffset(); + } + + public int getActionBarHeight() { + return mActivityUi.getActionBarHeight(); } /** diff --git a/src/com/android/dialer/widget/OverlappingPaneLayout.java b/src/com/android/dialer/widget/OverlappingPaneLayout.java index 95a0e43de..167b849f2 100644 --- a/src/com/android/dialer/widget/OverlappingPaneLayout.java +++ b/src/com/android/dialer/widget/OverlappingPaneLayout.java @@ -230,7 +230,6 @@ public class OverlappingPaneLayout extends ViewGroup { setWillNotDraw(false); ViewCompat.setAccessibilityDelegate(this, new AccessibilityDelegate()); - ViewCompat.setImportantForAccessibility(this, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES); mDragHelper = ViewDragHelper.create(this, 0.5f, new DragHelperCallback()); mDragHelper.setMinVelocity(MIN_FLING_VELOCITY * density); @@ -718,6 +717,22 @@ public class OverlappingPaneLayout extends ViewGroup { return wantTouchEvents; } + /** + * Refreshes the {@link OverlappingPaneLayout} be attempting to re-open or re-close the pane. + * This ensures that the overlapping pane is repositioned based on any changes to the view + * which is being overlapped. + * <p> + * The {@link #openPane()} and {@link #closePane()} methods do not perform any animation if the + * pane has already been positioned appropriately. + */ + public void refresh() { + if (isOpen()) { + openPane(); + } else { + closePane(); + } + } + private boolean closePane(View pane, int initialVelocity) { if (mFirstLayout || smoothSlideTo(0.f, initialVelocity)) { mPreservedOpenState = false; diff --git a/src/com/android/dialer/widget/SearchEditTextLayout.java b/src/com/android/dialer/widget/SearchEditTextLayout.java index 86a2f9b86..75f7fa4b7 100644 --- a/src/com/android/dialer/widget/SearchEditTextLayout.java +++ b/src/com/android/dialer/widget/SearchEditTextLayout.java @@ -107,6 +107,17 @@ public class SearchEditTextLayout extends FrameLayout { mExpandedSearchBox = findViewById(R.id.search_box_expanded); mClearButtonView = findViewById(R.id.search_close_button); + // Convert a long click into a click to expand the search box, and then long click on the + // search view. This accelerates the long-press scenario for copy/paste. + mCollapsedSearchBox.setOnLongClickListener(new OnLongClickListener() { + @Override + public boolean onLongClick(View view) { + mCollapsedSearchBox.performClick(); + mSearchView.performLongClick(); + return false; + } + }); + mSearchView.setOnFocusChangeListener(new OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { |