summaryrefslogtreecommitdiffstats
path: root/java/com/android/dialer/app
diff options
context:
space:
mode:
authorEric Erfanian <erfanian@google.com>2017-03-15 14:41:07 -0700
committerEric Erfanian <erfanian@google.com>2017-03-15 16:24:23 -0700
commitd5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9 (patch)
treeb54abbb51fb7d66e7755a1fbb5db023ff601090b /java/com/android/dialer/app
parent30436e7e6d3f2c8755a91b2b6222b74d465a9e87 (diff)
downloadandroid_packages_apps_Dialer-d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9.tar.gz
android_packages_apps_Dialer-d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9.tar.bz2
android_packages_apps_Dialer-d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9.zip
Update Dialer source from latest green build.
* Refactor voicemail component * Add new enriched calling components Test: treehugger, manual aosp testing Change-Id: I521a0f86327d4b42e14d93927c7d613044ed5942
Diffstat (limited to 'java/com/android/dialer/app')
-rw-r--r--java/com/android/dialer/app/AndroidManifest.xml12
-rw-r--r--java/com/android/dialer/app/CallDetailActivity.java480
-rw-r--r--java/com/android/dialer/app/DialerApplication.java77
-rw-r--r--java/com/android/dialer/app/DialtactsActivity.java87
-rw-r--r--java/com/android/dialer/app/PhoneCallDetails.java207
-rw-r--r--java/com/android/dialer/app/SpecialCharSequenceMgr.java46
-rw-r--r--java/com/android/dialer/app/calllog/CallDetailHistoryAdapter.java214
-rw-r--r--java/com/android/dialer/app/calllog/CallLogActivity.java220
-rw-r--r--java/com/android/dialer/app/calllog/CallLogAdapter.java94
-rw-r--r--java/com/android/dialer/app/calllog/CallLogAsyncTaskUtil.java243
-rw-r--r--java/com/android/dialer/app/calllog/CallLogFragment.java93
-rw-r--r--java/com/android/dialer/app/calllog/CallLogListItemHelper.java11
-rw-r--r--java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java72
-rw-r--r--java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java (renamed from java/com/android/dialer/app/calllog/CallLogNotificationsHelper.java)83
-rw-r--r--java/com/android/dialer/app/calllog/CallLogNotificationsService.java80
-rw-r--r--java/com/android/dialer/app/calllog/CallLogReceiver.java4
-rw-r--r--java/com/android/dialer/app/calllog/CallTypeHelper.java136
-rw-r--r--java/com/android/dialer/app/calllog/CallTypeIconsView.java221
-rw-r--r--java/com/android/dialer/app/calllog/DefaultVoicemailNotifier.java264
-rw-r--r--java/com/android/dialer/app/calllog/IntentProvider.java27
-rw-r--r--java/com/android/dialer/app/calllog/MissedCallNotifier.java405
-rw-r--r--java/com/android/dialer/app/calllog/PhoneAccountHandles.java41
-rw-r--r--java/com/android/dialer/app/calllog/PhoneAccountUtils.java104
-rw-r--r--java/com/android/dialer/app/calllog/PhoneCallDetailsHelper.java5
-rw-r--r--java/com/android/dialer/app/calllog/PhoneCallDetailsViews.java1
-rw-r--r--java/com/android/dialer/app/calllog/PhoneNumberDisplayUtil.java85
-rw-r--r--java/com/android/dialer/app/calllog/VisualVoicemailCallLogFragment.java5
-rw-r--r--java/com/android/dialer/app/calllog/VoicemailQueryHandler.java25
-rw-r--r--java/com/android/dialer/app/calllog/calllogcache/CallLogCacheLollipopMr1.java10
-rw-r--r--java/com/android/dialer/app/contactinfo/ContactInfoCache.java4
-rw-r--r--java/com/android/dialer/app/contactinfo/ContactPhotoLoader.java2
-rw-r--r--java/com/android/dialer/app/dialpad/DialpadFragment.java4
-rw-r--r--java/com/android/dialer/app/filterednumber/BlockedNumbersSettingsActivity.java5
-rw-r--r--java/com/android/dialer/app/legacybindings/DialerLegacyBindings.java3
-rw-r--r--java/com/android/dialer/app/legacybindings/DialerLegacyBindingsStub.java4
-rw-r--r--java/com/android/dialer/app/list/ListsFragment.java26
-rw-r--r--java/com/android/dialer/app/list/SearchFragment.java11
-rw-r--r--java/com/android/dialer/app/manifests/activities/AndroidManifest.xml12
-rw-r--r--java/com/android/dialer/app/res/drawable-hdpi/ic_call_arrow.pngbin538 -> 0 bytes
-rw-r--r--java/com/android/dialer/app/res/drawable-mdpi/ic_call_arrow.pngbin455 -> 0 bytes
-rw-r--r--java/com/android/dialer/app/res/drawable-xhdpi/ic_call_arrow.pngbin627 -> 0 bytes
-rw-r--r--java/com/android/dialer/app/res/drawable-xxhdpi/ic_call_arrow.pngbin1203 -> 0 bytes
-rw-r--r--java/com/android/dialer/app/res/drawable-xxxhdpi/ic_call_arrow.pngbin1344 -> 0 bytes
-rw-r--r--java/com/android/dialer/app/res/drawable-xxxhdpi/search_shadow.9.pngbin0 -> 1148 bytes
-rw-r--r--java/com/android/dialer/app/res/layout/call_detail.xml32
-rw-r--r--java/com/android/dialer/app/res/layout/call_detail_footer.xml52
-rw-r--r--java/com/android/dialer/app/res/layout/call_detail_header.xml89
-rw-r--r--java/com/android/dialer/app/res/layout/call_detail_history_item.xml3
-rw-r--r--java/com/android/dialer/app/res/layout/call_log_activity.xml40
-rw-r--r--java/com/android/dialer/app/res/layout/call_log_list_item.xml3
-rw-r--r--java/com/android/dialer/app/res/menu/call_log_options.xml22
-rw-r--r--java/com/android/dialer/app/res/menu/dialtacts_options.xml8
-rw-r--r--java/com/android/dialer/app/res/values/colors.xml8
-rw-r--r--java/com/android/dialer/app/res/values/dimens.xml5
-rw-r--r--java/com/android/dialer/app/res/values/strings.xml84
-rw-r--r--java/com/android/dialer/app/res/values/styles.xml5
-rw-r--r--java/com/android/dialer/app/settings/DialerSettingsActivity.java13
-rw-r--r--java/com/android/dialer/app/voicemail/VoicemailPlaybackLayout.java7
-rw-r--r--java/com/android/dialer/app/voicemail/VoicemailPlaybackPresenter.java84
-rw-r--r--java/com/android/dialer/app/voicemail/error/OmtpVoicemailMessageCreator.java113
-rw-r--r--java/com/android/dialer/app/voicemail/error/VoicemailErrorMessage.java51
-rw-r--r--java/com/android/dialer/app/voicemail/error/VoicemailErrorMessageCreator.java2
-rw-r--r--java/com/android/dialer/app/voicemail/error/VoicemailStatus.java7
-rw-r--r--java/com/android/dialer/app/voicemail/error/Vvm3VoicemailMessageCreator.java2
-rw-r--r--java/com/android/dialer/app/voicemail/error/res/layout/voicemai_error_message_fragment.xml1
-rw-r--r--java/com/android/dialer/app/voicemail/error/res/layout/voicemail_tos_fragment.xml1
-rw-r--r--java/com/android/dialer/app/voicemail/error/res/values/strings.xml7
-rw-r--r--java/com/android/dialer/app/widget/ActionBarController.java88
68 files changed, 1479 insertions, 2671 deletions
diff --git a/java/com/android/dialer/app/AndroidManifest.xml b/java/com/android/dialer/app/AndroidManifest.xml
index 80f294acc..5ce13dbd7 100644
--- a/java/com/android/dialer/app/AndroidManifest.xml
+++ b/java/com/android/dialer/app/AndroidManifest.xml
@@ -57,11 +57,7 @@
android:minSdkVersion="23"
android:targetSdkVersion="25"/>
- <application
- android:backupAgent='com.android.dialer.backup.DialerBackupAgent'
- android:fullBackupOnly="true"
- android:restoreAnyVersion="true"
- android:name="com.android.dialer.app.DialerApplication">
+ <application android:theme="@style/Theme.AppCompat">
<activity
android:exported="false"
@@ -75,6 +71,12 @@
</intent-filter>
</activity>
+ <activity
+ android:label="@string/call_log_activity_title"
+ android:name="com.android.dialer.app.calllog.CallLogActivity"
+ android:theme="@style/DialtactsThemeWithoutActionBarOverlay">
+ </activity>
+
<receiver android:name="com.android.dialer.app.calllog.CallLogReceiver">
<intent-filter>
<action android:name="android.intent.action.NEW_VOICEMAIL"/>
diff --git a/java/com/android/dialer/app/CallDetailActivity.java b/java/com/android/dialer/app/CallDetailActivity.java
deleted file mode 100644
index cda2b2e2c..000000000
--- a/java/com/android/dialer/app/CallDetailActivity.java
+++ /dev/null
@@ -1,480 +0,0 @@
-/*
- * Copyright (C) 2009 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.app;
-
-import android.content.ContentUris;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.support.v7.app.AppCompatActivity;
-import android.text.BidiFormatter;
-import android.text.TextDirectionHeuristics;
-import android.text.TextUtils;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.ListView;
-import android.widget.QuickContactBadge;
-import android.widget.TextView;
-import android.widget.Toast;
-import com.android.contacts.common.ClipboardUtils;
-import com.android.contacts.common.ContactPhotoManager;
-import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
-import com.android.contacts.common.GeoUtil;
-import com.android.contacts.common.preference.ContactsPreferences;
-import com.android.contacts.common.util.UriUtils;
-import com.android.dialer.app.calllog.CallDetailHistoryAdapter;
-import com.android.dialer.app.calllog.CallLogAsyncTaskUtil;
-import com.android.dialer.app.calllog.CallLogAsyncTaskUtil.CallLogAsyncTaskListener;
-import com.android.dialer.app.calllog.CallTypeHelper;
-import com.android.dialer.app.calllog.PhoneAccountUtils;
-import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler;
-import com.android.dialer.callintent.CallIntentBuilder;
-import com.android.dialer.callintent.nano.CallInitiationType;
-import com.android.dialer.common.Assert;
-import com.android.dialer.common.AsyncTaskExecutor;
-import com.android.dialer.common.AsyncTaskExecutors;
-import com.android.dialer.compat.CompatUtils;
-import com.android.dialer.logging.Logger;
-import com.android.dialer.logging.nano.DialerImpression;
-import com.android.dialer.logging.nano.ScreenEvent;
-import com.android.dialer.phonenumbercache.ContactInfoHelper;
-import com.android.dialer.phonenumberutil.PhoneNumberHelper;
-import com.android.dialer.proguard.UsedByReflection;
-import com.android.dialer.spam.Spam;
-import com.android.dialer.telecom.TelecomUtil;
-import com.android.dialer.util.CallUtil;
-import com.android.dialer.util.DialerUtils;
-import com.android.dialer.util.TouchPointManager;
-
-/**
- * Displays the details of a specific call log entry.
- *
- * <p>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.
- */
-@UsedByReflection(value = "AndroidManifest-app.xml")
-public class CallDetailActivity extends AppCompatActivity
- implements MenuItem.OnMenuItemClickListener, View.OnClickListener {
-
- /** A long array extra containing ids of call log entries to display. */
- public static final String EXTRA_CALL_LOG_IDS = "EXTRA_CALL_LOG_IDS";
- /** If we are started with a voicemail, we'll find the uri to play with this extra. */
- public static final String EXTRA_VOICEMAIL_URI = "EXTRA_VOICEMAIL_URI";
- /** If the activity was triggered from a notification. */
- public static final String EXTRA_FROM_NOTIFICATION = "EXTRA_FROM_NOTIFICATION";
-
- public static final String BLOCKED_OR_SPAM_QUERY_IDENTIFIER = "blockedOrSpamIdentifier";
-
- private final AsyncTaskExecutor executor = AsyncTaskExecutors.createAsyncTaskExecutor();
- protected String mNumber;
- private Context mContext;
- private ContactInfoHelper mContactInfoHelper;
- private ContactsPreferences mContactsPreferences;
- private CallTypeHelper mCallTypeHelper;
- private ContactPhotoManager mContactPhotoManager;
- private BidiFormatter mBidiFormatter = BidiFormatter.getInstance();
- private LayoutInflater mInflater;
- private Resources mResources;
- private PhoneCallDetails mDetails;
- private Uri mVoicemailUri;
- private String mPostDialDigits = "";
- private ListView mHistoryList;
- private QuickContactBadge mQuickContactBadge;
- private TextView mCallerName;
- private TextView mCallerNumber;
- private TextView mAccountLabel;
- private View mCallButton;
- private View mEditBeforeCallActionItem;
- private View mReportActionItem;
- private View mCopyNumberActionItem;
- private FilteredNumberAsyncQueryHandler mFilteredNumberAsyncQueryHandler;
- private CallLogAsyncTaskListener mCallLogAsyncTaskListener =
- new CallLogAsyncTaskListener() {
- @Override
- public void onDeleteCall() {
- finish();
- }
-
- @Override
- public void onDeleteVoicemail() {
- finish();
- }
-
- @Override
- public void onGetCallDetails(final PhoneCallDetails[] details) {
- if (details == null) {
- // Somewhere went wrong: we're going to bail out and show error to users.
- Toast.makeText(mContext, R.string.toast_call_detail_error, Toast.LENGTH_SHORT).show();
- finish();
- return;
- }
-
- // All calls are from the same number and same contact, so pick the first detail.
- mDetails = details[0];
- mNumber = TextUtils.isEmpty(mDetails.number) ? null : mDetails.number.toString();
-
- if (mNumber == null) {
- updateDataAndRender(details);
- return;
- }
-
- executor.submit(
- BLOCKED_OR_SPAM_QUERY_IDENTIFIER,
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... params) {
- mDetails.isBlocked =
- mFilteredNumberAsyncQueryHandler.getBlockedIdSynchronousForCalllogOnly(
- mNumber, mDetails.countryIso)
- != null;
- if (Spam.get(mContext).isSpamEnabled()) {
- mDetails.isSpam =
- hasIncomingCalls(details)
- && Spam.get(mContext)
- .checkSpamStatusSynchronous(mNumber, mDetails.countryIso);
- }
- return null;
- }
-
- @Override
- protected void onPostExecute(Void result) {
- updateDataAndRender(details);
- }
- });
- }
-
- private void updateDataAndRender(PhoneCallDetails[] details) {
- mPostDialDigits =
- TextUtils.isEmpty(mDetails.postDialDigits) ? "" : mDetails.postDialDigits;
-
- final CharSequence callLocationOrType = getNumberTypeOrLocation(mDetails);
-
- final CharSequence displayNumber;
- if (!TextUtils.isEmpty(mDetails.postDialDigits)) {
- displayNumber = mDetails.number + mDetails.postDialDigits;
- } else {
- displayNumber = mDetails.displayNumber;
- }
-
- final String displayNumberStr =
- mBidiFormatter.unicodeWrap(displayNumber.toString(), TextDirectionHeuristics.LTR);
-
- mDetails.nameDisplayOrder = mContactsPreferences.getDisplayOrder();
-
- if (!TextUtils.isEmpty(mDetails.getPreferredName())) {
- mCallerName.setText(mDetails.getPreferredName());
- mCallerNumber.setText(callLocationOrType + " " + displayNumberStr);
- } else {
- mCallerName.setText(displayNumberStr);
- if (!TextUtils.isEmpty(callLocationOrType)) {
- mCallerNumber.setText(callLocationOrType);
- mCallerNumber.setVisibility(View.VISIBLE);
- } else {
- mCallerNumber.setVisibility(View.GONE);
- }
- }
-
- CharSequence accountLabel =
- PhoneAccountUtils.getAccountLabel(mContext, mDetails.accountHandle);
- CharSequence accountContentDescription =
- PhoneCallDetails.createAccountLabelDescription(
- mResources, mDetails.viaNumber, accountLabel);
- if (!TextUtils.isEmpty(mDetails.viaNumber)) {
- if (!TextUtils.isEmpty(accountLabel)) {
- accountLabel =
- mResources.getString(
- R.string.call_log_via_number_phone_account, accountLabel, mDetails.viaNumber);
- } else {
- accountLabel = mResources.getString(R.string.call_log_via_number, mDetails.viaNumber);
- }
- }
- if (!TextUtils.isEmpty(accountLabel)) {
- mAccountLabel.setText(accountLabel);
- mAccountLabel.setContentDescription(accountContentDescription);
- mAccountLabel.setVisibility(View.VISIBLE);
- } else {
- mAccountLabel.setVisibility(View.GONE);
- }
-
- final boolean canPlaceCallsTo =
- PhoneNumberHelper.canPlaceCallsTo(mNumber, mDetails.numberPresentation);
- mCallButton.setVisibility(canPlaceCallsTo ? View.VISIBLE : View.GONE);
- mCopyNumberActionItem.setVisibility(canPlaceCallsTo ? View.VISIBLE : View.GONE);
-
- final boolean isSipNumber = PhoneNumberHelper.isSipNumber(mNumber);
- final boolean isVoicemailNumber =
- PhoneNumberHelper.isVoicemailNumber(mContext, mDetails.accountHandle, mNumber);
- final boolean showEditNumberBeforeCallAction =
- canPlaceCallsTo && !isSipNumber && !isVoicemailNumber;
- mEditBeforeCallActionItem.setVisibility(
- showEditNumberBeforeCallAction ? View.VISIBLE : View.GONE);
-
- final boolean showReportAction =
- mContactInfoHelper.canReportAsInvalid(mDetails.sourceType, mDetails.objectId);
- mReportActionItem.setVisibility(showReportAction ? View.VISIBLE : View.GONE);
-
- invalidateOptionsMenu();
-
- mHistoryList.setAdapter(
- new CallDetailHistoryAdapter(mContext, mInflater, mCallTypeHelper, details));
-
- updateContactPhoto(mDetails.isSpam);
-
- findViewById(R.id.call_detail).setVisibility(View.VISIBLE);
- }
-
- /**
- * Determines the location geocode text for a call, or the phone number type (if available).
- *
- * @param details The call details.
- * @return The phone number type or location.
- */
- private CharSequence getNumberTypeOrLocation(PhoneCallDetails details) {
- if (details.isSpam) {
- return mResources.getString(R.string.spam_number_call_log_label);
- } else if (details.isBlocked) {
- return mResources.getString(R.string.blocked_number_call_log_label);
- } else if (!TextUtils.isEmpty(details.namePrimary)) {
- return Phone.getTypeLabel(mResources, details.numberType, details.numberLabel);
- } else {
- return details.geocode;
- }
- }
- };
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- mContext = this;
- mResources = getResources();
- mContactInfoHelper = new ContactInfoHelper(this, GeoUtil.getCurrentCountryIso(this));
- mContactsPreferences = new ContactsPreferences(mContext);
- mCallTypeHelper = new CallTypeHelper(getResources());
- mFilteredNumberAsyncQueryHandler = new FilteredNumberAsyncQueryHandler(mContext);
-
- mVoicemailUri = getIntent().getParcelableExtra(EXTRA_VOICEMAIL_URI);
-
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
-
- setContentView(R.layout.call_detail);
- mInflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
-
- mHistoryList = (ListView) findViewById(R.id.history);
- mHistoryList.addHeaderView(mInflater.inflate(R.layout.call_detail_header, null));
- mHistoryList.addFooterView(mInflater.inflate(R.layout.call_detail_footer, null), null, false);
-
- mQuickContactBadge = (QuickContactBadge) findViewById(R.id.quick_contact_photo);
- mQuickContactBadge.setOverlay(null);
- if (CompatUtils.hasPrioritizedMimeType()) {
- mQuickContactBadge.setPrioritizedMimeType(Phone.CONTENT_ITEM_TYPE);
- }
- mCallerName = (TextView) findViewById(R.id.caller_name);
- mCallerNumber = (TextView) findViewById(R.id.caller_number);
- mAccountLabel = (TextView) findViewById(R.id.phone_account_label);
- mContactPhotoManager = ContactPhotoManager.getInstance(this);
-
- mCallButton = findViewById(R.id.call_back_button);
- mCallButton.setOnClickListener(
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- if (TextUtils.isEmpty(mNumber)) {
- return;
- }
- DialerUtils.startActivityWithErrorToast(
- CallDetailActivity.this,
- new CallIntentBuilder(getDialableNumber(), CallInitiationType.Type.CALL_DETAILS)
- .build());
- }
- });
-
- mEditBeforeCallActionItem = findViewById(R.id.call_detail_action_edit_before_call);
- mEditBeforeCallActionItem.setOnClickListener(this);
- mReportActionItem = findViewById(R.id.call_detail_action_report);
- mReportActionItem.setOnClickListener(this);
-
- mCopyNumberActionItem = findViewById(R.id.call_detail_action_copy);
- mCopyNumberActionItem.setOnClickListener(this);
-
- if (getIntent().getBooleanExtra(EXTRA_FROM_NOTIFICATION, false)) {
- closeSystemDialogs();
- }
-
- Logger.get(this).logScreenView(ScreenEvent.Type.CALL_DETAILS, this);
- }
-
- @Override
- public void onResume() {
- super.onResume();
- mContactsPreferences.refreshValue(ContactsPreferences.DISPLAY_ORDER_KEY);
- getCallDetails();
- }
-
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- TouchPointManager.getInstance().setPoint((int) ev.getRawX(), (int) ev.getRawY());
- }
- return super.dispatchTouchEvent(ev);
- }
-
- public void getCallDetails() {
- CallLogAsyncTaskUtil.getCallDetails(this, mCallLogAsyncTaskListener, getCallLogEntryUris());
- }
-
- /**
- * Returns the list of URIs to show.
- *
- * <p>There are two ways the URIs can be provided to the activity: as the data on the intent, or
- * as a list of ids in the call log added as an extra on the URI.
- *
- * <p>If both are available, the data on the intent takes precedence.
- */
- private Uri[] getCallLogEntryUris() {
- final Uri uri = getIntent().getData();
- if (uri != null) {
- // If there is a data on the intent, it takes precedence over the extra.
- return new Uri[] {uri};
- }
- final long[] ids = getIntent().getLongArrayExtra(EXTRA_CALL_LOG_IDS);
- final int numIds = ids == null ? 0 : ids.length;
- final Uri[] uris = new Uri[numIds];
- for (int index = 0; index < numIds; ++index) {
- uris[index] =
- ContentUris.withAppendedId(
- TelecomUtil.getCallLogUri(CallDetailActivity.this), ids[index]);
- }
- return uris;
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- final MenuItem deleteMenuItem =
- menu.add(
- Menu.NONE, R.id.call_detail_delete_menu_item, Menu.NONE, R.string.call_details_delete);
- deleteMenuItem.setIcon(R.drawable.ic_delete_24dp);
- deleteMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
- deleteMenuItem.setOnMenuItemClickListener(this);
-
- return super.onCreateOptionsMenu(menu);
- }
-
- @Override
- public boolean onMenuItemClick(MenuItem item) {
- if (item.getItemId() == R.id.call_detail_delete_menu_item) {
- Logger.get(mContext).logImpression(DialerImpression.Type.USER_DELETED_CALL_LOG_ITEM);
- if (hasVoicemail()) {
- CallLogAsyncTaskUtil.deleteVoicemail(this, mVoicemailUri, mCallLogAsyncTaskListener);
- } else {
- final StringBuilder callIds = new StringBuilder();
- for (Uri callUri : getCallLogEntryUris()) {
- if (callIds.length() != 0) {
- callIds.append(",");
- }
- callIds.append(ContentUris.parseId(callUri));
- }
- CallLogAsyncTaskUtil.deleteCalls(this, callIds.toString(), mCallLogAsyncTaskListener);
- }
- }
- return true;
- }
-
- @Override
- public void onClick(View view) {
- int resId = view.getId();
- if (resId == R.id.call_detail_action_copy) {
- ClipboardUtils.copyText(mContext, null, mNumber, true);
- } else if (resId == R.id.call_detail_action_edit_before_call) {
- Intent dialIntent = new Intent(Intent.ACTION_DIAL, CallUtil.getCallUri(getDialableNumber()));
- DialerUtils.startActivityWithErrorToast(mContext, dialIntent);
- } else {
- Assert.fail("Unexpected onClick event from " + view);
- }
- }
-
- // Loads and displays the contact photo.
- private void updateContactPhoto(boolean isSpam) {
- if (mDetails == null) {
- return;
- }
-
- mQuickContactBadge.assignContactUri(mDetails.contactUri);
- final String displayName =
- TextUtils.isEmpty(mDetails.namePrimary)
- ? mDetails.displayNumber
- : mDetails.namePrimary.toString();
- mQuickContactBadge.setContentDescription(
- mResources.getString(R.string.description_contact_details, displayName));
-
- final boolean isVoicemailNumber =
- PhoneNumberHelper.isVoicemailNumber(mContext, mDetails.accountHandle, mNumber);
- if (isSpam) {
- mQuickContactBadge.setImageDrawable(mContext.getDrawable(R.drawable.blocked_contact));
- return;
- }
-
- final boolean isBusiness = mContactInfoHelper.isBusiness(mDetails.sourceType);
- int contactType = ContactPhotoManager.TYPE_DEFAULT;
- if (isVoicemailNumber) {
- contactType = ContactPhotoManager.TYPE_VOICEMAIL;
- } else if (isBusiness) {
- contactType = ContactPhotoManager.TYPE_BUSINESS;
- }
-
- final String lookupKey =
- mDetails.contactUri == null ? null : UriUtils.getLookupKeyFromUri(mDetails.contactUri);
-
- final DefaultImageRequest request =
- new DefaultImageRequest(displayName, lookupKey, contactType, true /* isCircular */);
-
- mContactPhotoManager.loadDirectoryPhoto(
- mQuickContactBadge,
- mDetails.photoUri,
- false /* darkTheme */,
- true /* isCircular */,
- request);
- }
-
- private void closeSystemDialogs() {
- sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
- }
-
- private String getDialableNumber() {
- return mNumber + mPostDialDigits;
- }
-
- public boolean hasVoicemail() {
- return mVoicemailUri != null;
- }
-
- private static boolean hasIncomingCalls(PhoneCallDetails[] details) {
- for (int i = 0; i < details.length; i++) {
- if (details[i].hasIncomingCalls()) {
- return true;
- }
- }
- return false;
- }
-}
diff --git a/java/com/android/dialer/app/DialerApplication.java b/java/com/android/dialer/app/DialerApplication.java
deleted file mode 100644
index 3b979212b..000000000
--- a/java/com/android/dialer/app/DialerApplication.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2013 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.app;
-
-import android.app.Application;
-import android.os.Trace;
-import android.preference.PreferenceManager;
-import com.android.dialer.blocking.BlockedNumbersAutoMigrator;
-import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler;
-import com.android.dialer.enrichedcall.EnrichedCallManager;
-import com.android.dialer.inject.ApplicationModule;
-import com.android.dialer.inject.DaggerDialerAppComponent;
-import com.android.dialer.inject.DialerAppComponent;
-
-public class DialerApplication extends Application implements EnrichedCallManager.Factory {
-
- private static final String TAG = "DialerApplication";
-
- private volatile DialerAppComponent component;
-
- @Override
- public void onCreate() {
- Trace.beginSection(TAG + " onCreate");
- super.onCreate();
- new BlockedNumbersAutoMigrator(
- this,
- PreferenceManager.getDefaultSharedPreferences(this),
- new FilteredNumberAsyncQueryHandler(this))
- .autoMigrate();
- Trace.endSection();
- }
-
- @Override
- public EnrichedCallManager getEnrichedCallManager() {
- return component().enrichedCallManager();
- }
-
- protected DialerAppComponent buildApplicationComponent() {
- return DaggerDialerAppComponent.builder()
- .applicationModule(new ApplicationModule(this))
- .build();
- }
-
- /**
- * Returns the application component.
- *
- * <p>A single Component is created per application instance. Note that it won't be instantiated
- * until it's first requested, but guarantees that only one will ever be created.
- */
- private final DialerAppComponent component() {
- // Double-check idiom for lazy initialization
- DialerAppComponent result = component;
- if (result == null) {
- synchronized (this) {
- result = component;
- if (result == null) {
- component = result = buildApplicationComponent();
- }
- }
- }
- return result;
- }
-}
diff --git a/java/com/android/dialer/app/DialtactsActivity.java b/java/com/android/dialer/app/DialtactsActivity.java
index 4c57cda70..b2837769f 100644
--- a/java/com/android/dialer/app/DialtactsActivity.java
+++ b/java/com/android/dialer/app/DialtactsActivity.java
@@ -63,15 +63,14 @@ import android.widget.Toast;
import com.android.contacts.common.dialog.ClearFrequentsDialog;
import com.android.contacts.common.list.OnPhoneNumberPickerActionListener;
import com.android.contacts.common.list.PhoneNumberListAdapter;
-import com.android.contacts.common.list.PhoneNumberListAdapter.PhoneQuery;
import com.android.contacts.common.list.PhoneNumberPickerFragment.CursorReranker;
import com.android.contacts.common.list.PhoneNumberPickerFragment.OnLoadFinishedListener;
import com.android.contacts.common.widget.FloatingActionButtonController;
import com.android.dialer.animation.AnimUtils;
import com.android.dialer.animation.AnimationListenerAdapter;
+import com.android.dialer.app.calllog.CallLogActivity;
import com.android.dialer.app.calllog.CallLogFragment;
import com.android.dialer.app.calllog.CallLogNotificationsService;
-import com.android.dialer.app.calllog.ClearCallLogDialog;
import com.android.dialer.app.dialpad.DialpadFragment;
import com.android.dialer.app.list.DragDropController;
import com.android.dialer.app.list.ListsFragment;
@@ -85,6 +84,7 @@ import com.android.dialer.app.list.SpeedDialFragment;
import com.android.dialer.app.settings.DialerSettingsActivity;
import com.android.dialer.app.widget.ActionBarController;
import com.android.dialer.app.widget.SearchEditTextLayout;
+import com.android.dialer.callcomposer.CallComposerActivity;
import com.android.dialer.callintent.CallIntentBuilder;
import com.android.dialer.callintent.nano.CallSpecificAppData;
import com.android.dialer.common.Assert;
@@ -101,7 +101,10 @@ import com.android.dialer.p13n.inference.protocol.P13nRanker;
import com.android.dialer.p13n.inference.protocol.P13nRanker.P13nRefreshCompleteListener;
import com.android.dialer.p13n.logging.P13nLogger;
import com.android.dialer.p13n.logging.P13nLogging;
+import com.android.dialer.postcall.PostCall;
import com.android.dialer.proguard.UsedByReflection;
+import com.android.dialer.simulator.Simulator;
+import com.android.dialer.simulator.SimulatorComponent;
import com.android.dialer.smartdial.SmartDialNameMatcher;
import com.android.dialer.smartdial.SmartDialPrefix;
import com.android.dialer.telecom.TelecomUtil;
@@ -124,7 +127,6 @@ public class DialtactsActivity extends TransactionSafeActivity
OnListFragmentScrolledListener,
CallLogFragment.HostInterface,
DialpadFragment.HostInterface,
- ListsFragment.HostInterface,
SpeedDialFragment.HostInterface,
SearchFragment.HostInterface,
OnDragDropListener,
@@ -478,6 +480,7 @@ public class DialtactsActivity extends TransactionSafeActivity
@Override
protected void onResume() {
+ LogUtil.d("DialtactsActivity.onResume", "");
Trace.beginSection(TAG + " onResume");
super.onResume();
@@ -490,6 +493,8 @@ public class DialtactsActivity extends TransactionSafeActivity
} else if (mShowDialpadOnResume) {
showDialpadFragment(false);
mShowDialpadOnResume = false;
+ } else {
+ PostCall.promptUserForMessageIfNecessary(this, mParentLayout);
}
// If there was a voice query result returned in the {@link #onActivityResult} callback, it
@@ -539,7 +544,7 @@ public class DialtactsActivity extends TransactionSafeActivity
}
if (getIntent().getBooleanExtra(EXTRA_CLEAR_NEW_VOICEMAILS, false)) {
- CallLogNotificationsService.markNewVoicemailsAsOld(this);
+ CallLogNotificationsService.markNewVoicemailsAsOld(this, null);
}
setSearchBoxHint();
@@ -588,6 +593,7 @@ public class DialtactsActivity extends TransactionSafeActivity
@Override
public void onAttachFragment(final Fragment fragment) {
+ LogUtil.d("DialtactsActivity.onAttachFragment", "fragment: %s", fragment);
if (fragment instanceof DialpadFragment) {
mDialpadFragment = (DialpadFragment) fragment;
if (!mIsDialpadShown && !mShowDialpadOnResume) {
@@ -616,7 +622,8 @@ public class DialtactsActivity extends TransactionSafeActivity
@MainThread
public Cursor rerankCursor(Cursor data) {
Assert.isMainThread();
- return mP13nRanker.rankCursor(data, PhoneQuery.PHONE_NUMBER);
+ String queryString = searchFragment.getQueryString();
+ return mP13nRanker.rankCursor(data, queryString == null ? 0 : queryString.length());
}
});
searchFragment.addOnLoadFinishedListener(
@@ -674,9 +681,9 @@ public class DialtactsActivity extends TransactionSafeActivity
}
int resId = item.getItemId();
- if (item.getItemId() == R.id.menu_delete_all) {
- ClearCallLogDialog.show(getFragmentManager());
- return true;
+ if (resId == R.id.menu_history) {
+ final Intent intent = new Intent(this, CallLogActivity.class);
+ startActivity(intent);
} else if (resId == R.id.menu_clear_frequents) {
ClearFrequentsDialog.show(getFragmentManager());
Logger.get(this).logScreenView(ScreenEvent.Type.CLEAR_FREQUENTS, this);
@@ -691,6 +698,11 @@ public class DialtactsActivity extends TransactionSafeActivity
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ LogUtil.i(
+ "DialtactsActivity.onActivityResult",
+ "requestCode:%d, resultCode:%d",
+ requestCode,
+ resultCode);
if (requestCode == ACTIVITY_REQUEST_CODE_VOICE_SEARCH) {
if (resultCode == RESULT_OK) {
final ArrayList<String> matches =
@@ -701,15 +713,16 @@ public class DialtactsActivity extends TransactionSafeActivity
LogUtil.i("DialtactsActivity.onActivityResult", "voice search - nothing heard");
}
} else {
- LogUtil.e("DialtactsActivity.onActivityResult", "voice search failed: " + resultCode);
+ LogUtil.e("DialtactsActivity.onActivityResult", "voice search failed");
}
} else if (requestCode == ACTIVITY_REQUEST_CODE_CALL_COMPOSE) {
- if (resultCode != RESULT_OK) {
+ if (resultCode == RESULT_FIRST_USER) {
LogUtil.i(
- "DialtactsActivity.onActivityResult",
- "returned from call composer, error occurred (resultCode=" + resultCode + ")");
+ "DialtactsActivity.onActivityResult", "returned from call composer, error occurred");
String message =
- getString(R.string.call_composer_connection_failed, getString(R.string.share_and_call));
+ getString(
+ R.string.call_composer_connection_failed,
+ data.getStringExtra(CallComposerActivity.KEY_CONTACT_NAME));
Snackbar.make(mParentLayout, message, Snackbar.LENGTH_LONG).show();
} else {
LogUtil.i("DialtactsActivity.onActivityResult", "returned from call composer, no error");
@@ -732,6 +745,7 @@ public class DialtactsActivity extends TransactionSafeActivity
* @see #onDialpadShown
*/
private void showDialpadFragment(boolean animate) {
+ LogUtil.d("DialtactActivity.showDialpadFragment", "animate: %b", animate);
if (mIsDialpadShown || mStateSaved) {
return;
}
@@ -767,6 +781,7 @@ public class DialtactsActivity extends TransactionSafeActivity
/** Callback from child DialpadFragment when the dialpad is shown. */
public void onDialpadShown() {
+ LogUtil.d("DialtactsActivity.onDialpadShown", "");
Assert.isNotNull(mDialpadFragment);
if (mDialpadFragment.getAnimate()) {
Assert.isNotNull(mDialpadFragment.getView()).startAnimation(mSlideIn);
@@ -838,12 +853,21 @@ public class DialtactsActivity extends TransactionSafeActivity
private void updateSearchFragmentPosition() {
SearchFragment fragment = null;
- if (mSmartDialSearchFragment != null && mSmartDialSearchFragment.isVisible()) {
+ if (mSmartDialSearchFragment != null) {
fragment = mSmartDialSearchFragment;
- } else if (mRegularSearchFragment != null && mRegularSearchFragment.isVisible()) {
+ } else if (mRegularSearchFragment != null) {
fragment = mRegularSearchFragment;
}
- if (fragment != null && fragment.isVisible()) {
+ LogUtil.d(
+ "DialtactsActivity.updateSearchFragmentPosition",
+ "fragment: %s, isVisible: %b",
+ fragment,
+ fragment != null && fragment.isVisible());
+ if (fragment != null) {
+ // We need to force animation here even when fragment is not visible since it might not be
+ // visible immediately after screen orientation change and dialpad height would not be
+ // available immediately which is required to update position. By forcing an animation,
+ // position will be updated after a delay by when the dialpad height would be available.
fragment.updatePosition(true /* animate */);
}
}
@@ -858,11 +882,6 @@ public class DialtactsActivity extends TransactionSafeActivity
return !TextUtils.isEmpty(mSearchQuery);
}
- @Override
- public boolean shouldShowActionBar() {
- return mListsFragment.shouldShowActionBar();
- }
-
private void setNotInSearchUi() {
mInDialpadSearch = false;
mInRegularSearch = false;
@@ -1056,7 +1075,8 @@ public class DialtactsActivity extends TransactionSafeActivity
}
// DialtactsActivity will provide the options menu
fragment.setHasOptionsMenu(false);
- fragment.setShowEmptyListForNullQuery(true);
+ // Will show empty list if P13nRanker is not enabled. Else, re-ranked list by the ranker.
+ fragment.setShowEmptyListForNullQuery(mP13nRanker.shouldShowEmptyListForNullQuery());
if (!smartDialSearch) {
fragment.setQueryString(query);
}
@@ -1361,11 +1381,6 @@ public class DialtactsActivity extends TransactionSafeActivity
}
@Override
- public ActionBarController getActionBarController() {
- return mActionBarController;
- }
-
- @Override
public boolean isDialpadShown() {
return mIsDialpadShown;
}
@@ -1379,11 +1394,6 @@ public class DialtactsActivity extends TransactionSafeActivity
}
@Override
- public int getActionBarHideOffset() {
- return getActionBarSafely().getHideOffset();
- }
-
- @Override
public void setActionBarHideOffset(int offset) {
getActionBarSafely().setHideOffset(offset);
}
@@ -1461,8 +1471,19 @@ public class DialtactsActivity extends TransactionSafeActivity
&& mListsFragment.getSpeedDialFragment().hasFrequents()
&& hasContactsPermission);
- menu.findItem(R.id.menu_delete_all)
+ menu.findItem(R.id.menu_history)
.setVisible(PermissionsUtil.hasPhonePermissions(DialtactsActivity.this));
+
+ Context context = DialtactsActivity.this.getApplicationContext();
+ MenuItem simulatorMenuItem = menu.findItem(R.id.menu_simulator_submenu);
+ Simulator simulator = SimulatorComponent.get(context).getSimulator();
+ if (simulator.shouldShow()) {
+ simulatorMenuItem.setVisible(true);
+ simulatorMenuItem.setActionProvider(simulator.getActionProvider(context));
+ } else {
+ simulatorMenuItem.setVisible(false);
+ }
+
super.show();
}
}
diff --git a/java/com/android/dialer/app/PhoneCallDetails.java b/java/com/android/dialer/app/PhoneCallDetails.java
deleted file mode 100644
index 436f68eec..000000000
--- a/java/com/android/dialer/app/PhoneCallDetails.java
+++ /dev/null
@@ -1,207 +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.app;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.net.Uri;
-import android.provider.CallLog;
-import android.provider.CallLog.Calls;
-import android.support.annotation.Nullable;
-import android.telecom.PhoneAccountHandle;
-import android.text.TextUtils;
-import com.android.contacts.common.ContactsUtils.UserType;
-import com.android.contacts.common.preference.ContactsPreferences;
-import com.android.contacts.common.util.ContactDisplayUtils;
-import com.android.dialer.app.calllog.PhoneNumberDisplayUtil;
-import com.android.dialer.phonenumbercache.ContactInfo;
-
-/** The details of a phone call to be shown in the UI. */
-public class PhoneCallDetails {
-
- // The number of the other party involved in the call.
- public CharSequence number;
- // Post-dial digits associated with the outgoing call.
- public String postDialDigits;
- // The secondary line number the call was received via.
- public String viaNumber;
- // The number presenting rules set by the network, e.g., {@link Calls#PRESENTATION_ALLOWED}
- public int numberPresentation;
- // The country corresponding with the phone number.
- public String countryIso;
- // The geocoded location for the phone number.
- public String geocode;
-
- /**
- * The type of calls, as defined in the call log table, e.g., {@link Calls#INCOMING_TYPE}.
- *
- * <p>There might be multiple types if this represents a set of entries grouped together.
- */
- public int[] callTypes;
-
- // The date of the call, in milliseconds since the epoch.
- public long date;
- // The duration of the call in milliseconds, or 0 for missed calls.
- public long duration;
- // The name of the contact, or the empty string.
- public CharSequence namePrimary;
- // The alternative name of the contact, e.g. last name first, or the empty string
- public CharSequence nameAlternative;
- /**
- * The user's preference on name display order, last name first or first time first. {@see
- * ContactsPreferences}
- */
- public int nameDisplayOrder;
- // The type of phone, e.g., {@link Phone#TYPE_HOME}, 0 if not available.
- public int numberType;
- // The custom label associated with the phone number in the contact, or the empty string.
- public CharSequence numberLabel;
- // The URI of the contact associated with this phone call.
- public Uri contactUri;
-
- /**
- * The photo URI of the picture of the contact that is associated with this phone call or null if
- * there is none.
- *
- * <p>This is meant to store the high-res photo only.
- */
- public Uri photoUri;
-
- // The source type of the contact associated with this call.
- public int sourceType;
-
- // The object id type of the contact associated with this call.
- public String objectId;
-
- // The unique identifier for the account associated with the call.
- public PhoneAccountHandle accountHandle;
-
- // Features applicable to this call.
- public int features;
-
- // Total data usage for this call.
- public Long dataUsage;
-
- // Voicemail transcription
- public String transcription;
-
- // The display string for the number.
- public String displayNumber;
-
- // Whether the contact number is a voicemail number.
- public boolean isVoicemail;
-
- /** The {@link UserType} of the contact */
- public @UserType long contactUserType;
-
- /**
- * If this is a voicemail, whether the message is read. For other types of calls, this defaults to
- * {@code true}.
- */
- public boolean isRead = true;
-
- // If this call is a spam number.
- public boolean isSpam = false;
-
- // If this call is a blocked number.
- public boolean isBlocked = false;
-
- // Call location and date text.
- public CharSequence callLocationAndDate;
-
- // Call description.
- public CharSequence callDescription;
- public String accountComponentName;
- public String accountId;
- public ContactInfo cachedContactInfo;
- public int voicemailId;
- public int previousGroup;
-
- /**
- * Constructor with required fields for the details of a call with a number associated with a
- * contact.
- */
- public PhoneCallDetails(
- CharSequence number, int numberPresentation, CharSequence postDialDigits) {
- this.number = number;
- this.numberPresentation = numberPresentation;
- this.postDialDigits = postDialDigits.toString();
- }
- /**
- * Construct the "on {accountLabel} via {viaNumber}" accessibility description for the account
- * list item, depending on the existence of the accountLabel and viaNumber.
- *
- * @param viaNumber The number that this call is being placed via.
- * @param accountLabel The {@link PhoneAccount} label that this call is being placed with.
- * @return The description of the account that this call has been placed on.
- */
- public static CharSequence createAccountLabelDescription(
- Resources resources, @Nullable String viaNumber, @Nullable CharSequence accountLabel) {
-
- if ((!TextUtils.isEmpty(viaNumber)) && !TextUtils.isEmpty(accountLabel)) {
- String msg =
- resources.getString(
- R.string.description_via_number_phone_account, accountLabel, viaNumber);
- CharSequence accountNumberLabel =
- ContactDisplayUtils.getTelephoneTtsSpannable(msg, viaNumber);
- return (accountNumberLabel == null) ? msg : accountNumberLabel;
- } else if (!TextUtils.isEmpty(viaNumber)) {
- CharSequence viaNumberLabel =
- ContactDisplayUtils.getTtsSpannedPhoneNumber(
- resources, R.string.description_via_number, viaNumber);
- return (viaNumberLabel == null) ? viaNumber : viaNumberLabel;
- } else if (!TextUtils.isEmpty(accountLabel)) {
- return TextUtils.expandTemplate(
- resources.getString(R.string.description_phone_account), accountLabel);
- }
- return "";
- }
-
- /**
- * Returns the preferred name for the call details as specified by the {@link #nameDisplayOrder}
- *
- * @return the preferred name
- */
- public CharSequence getPreferredName() {
- if (nameDisplayOrder == ContactsPreferences.DISPLAY_ORDER_PRIMARY
- || TextUtils.isEmpty(nameAlternative)) {
- return namePrimary;
- }
- return nameAlternative;
- }
-
- public void updateDisplayNumber(
- Context context, CharSequence formattedNumber, boolean isVoicemail) {
- displayNumber =
- PhoneNumberDisplayUtil.getDisplayNumber(
- context, number, numberPresentation, formattedNumber, postDialDigits, isVoicemail)
- .toString();
- }
-
- public boolean hasIncomingCalls() {
- for (int i = 0; i < callTypes.length; i++) {
- if (callTypes[i] == CallLog.Calls.INCOMING_TYPE
- || callTypes[i] == CallLog.Calls.MISSED_TYPE
- || callTypes[i] == CallLog.Calls.VOICEMAIL_TYPE
- || callTypes[i] == CallLog.Calls.REJECTED_TYPE
- || callTypes[i] == CallLog.Calls.BLOCKED_TYPE) {
- return true;
- }
- }
- return false;
- }
-}
diff --git a/java/com/android/dialer/app/SpecialCharSequenceMgr.java b/java/com/android/dialer/app/SpecialCharSequenceMgr.java
index 2ae19704a..712659c12 100644
--- a/java/com/android/dialer/app/SpecialCharSequenceMgr.java
+++ b/java/com/android/dialer/app/SpecialCharSequenceMgr.java
@@ -28,15 +28,14 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
-import android.os.Looper;
import android.provider.Settings;
import android.support.annotation.Nullable;
+import android.support.v4.os.BuildCompat;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telephony.PhoneNumberUtils;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
-import android.util.Log;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.Toast;
@@ -46,8 +45,11 @@ import com.android.contacts.common.database.NoNullCursorAsyncQueryHandler;
import com.android.contacts.common.util.ContactDisplayUtils;
import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment;
import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment.SelectPhoneAccountListener;
-import com.android.dialer.app.calllog.PhoneAccountUtils;
+import com.android.dialer.calllogutils.PhoneAccountUtils;
+import com.android.dialer.common.Assert;
+import com.android.dialer.common.LogUtil;
import com.android.dialer.compat.CompatUtils;
+import com.android.dialer.oem.MotorolaUtils;
import com.android.dialer.telecom.TelecomUtil;
import java.util.ArrayList;
import java.util.List;
@@ -100,12 +102,19 @@ public class SpecialCharSequenceMgr {
//get rid of the separators so that the string gets parsed correctly
String dialString = PhoneNumberUtils.stripSeparators(input);
- return handleDeviceIdDisplay(context, dialString)
+ if (handleDeviceIdDisplay(context, dialString)
|| handleRegulatoryInfoDisplay(context, dialString)
|| handlePinEntry(context, dialString)
|| handleAdnEntry(context, dialString, textField)
- || handleSecretCode(context, dialString);
+ || handleSecretCode(context, dialString)) {
+ return true;
+ }
+
+ if (MotorolaUtils.handleSpecialCharSequence(context, input)) {
+ return true;
+ }
+ return false;
}
/**
@@ -114,10 +123,7 @@ public class SpecialCharSequenceMgr {
* <p>This should be called when the screen becomes background.
*/
public static void cleanup() {
- if (Looper.myLooper() != Looper.getMainLooper()) {
- Log.wtf(TAG, "cleanup() is called outside the main thread");
- return;
- }
+ Assert.isMainThread();
if (sPreviousAdnQueryHandler != null) {
sPreviousAdnQueryHandler.cancel();
@@ -126,14 +132,21 @@ public class SpecialCharSequenceMgr {
}
/**
- * Handles secret codes to launch arbitrary activities in the form of *#*#<code>#*#*. If a secret
- * code is encountered an Intent is started with the android_secret_code://<code> URI.
+ * Handles secret codes to launch arbitrary activities in the form of *#*#<code>#*#*.
+ * If a secret code is encountered, an Intent is started with the android_secret_code://<code>
+ * URI.
*
* @param context the context to use
* @param input the text to check for a secret code in
- * @return true if a secret code was encountered
+ * @return true if a secret code was encountered and intent is sent out
*/
static boolean handleSecretCode(Context context, String input) {
+ // Must use system service on O+ to avoid using broadcasts, which are not allowed on O+.
+ if (BuildCompat.isAtLeastO()) {
+ return context.getSystemService(TelephonyManager.class).sendDialerCode(input);
+ }
+
+ // System service call is not supported pre-O, so must use a broadcast for N-.
// Secret codes are in the form *#*#<code>#*#*
int len = input.length();
if (len > 8 && input.startsWith("*#*#") && input.endsWith("#*#*")) {
@@ -144,7 +157,6 @@ public class SpecialCharSequenceMgr {
context.sendBroadcast(intent);
return true;
}
-
return false;
}
@@ -237,7 +249,7 @@ public class SpecialCharSequenceMgr {
private static void handleAdnQuery(QueryHandler handler, SimContactQueryCookie cookie, Uri uri) {
if (handler == null || cookie == null || uri == null) {
- Log.w(TAG, "queryAdn parameters incorrect");
+ LogUtil.w("SpecialCharSequenceMgr.handleAdnQuery", "queryAdn parameters incorrect");
return;
}
@@ -325,12 +337,14 @@ public class SpecialCharSequenceMgr {
private static boolean handleRegulatoryInfoDisplay(Context context, String input) {
if (input.equals(MMI_REGULATORY_INFO_DISPLAY)) {
- Log.d(TAG, "handleRegulatoryInfoDisplay() sending intent to settings app");
+ LogUtil.i(
+ "SpecialCharSequenceMgr.handleRegulatoryInfoDisplay", "sending intent to settings app");
Intent showRegInfoIntent = new Intent(Settings.ACTION_SHOW_REGULATORY_INFO);
try {
context.startActivity(showRegInfoIntent);
} catch (ActivityNotFoundException e) {
- Log.e(TAG, "startActivity() failed: " + e);
+ LogUtil.e(
+ "SpecialCharSequenceMgr.handleRegulatoryInfoDisplay", "startActivity() failed: ", e);
}
return true;
}
diff --git a/java/com/android/dialer/app/calllog/CallDetailHistoryAdapter.java b/java/com/android/dialer/app/calllog/CallDetailHistoryAdapter.java
deleted file mode 100644
index ab6ef7362..000000000
--- a/java/com/android/dialer/app/calllog/CallDetailHistoryAdapter.java
+++ /dev/null
@@ -1,214 +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.app.calllog;
-
-import android.content.Context;
-import android.icu.lang.UCharacter;
-import android.icu.text.BreakIterator;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
-import android.provider.CallLog.Calls;
-import android.text.format.DateUtils;
-import android.text.format.Formatter;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.TextView;
-import com.android.dialer.app.PhoneCallDetails;
-import com.android.dialer.app.R;
-import com.android.dialer.util.CallUtil;
-import com.android.dialer.util.DialerUtils;
-import java.util.ArrayList;
-import java.util.Locale;
-
-/** Adapter for a ListView containing history items from the details of a call. */
-public class CallDetailHistoryAdapter extends BaseAdapter {
-
- /** Each history item shows the detail of a call. */
- private static final int VIEW_TYPE_HISTORY_ITEM = 1;
-
- private final Context mContext;
- private final LayoutInflater mLayoutInflater;
- private final CallTypeHelper mCallTypeHelper;
- private final PhoneCallDetails[] mPhoneCallDetails;
-
- /** List of items to be concatenated together for duration strings. */
- private ArrayList<CharSequence> mDurationItems = new ArrayList<>();
-
- public CallDetailHistoryAdapter(
- Context context,
- LayoutInflater layoutInflater,
- CallTypeHelper callTypeHelper,
- PhoneCallDetails[] phoneCallDetails) {
- mContext = context;
- mLayoutInflater = layoutInflater;
- mCallTypeHelper = callTypeHelper;
- mPhoneCallDetails = phoneCallDetails;
- }
-
- @Override
- public boolean isEnabled(int position) {
- // None of history will be clickable.
- return false;
- }
-
- @Override
- public int getCount() {
- return mPhoneCallDetails.length;
- }
-
- @Override
- public Object getItem(int position) {
- return mPhoneCallDetails[position];
- }
-
- @Override
- public long getItemId(int position) {
- return position;
- }
-
- @Override
- public int getViewTypeCount() {
- return 1;
- }
-
- @Override
- public int getItemViewType(int position) {
- return VIEW_TYPE_HISTORY_ITEM;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- // Make sure we have a valid convertView to start with
- final View result =
- convertView == null
- ? mLayoutInflater.inflate(R.layout.call_detail_history_item, parent, false)
- : convertView;
-
- PhoneCallDetails details = mPhoneCallDetails[position];
- CallTypeIconsView callTypeIconView =
- (CallTypeIconsView) result.findViewById(R.id.call_type_icon);
- TextView callTypeTextView = (TextView) result.findViewById(R.id.call_type_text);
- TextView dateView = (TextView) result.findViewById(R.id.date);
- TextView durationView = (TextView) result.findViewById(R.id.duration);
-
- int callType = details.callTypes[0];
- boolean isVideoCall =
- (details.features & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO
- && CallUtil.isVideoEnabled(mContext);
- boolean isPulledCall =
- (details.features & Calls.FEATURES_PULLED_EXTERNALLY) == Calls.FEATURES_PULLED_EXTERNALLY;
-
- callTypeIconView.clear();
- callTypeIconView.add(callType);
- callTypeIconView.setShowVideo(isVideoCall);
- callTypeTextView.setText(mCallTypeHelper.getCallTypeText(callType, isVideoCall, isPulledCall));
- // Set the date.
- dateView.setText(formatDate(details.date));
- // Set the duration
- if (Calls.VOICEMAIL_TYPE == callType || CallTypeHelper.isMissedCallType(callType)) {
- durationView.setVisibility(View.GONE);
- } else {
- durationView.setVisibility(View.VISIBLE);
- durationView.setText(formatDurationAndDataUsage(details.duration, details.dataUsage));
- }
-
- return result;
- }
-
- /**
- * Formats the provided date into a value suitable for display in the current locale.
- *
- * <p>For example, returns a string like "Wednesday, May 25, 2016, 8:02PM" or "Chorshanba, 2016
- * may 25,20:02".
- *
- * <p>For pre-N devices, the returned value may not start with a capital if the local convention
- * is to not capitalize day names. On N+ devices, the returned value is always capitalized.
- */
- private CharSequence formatDate(long callDateMillis) {
- CharSequence dateValue =
- DateUtils.formatDateRange(
- mContext,
- callDateMillis /* startDate */,
- callDateMillis /* endDate */,
- DateUtils.FORMAT_SHOW_TIME
- | DateUtils.FORMAT_SHOW_DATE
- | DateUtils.FORMAT_SHOW_WEEKDAY
- | DateUtils.FORMAT_SHOW_YEAR);
-
- // We want the beginning of the date string to be capitalized, even if the word at the beginning
- // of the string is not usually capitalized. For example, "Wednesdsay" in Uzbek is "chorshanba”
- // (not capitalized). To handle this issue we apply title casing to the start of the sentence so
- // that "chorshanba, 2016 may 25,20:02" becomes "Chorshanba, 2016 may 25,20:02".
- //
- // The ICU library was not available in Android until N, so we can only do this in N+ devices.
- // Pre-N devices will still see incorrect capitalization in some languages.
- if (VERSION.SDK_INT < VERSION_CODES.N) {
- return dateValue;
- }
-
- // Using the ICU library is safer than just applying toUpperCase() on the first letter of the
- // word because in some languages, there can be multiple starting characters which should be
- // upper-cased together. For example in Dutch "ij" is a digraph in which both letters should be
- // capitalized together.
-
- // TITLECASE_NO_LOWERCASE is necessary so that things that are already capitalized like the
- // month ("May") are not lower-cased as part of the conversion.
- return UCharacter.toTitleCase(
- Locale.getDefault(),
- dateValue.toString(),
- BreakIterator.getSentenceInstance(),
- UCharacter.TITLECASE_NO_LOWERCASE);
- }
-
- private CharSequence formatDuration(long elapsedSeconds) {
- long minutes = 0;
- long seconds = 0;
-
- if (elapsedSeconds >= 60) {
- minutes = elapsedSeconds / 60;
- elapsedSeconds -= minutes * 60;
- seconds = elapsedSeconds;
- return mContext.getString(R.string.callDetailsDurationFormat, minutes, seconds);
- } else {
- seconds = elapsedSeconds;
- return mContext.getString(R.string.callDetailsShortDurationFormat, seconds);
- }
- }
-
- /**
- * Formats a string containing the call duration and the data usage (if specified).
- *
- * @param elapsedSeconds Total elapsed seconds.
- * @param dataUsage Data usage in bytes, or null if not specified.
- * @return String containing call duration and data usage.
- */
- private CharSequence formatDurationAndDataUsage(long elapsedSeconds, Long dataUsage) {
- CharSequence duration = formatDuration(elapsedSeconds);
-
- if (dataUsage != null) {
- mDurationItems.clear();
- mDurationItems.add(duration);
- mDurationItems.add(Formatter.formatShortFileSize(mContext, dataUsage));
-
- return DialerUtils.join(mDurationItems);
- } else {
- return duration;
- }
- }
-}
diff --git a/java/com/android/dialer/app/calllog/CallLogActivity.java b/java/com/android/dialer/app/calllog/CallLogActivity.java
new file mode 100644
index 000000000..719ab4369
--- /dev/null
+++ b/java/com/android/dialer/app/calllog/CallLogActivity.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2013 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.app.calllog;
+
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.content.Intent;
+import android.os.Bundle;
+import android.provider.CallLog;
+import android.provider.CallLog.Calls;
+import android.support.v13.app.FragmentPagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.support.v7.app.ActionBar;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.ViewGroup;
+import com.android.contacts.common.list.ViewPagerTabs;
+import com.android.dialer.app.DialtactsActivity;
+import com.android.dialer.app.R;
+import com.android.dialer.database.CallLogQueryHandler;
+import com.android.dialer.logging.Logger;
+import com.android.dialer.logging.nano.ScreenEvent;
+import com.android.dialer.util.TransactionSafeActivity;
+import com.android.dialer.util.ViewUtil;
+
+/** Activity for viewing call history. */
+public class CallLogActivity extends TransactionSafeActivity
+ implements ViewPager.OnPageChangeListener {
+
+ private static final int TAB_INDEX_ALL = 0;
+ private static final int TAB_INDEX_MISSED = 1;
+ private static final int TAB_INDEX_COUNT = 2;
+ private ViewPager mViewPager;
+ private ViewPagerTabs mViewPagerTabs;
+ private ViewPagerAdapter mViewPagerAdapter;
+ private CallLogFragment mAllCallsFragment;
+ private CallLogFragment mMissedCallsFragment;
+ private String[] mTabTitles;
+ private boolean mIsResumed;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.call_log_activity);
+ getWindow().setBackgroundDrawable(null);
+
+ final ActionBar actionBar = getSupportActionBar();
+ actionBar.setDisplayShowHomeEnabled(true);
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setDisplayShowTitleEnabled(true);
+ actionBar.setElevation(0);
+
+ int startingTab = TAB_INDEX_ALL;
+ final Intent intent = getIntent();
+ if (intent != null) {
+ final int callType = intent.getIntExtra(CallLog.Calls.EXTRA_CALL_TYPE_FILTER, -1);
+ if (callType == CallLog.Calls.MISSED_TYPE) {
+ startingTab = TAB_INDEX_MISSED;
+ }
+ }
+
+ mTabTitles = new String[TAB_INDEX_COUNT];
+ mTabTitles[0] = getString(R.string.call_log_all_title);
+ mTabTitles[1] = getString(R.string.call_log_missed_title);
+
+ mViewPager = (ViewPager) findViewById(R.id.call_log_pager);
+
+ mViewPagerAdapter = new ViewPagerAdapter(getFragmentManager());
+ mViewPager.setAdapter(mViewPagerAdapter);
+ mViewPager.setOffscreenPageLimit(1);
+ mViewPager.setOnPageChangeListener(this);
+
+ mViewPagerTabs = (ViewPagerTabs) findViewById(R.id.viewpager_header);
+
+ mViewPagerTabs.setViewPager(mViewPager);
+ mViewPager.setCurrentItem(startingTab);
+ }
+
+ @Override
+ protected void onResume() {
+ mIsResumed = true;
+ super.onResume();
+ sendScreenViewForChildFragment(mViewPager.getCurrentItem());
+ }
+
+ @Override
+ protected void onPause() {
+ mIsResumed = false;
+ super.onPause();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ final MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.call_log_options, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ final MenuItem itemDeleteAll = menu.findItem(R.id.delete_all);
+ if (mAllCallsFragment != null && itemDeleteAll != null) {
+ // If onPrepareOptionsMenu is called before fragments are loaded, don't do anything.
+ final CallLogAdapter adapter = mAllCallsFragment.getAdapter();
+ itemDeleteAll.setVisible(adapter != null && !adapter.isEmpty());
+ }
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (!isSafeToCommitTransactions()) {
+ return true;
+ }
+
+ if (item.getItemId() == android.R.id.home) {
+ final Intent intent = new Intent(this, DialtactsActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ startActivity(intent);
+ return true;
+ } else if (item.getItemId() == R.id.delete_all) {
+ ClearCallLogDialog.show(getFragmentManager());
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ mViewPagerTabs.onPageScrolled(position, positionOffset, positionOffsetPixels);
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ if (mIsResumed) {
+ sendScreenViewForChildFragment(position);
+ }
+ mViewPagerTabs.onPageSelected(position);
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ mViewPagerTabs.onPageScrollStateChanged(state);
+ }
+
+ private void sendScreenViewForChildFragment(int position) {
+ Logger.get(this).logScreenView(ScreenEvent.Type.CALL_LOG_FILTER, this);
+ }
+
+ private int getRtlPosition(int position) {
+ if (ViewUtil.isRtl()) {
+ return mViewPagerAdapter.getCount() - 1 - position;
+ }
+ return position;
+ }
+
+ /** Adapter for the view pager. */
+ public class ViewPagerAdapter extends FragmentPagerAdapter {
+
+ public ViewPagerAdapter(FragmentManager fm) {
+ super(fm);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return getRtlPosition(position);
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ switch (getRtlPosition(position)) {
+ case TAB_INDEX_ALL:
+ return new CallLogFragment(
+ CallLogQueryHandler.CALL_TYPE_ALL, true /* isCallLogActivity */);
+ case TAB_INDEX_MISSED:
+ return new CallLogFragment(Calls.MISSED_TYPE, true /* isCallLogActivity */);
+ }
+ throw new IllegalStateException("No fragment at position " + position);
+ }
+
+ @Override
+ public Object instantiateItem(ViewGroup container, int position) {
+ final CallLogFragment fragment = (CallLogFragment) super.instantiateItem(container, position);
+ switch (position) {
+ case TAB_INDEX_ALL:
+ mAllCallsFragment = fragment;
+ break;
+ case TAB_INDEX_MISSED:
+ mMissedCallsFragment = fragment;
+ break;
+ }
+ return fragment;
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ return mTabTitles[position];
+ }
+
+ @Override
+ public int getCount() {
+ return TAB_INDEX_COUNT;
+ }
+ }
+}
diff --git a/java/com/android/dialer/app/calllog/CallLogAdapter.java b/java/com/android/dialer/app/calllog/CallLogAdapter.java
index ea09a8c0a..fc5ffbb29 100644
--- a/java/com/android/dialer/app/calllog/CallLogAdapter.java
+++ b/java/com/android/dialer/app/calllog/CallLogAdapter.java
@@ -47,7 +47,6 @@ import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
import com.android.contacts.common.preference.ContactsPreferences;
import com.android.dialer.app.Bindings;
import com.android.dialer.app.DialtactsActivity;
-import com.android.dialer.app.PhoneCallDetails;
import com.android.dialer.app.R;
import com.android.dialer.app.calllog.CallLogGroupBuilder.GroupCreator;
import com.android.dialer.app.calllog.calllogcache.CallLogCache;
@@ -55,13 +54,19 @@ import com.android.dialer.app.contactinfo.ContactInfoCache;
import com.android.dialer.app.voicemail.VoicemailPlaybackPresenter;
import com.android.dialer.app.voicemail.VoicemailPlaybackPresenter.OnVoicemailDeletedListener;
import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler;
+import com.android.dialer.calldetails.nano.CallDetailsEntries;
+import com.android.dialer.calldetails.nano.CallDetailsEntries.CallDetailsEntry;
+import com.android.dialer.calllogutils.PhoneAccountUtils;
+import com.android.dialer.calllogutils.PhoneCallDetails;
import com.android.dialer.common.Assert;
import com.android.dialer.common.AsyncTaskExecutor;
import com.android.dialer.common.AsyncTaskExecutors;
import com.android.dialer.common.LogUtil;
import com.android.dialer.enrichedcall.EnrichedCallCapabilities;
+import com.android.dialer.enrichedcall.EnrichedCallComponent;
import com.android.dialer.enrichedcall.EnrichedCallManager;
import com.android.dialer.enrichedcall.EnrichedCallManager.CapabilitiesListener;
+import com.android.dialer.enrichedcall.historyquery.proto.nano.HistoryResult;
import com.android.dialer.logging.Logger;
import com.android.dialer.logging.nano.DialerImpression;
import com.android.dialer.phonenumbercache.CallLogQuery;
@@ -70,6 +75,7 @@ import com.android.dialer.phonenumbercache.ContactInfoHelper;
import com.android.dialer.phonenumberutil.PhoneNumberHelper;
import com.android.dialer.spam.Spam;
import com.android.dialer.util.PermissionsUtil;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -96,7 +102,7 @@ public class CallLogAdapter extends GroupingListAdapter
protected final CallLogCache mCallLogCache;
private final CallFetcher mCallFetcher;
- private final FilteredNumberAsyncQueryHandler mFilteredNumberAsyncQueryHandler;
+ @NonNull private final FilteredNumberAsyncQueryHandler mFilteredNumberAsyncQueryHandler;
private final int mActivityType;
/** Instance of helper class for managing views. */
@@ -182,8 +188,6 @@ public class CallLogAdapter extends GroupingListAdapter
private boolean mIsSpamEnabled;
- @NonNull private final EnrichedCallManager mEnrichedCallManager;
-
public CallLogAdapter(
Activity activity,
ViewGroup alertContainer,
@@ -191,6 +195,7 @@ public class CallLogAdapter extends GroupingListAdapter
CallLogCache callLogCache,
ContactInfoCache contactInfoCache,
VoicemailPlaybackPresenter voicemailPlaybackPresenter,
+ @NonNull FilteredNumberAsyncQueryHandler filteredNumberAsyncQueryHandler,
int activityType) {
super();
@@ -218,7 +223,7 @@ public class CallLogAdapter extends GroupingListAdapter
mCallLogListItemHelper =
new CallLogListItemHelper(phoneCallDetailsHelper, resources, mCallLogCache);
mCallLogGroupBuilder = new CallLogGroupBuilder(this);
- mFilteredNumberAsyncQueryHandler = new FilteredNumberAsyncQueryHandler(mActivity);
+ mFilteredNumberAsyncQueryHandler = Assert.isNotNull(filteredNumberAsyncQueryHandler);
mContactsPreferences = new ContactsPreferences(mActivity);
@@ -232,7 +237,6 @@ public class CallLogAdapter extends GroupingListAdapter
mCallLogAlertManager =
new CallLogAlertManager(this, LayoutInflater.from(mActivity), alertContainer);
- mEnrichedCallManager = EnrichedCallManager.Accessor.getInstance(activity.getApplication());
}
private void expandViewHolderActions(CallLogListItemViewHolder viewHolder) {
@@ -296,7 +300,7 @@ public class CallLogAdapter extends GroupingListAdapter
}
mContactsPreferences.refreshValue(ContactsPreferences.DISPLAY_ORDER_KEY);
mIsSpamEnabled = Spam.get(mActivity).isSpamEnabled();
- mEnrichedCallManager.registerCapabilitiesListener(this);
+ getEnrichedCallManager().registerCapabilitiesListener(this);
notifyDataSetChanged();
}
@@ -305,11 +309,11 @@ public class CallLogAdapter extends GroupingListAdapter
for (Uri uri : mHiddenItemUris) {
CallLogAsyncTaskUtil.deleteVoicemail(mActivity, uri, null);
}
- mEnrichedCallManager.unregisterCapabilitiesListener(this);
+ getEnrichedCallManager().unregisterCapabilitiesListener(this);
}
public void onStop() {
- mEnrichedCallManager.clearCachedData();
+ getEnrichedCallManager().clearCachedData();
}
public CallLogAlertManager getAlertManager() {
@@ -420,7 +424,9 @@ public class CallLogAdapter extends GroupingListAdapter
}
CallLogListItemViewHolder views = (CallLogListItemViewHolder) viewHolder;
views.isLoaded = false;
- PhoneCallDetails details = createPhoneCallDetails(c, getGroupSize(position), views);
+ int groupSize = getGroupSize(position);
+ CallDetailsEntries callDetailsEntries = createCallDetailsEntries(c, groupSize);
+ PhoneCallDetails details = createPhoneCallDetails(c, groupSize, views);
if (mHiddenRowIds.contains(c.getLong(CallLogQuery.ID))) {
views.callLogEntryView.setVisibility(View.GONE);
views.dayGroupHeader.setVisibility(View.GONE);
@@ -432,11 +438,14 @@ public class CallLogAdapter extends GroupingListAdapter
if (mCurrentlyExpandedRowId == views.rowId) {
views.inflateActionViewStub();
}
- loadAndRender(views, views.rowId, details);
+ loadAndRender(views, views.rowId, details, callDetailsEntries);
}
private void loadAndRender(
- final CallLogListItemViewHolder views, final long rowId, final PhoneCallDetails details) {
+ final CallLogListItemViewHolder views,
+ final long rowId,
+ final PhoneCallDetails details,
+ final CallDetailsEntries callDetailsEntries) {
// Reset block and spam information since this view could be reused which may contain
// outdated data.
views.isSpam = false;
@@ -464,12 +473,33 @@ public class CallLogAdapter extends GroupingListAdapter
&& Spam.get(mActivity)
.checkSpamStatusSynchronous(views.number, views.countryIso);
details.isSpam = views.isSpam;
- if (isCancelled()) {
- return false;
+ }
+ if (isCancelled()) {
+ return false;
+ }
+ setCallDetailsEntriesHistoryResults(
+ PhoneNumberUtils.formatNumberToE164(views.number, views.countryIso),
+ callDetailsEntries);
+ views.setDetailedPhoneDetails(callDetailsEntries);
+ return !isCancelled() && loadData(views, rowId, details);
+ }
+
+ private void setCallDetailsEntriesHistoryResults(
+ @Nullable String number, CallDetailsEntries callDetailsEntries) {
+ if (number == null) {
+ return;
+ }
+ Map<CallDetailsEntry, List<HistoryResult>> mappedResults =
+ getEnrichedCallManager().getAllHistoricalData(number, callDetailsEntries);
+ for (CallDetailsEntry entry : callDetailsEntries.entries) {
+ List<HistoryResult> results = mappedResults.get(entry);
+ if (results != null) {
+ entry.historyResults = mappedResults.get(entry).toArray(new HistoryResult[0]);
+ LogUtil.v(
+ "CallLogAdapter.setCallDetailsEntriesHistoryResults",
+ "mapped %d results",
+ entry.historyResults.length);
}
- return loadData(views, rowId, details);
- } else {
- return loadData(views, rowId, details);
}
}
@@ -499,9 +529,9 @@ public class CallLogAdapter extends GroupingListAdapter
return false;
}
- EnrichedCallCapabilities capabilities = mEnrichedCallManager.getCapabilities(e164Number);
+ EnrichedCallCapabilities capabilities = getEnrichedCallManager().getCapabilities(e164Number);
if (capabilities == null) {
- mEnrichedCallManager.requestCapabilities(e164Number);
+ getEnrichedCallManager().requestCapabilities(e164Number);
return false;
}
return capabilities.supportsCallComposer();
@@ -562,6 +592,27 @@ public class CallLogAdapter extends GroupingListAdapter
return details;
}
+ @MainThread
+ private static CallDetailsEntries createCallDetailsEntries(Cursor cursor, int count) {
+ Assert.isMainThread();
+ int position = cursor.getPosition();
+ CallDetailsEntries entries = new CallDetailsEntries();
+ entries.entries = new CallDetailsEntry[count];
+ for (int i = 0; i < count; i++) {
+ CallDetailsEntry entry = new CallDetailsEntry();
+ entry.callId = cursor.getLong(CallLogQuery.ID);
+ entry.callType = cursor.getInt(CallLogQuery.CALL_TYPE);
+ entry.dataUsage = cursor.getLong(CallLogQuery.DATA_USAGE);
+ entry.date = cursor.getLong(CallLogQuery.DATE);
+ entry.duration = cursor.getLong(CallLogQuery.DURATION);
+ entry.features |= cursor.getInt(CallLogQuery.FEATURES);
+ entries.entries[i] = entry;
+ cursor.moveToNext();
+ }
+ cursor.moveToPosition(position);
+ return entries;
+ }
+
/**
* Load data for call log. Any expensive operation should be put here to avoid blocking main
* thread. Do NOT put any cursor operation here since it's not thread safe.
@@ -907,6 +958,11 @@ public class CallLogAdapter extends GroupingListAdapter
notifyDataSetChanged();
}
+ @NonNull
+ private EnrichedCallManager getEnrichedCallManager() {
+ return EnrichedCallComponent.get(mActivity).getEnrichedCallManager();
+ }
+
/** Interface used to initiate a refresh of the content. */
public interface CallFetcher {
diff --git a/java/com/android/dialer/app/calllog/CallLogAsyncTaskUtil.java b/java/com/android/dialer/app/calllog/CallLogAsyncTaskUtil.java
index b4e6fc5ad..2198626d6 100644
--- a/java/com/android/dialer/app/calllog/CallLogAsyncTaskUtil.java
+++ b/java/com/android/dialer/app/calllog/CallLogAsyncTaskUtil.java
@@ -16,37 +16,22 @@
package com.android.dialer.app.calllog;
-import android.Manifest.permission;
import android.annotation.TargetApi;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
-import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.provider.CallLog;
import android.provider.VoicemailContract.Voicemails;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import android.support.annotation.VisibleForTesting;
-import android.support.v4.content.ContextCompat;
-import android.telecom.PhoneAccountHandle;
import android.text.TextUtils;
-import com.android.contacts.common.GeoUtil;
-import com.android.dialer.app.PhoneCallDetails;
import com.android.dialer.common.AsyncTaskExecutor;
import com.android.dialer.common.AsyncTaskExecutors;
-import com.android.dialer.common.LogUtil;
-import com.android.dialer.phonenumbercache.ContactInfo;
-import com.android.dialer.phonenumbercache.ContactInfoHelper;
-import com.android.dialer.phonenumberutil.PhoneNumberHelper;
-import com.android.dialer.telecom.TelecomUtil;
import com.android.dialer.util.PermissionsUtil;
-import java.util.ArrayList;
-import java.util.Arrays;
+import com.android.voicemail.VoicemailClient;
@TargetApi(VERSION_CODES.M)
public class CallLogAsyncTaskUtil {
@@ -58,166 +43,6 @@ public class CallLogAsyncTaskUtil {
sAsyncTaskExecutor = AsyncTaskExecutors.createThreadPoolExecutor();
}
- public static void getCallDetails(
- @NonNull final Context context,
- @Nullable final CallLogAsyncTaskListener callLogAsyncTaskListener,
- @NonNull final Uri... callUris) {
- if (sAsyncTaskExecutor == null) {
- initTaskExecutor();
- }
-
- sAsyncTaskExecutor.submit(
- Tasks.GET_CALL_DETAILS,
- new AsyncTask<Void, Void, PhoneCallDetails[]>() {
- @Override
- public PhoneCallDetails[] doInBackground(Void... params) {
- if (ContextCompat.checkSelfPermission(context, permission.READ_CALL_LOG)
- != PackageManager.PERMISSION_GRANTED) {
- LogUtil.w("CallLogAsyncTaskUtil.getCallDetails", "missing READ_CALL_LOG permission");
- return null;
- }
- // TODO: All calls correspond to the same person, so make a single lookup.
- final int numCalls = callUris.length;
- PhoneCallDetails[] details = new PhoneCallDetails[numCalls];
- try {
- for (int index = 0; index < numCalls; ++index) {
- details[index] = getPhoneCallDetailsForUri(context, callUris[index]);
- }
- return details;
- } catch (IllegalArgumentException e) {
- // Something went wrong reading in our primary data.
- LogUtil.e(
- "CallLogAsyncTaskUtil.getCallDetails", "invalid URI starting call details", e);
- return null;
- }
- }
-
- @Override
- public void onPostExecute(PhoneCallDetails[] phoneCallDetails) {
- if (callLogAsyncTaskListener != null) {
- callLogAsyncTaskListener.onGetCallDetails(phoneCallDetails);
- }
- }
- });
- }
-
- /** Return the phone call details for a given call log URI. */
- private static PhoneCallDetails getPhoneCallDetailsForUri(
- @NonNull Context context, @NonNull Uri callUri) {
- Cursor cursor =
- context
- .getContentResolver()
- .query(callUri, CallDetailQuery.CALL_LOG_PROJECTION, null, null, null);
-
- try {
- if (cursor == null || !cursor.moveToFirst()) {
- throw new IllegalArgumentException("Cannot find content: " + callUri);
- }
-
- // Read call log.
- final String countryIso = cursor.getString(CallDetailQuery.COUNTRY_ISO_COLUMN_INDEX);
- final String number = cursor.getString(CallDetailQuery.NUMBER_COLUMN_INDEX);
- final String postDialDigits =
- (VERSION.SDK_INT >= VERSION_CODES.N)
- ? cursor.getString(CallDetailQuery.POST_DIAL_DIGITS)
- : "";
- final String viaNumber =
- (VERSION.SDK_INT >= VERSION_CODES.N) ? cursor.getString(CallDetailQuery.VIA_NUMBER) : "";
- final int numberPresentation =
- cursor.getInt(CallDetailQuery.NUMBER_PRESENTATION_COLUMN_INDEX);
-
- final PhoneAccountHandle accountHandle =
- PhoneAccountUtils.getAccount(
- cursor.getString(CallDetailQuery.ACCOUNT_COMPONENT_NAME),
- cursor.getString(CallDetailQuery.ACCOUNT_ID));
-
- // If this is not a regular number, there is no point in looking it up in the contacts.
- ContactInfoHelper contactInfoHelper =
- new ContactInfoHelper(context, GeoUtil.getCurrentCountryIso(context));
- boolean isVoicemail = PhoneNumberHelper.isVoicemailNumber(context, accountHandle, number);
- boolean shouldLookupNumber =
- PhoneNumberHelper.canPlaceCallsTo(number, numberPresentation) && !isVoicemail;
- ContactInfo info = ContactInfo.EMPTY;
-
- if (shouldLookupNumber) {
- ContactInfo lookupInfo = contactInfoHelper.lookupNumber(number, countryIso);
- info = lookupInfo != null ? lookupInfo : ContactInfo.EMPTY;
- }
-
- PhoneCallDetails details = new PhoneCallDetails(number, numberPresentation, postDialDigits);
- details.updateDisplayNumber(context, info.formattedNumber, isVoicemail);
-
- details.viaNumber = viaNumber;
- details.accountHandle = accountHandle;
- details.contactUri = info.lookupUri;
- details.namePrimary = info.name;
- details.nameAlternative = info.nameAlternative;
- details.numberType = info.type;
- details.numberLabel = info.label;
- details.photoUri = info.photoUri;
- details.sourceType = info.sourceType;
- details.objectId = info.objectId;
-
- details.callTypes = new int[] {cursor.getInt(CallDetailQuery.CALL_TYPE_COLUMN_INDEX)};
- details.date = cursor.getLong(CallDetailQuery.DATE_COLUMN_INDEX);
- details.duration = cursor.getLong(CallDetailQuery.DURATION_COLUMN_INDEX);
- details.features = cursor.getInt(CallDetailQuery.FEATURES);
- details.geocode = cursor.getString(CallDetailQuery.GEOCODED_LOCATION_COLUMN_INDEX);
- details.transcription = cursor.getString(CallDetailQuery.TRANSCRIPTION_COLUMN_INDEX);
-
- details.countryIso =
- !TextUtils.isEmpty(countryIso) ? countryIso : GeoUtil.getCurrentCountryIso(context);
-
- if (!cursor.isNull(CallDetailQuery.DATA_USAGE)) {
- details.dataUsage = cursor.getLong(CallDetailQuery.DATA_USAGE);
- }
-
- return details;
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
-
- /**
- * Delete specified calls from the call log.
- *
- * @param context The context.
- * @param callIds String of the callIds to delete from the call log, delimited by commas (",").
- * @param callLogAsyncTaskListener The listener to invoke after the entries have been deleted.
- */
- public static void deleteCalls(
- @NonNull final Context context,
- final String callIds,
- @Nullable final CallLogAsyncTaskListener callLogAsyncTaskListener) {
- if (sAsyncTaskExecutor == null) {
- initTaskExecutor();
- }
-
- sAsyncTaskExecutor.submit(
- Tasks.DELETE_CALL,
- new AsyncTask<Void, Void, Void>() {
- @Override
- public Void doInBackground(Void... params) {
- context
- .getContentResolver()
- .delete(
- TelecomUtil.getCallLogUri(context),
- CallLog.Calls._ID + " IN (" + callIds + ")",
- null);
- return null;
- }
-
- @Override
- public void onPostExecute(Void result) {
- if (callLogAsyncTaskListener != null) {
- callLogAsyncTaskListener.onDeleteCall();
- }
- }
- });
- }
-
public static void markVoicemailAsRead(
@NonNull final Context context, @NonNull final Uri voicemailUri) {
if (sAsyncTaskExecutor == null) {
@@ -235,6 +60,8 @@ public class CallLogAsyncTaskUtil {
.getContentResolver()
.update(voicemailUri, values, Voicemails.IS_READ + " = 0", null);
+ uploadVoicemailLocalChangesToServer(context);
+
Intent intent = new Intent(context, CallLogNotificationsService.class);
intent.setAction(CallLogNotificationsService.ACTION_MARK_NEW_VOICEMAILS_AS_OLD);
context.startService(intent);
@@ -256,7 +83,12 @@ public class CallLogAsyncTaskUtil {
new AsyncTask<Void, Void, Void>() {
@Override
public Void doInBackground(Void... params) {
- context.getContentResolver().delete(voicemailUri, null, null);
+ ContentValues values = new ContentValues();
+ values.put(Voicemails.DELETED, "1");
+ context.getContentResolver().update(voicemailUri, values, null, null);
+ // TODO(b/35440541): check which source package is changed. Don't need
+ // to upload changes on foreign voicemails, they will get a PROVIDER_CHANGED
+ uploadVoicemailLocalChangesToServer(context);
return null;
}
@@ -305,11 +137,6 @@ public class CallLogAsyncTaskUtil {
});
}
- @VisibleForTesting
- public static void resetForTest() {
- sAsyncTaskExecutor = null;
- }
-
/** The enumeration of {@link AsyncTask} objects used in this class. */
public enum Tasks {
DELETE_VOICEMAIL,
@@ -321,56 +148,12 @@ public class CallLogAsyncTaskUtil {
}
public interface CallLogAsyncTaskListener {
-
- void onDeleteCall();
-
void onDeleteVoicemail();
-
- void onGetCallDetails(PhoneCallDetails[] details);
}
- private static final class CallDetailQuery {
-
- public static final String[] CALL_LOG_PROJECTION;
- static final int DATE_COLUMN_INDEX = 0;
- static final int DURATION_COLUMN_INDEX = 1;
- static final int NUMBER_COLUMN_INDEX = 2;
- static final int CALL_TYPE_COLUMN_INDEX = 3;
- static final int COUNTRY_ISO_COLUMN_INDEX = 4;
- static final int GEOCODED_LOCATION_COLUMN_INDEX = 5;
- static final int NUMBER_PRESENTATION_COLUMN_INDEX = 6;
- static final int ACCOUNT_COMPONENT_NAME = 7;
- static final int ACCOUNT_ID = 8;
- static final int FEATURES = 9;
- static final int DATA_USAGE = 10;
- static final int TRANSCRIPTION_COLUMN_INDEX = 11;
- static final int POST_DIAL_DIGITS = 12;
- static final int VIA_NUMBER = 13;
- private static final String[] CALL_LOG_PROJECTION_INTERNAL =
- new String[] {
- CallLog.Calls.DATE,
- CallLog.Calls.DURATION,
- CallLog.Calls.NUMBER,
- CallLog.Calls.TYPE,
- CallLog.Calls.COUNTRY_ISO,
- CallLog.Calls.GEOCODED_LOCATION,
- CallLog.Calls.NUMBER_PRESENTATION,
- CallLog.Calls.PHONE_ACCOUNT_COMPONENT_NAME,
- CallLog.Calls.PHONE_ACCOUNT_ID,
- CallLog.Calls.FEATURES,
- CallLog.Calls.DATA_USAGE,
- CallLog.Calls.TRANSCRIPTION
- };
-
- static {
- ArrayList<String> projectionList = new ArrayList<>();
- projectionList.addAll(Arrays.asList(CALL_LOG_PROJECTION_INTERNAL));
- if (VERSION.SDK_INT >= VERSION_CODES.N) {
- projectionList.add(CallLog.Calls.POST_DIAL_DIGITS);
- projectionList.add(CallLog.Calls.VIA_NUMBER);
- }
- projectionList.trimToSize();
- CALL_LOG_PROJECTION = projectionList.toArray(new String[projectionList.size()]);
- }
+ private static void uploadVoicemailLocalChangesToServer(Context context) {
+ Intent intent = new Intent(VoicemailClient.ACTION_UPLOAD);
+ intent.setPackage(context.getPackageName());
+ context.sendBroadcast(intent);
}
}
diff --git a/java/com/android/dialer/app/calllog/CallLogFragment.java b/java/com/android/dialer/app/calllog/CallLogFragment.java
index 1ae68cd65..4abef3430 100644
--- a/java/com/android/dialer/app/calllog/CallLogFragment.java
+++ b/java/com/android/dialer/app/calllog/CallLogFragment.java
@@ -53,6 +53,7 @@ import com.android.dialer.app.list.ListsFragment.ListsPage;
import com.android.dialer.app.voicemail.VoicemailPlaybackPresenter;
import com.android.dialer.app.widget.EmptyContentView;
import com.android.dialer.app.widget.EmptyContentView.OnEmptyViewActionButtonClickedListener;
+import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler;
import com.android.dialer.common.LogUtil;
import com.android.dialer.database.CallLogQueryHandler;
import com.android.dialer.phonenumbercache.ContactInfoHelper;
@@ -70,9 +71,17 @@ public class CallLogFragment extends Fragment
FragmentCompat.OnRequestPermissionsResultCallback,
CallLogModalAlertManager.Listener {
private static final String KEY_FILTER_TYPE = "filter_type";
+ private static final String KEY_LOG_LIMIT = "log_limit";
+ private static final String KEY_DATE_LIMIT = "date_limit";
+ private static final String KEY_IS_CALL_LOG_ACTIVITY = "is_call_log_activity";
private static final String KEY_HAS_READ_CALL_LOG_PERMISSION = "has_read_call_log_permission";
private static final String KEY_REFRESH_DATA_REQUIRED = "refresh_data_required";
+ // No limit specified for the number of logs to show; use the CallLogQueryHandler's default.
+ private static final int NO_LOG_LIMIT = -1;
+ // No date-based filtering.
+ private static final int NO_DATE_LIMIT = 0;
+
private static final int READ_CALL_LOG_PERMISSION_REQUEST_CODE = 1;
private static final int EVENT_UPDATE_DISPLAY = 1;
@@ -104,8 +113,17 @@ public class CallLogFragment extends Fragment
// Exactly same variable is in Fragment as a package private.
private boolean mMenuVisible = true;
// Default to all calls.
- protected int mCallTypeFilter = CallLogQueryHandler.CALL_TYPE_ALL;
-
+ private int mCallTypeFilter = CallLogQueryHandler.CALL_TYPE_ALL;
+ // Log limit - if no limit is specified, then the default in {@link CallLogQueryHandler}
+ // will be used.
+ private int mLogLimit = NO_LOG_LIMIT;
+ // Date limit (in millis since epoch) - when non-zero, only calls which occurred on or after
+ // the date filter are included. If zero, no date-based filtering occurs.
+ private long mDateLimit = NO_DATE_LIMIT;
+ /*
+ * True if this instance of the CallLogFragment shown in the CallLogActivity.
+ */
+ private boolean mIsCallLogActivity = false;
private final Handler mDisplayUpdateHandler =
new Handler() {
@Override
@@ -121,6 +139,48 @@ public class CallLogFragment extends Fragment
protected CallLogModalAlertManager mModalAlertManager;
private ViewGroup mModalAlertView;
+ public CallLogFragment() {
+ this(CallLogQueryHandler.CALL_TYPE_ALL, NO_LOG_LIMIT);
+ }
+
+ public CallLogFragment(int filterType) {
+ this(filterType, NO_LOG_LIMIT);
+ }
+
+ public CallLogFragment(int filterType, boolean isCallLogActivity) {
+ this(filterType, NO_LOG_LIMIT);
+ mIsCallLogActivity = isCallLogActivity;
+ }
+
+ public CallLogFragment(int filterType, int logLimit) {
+ this(filterType, logLimit, NO_DATE_LIMIT);
+ }
+
+ /**
+ * Creates a call log fragment, filtering to include only calls of the desired type, occurring
+ * after the specified date.
+ *
+ * @param filterType type of calls to include.
+ * @param dateLimit limits results to calls occurring on or after the specified date.
+ */
+ public CallLogFragment(int filterType, long dateLimit) {
+ this(filterType, NO_LOG_LIMIT, dateLimit);
+ }
+
+ /**
+ * Creates a call log fragment, filtering to include only calls of the desired type, occurring
+ * after the specified date. Also provides a means to limit the number of results returned.
+ *
+ * @param filterType type of calls to include.
+ * @param logLimit limits the number of results to return.
+ * @param dateLimit limits results to calls occurring on or after the specified date.
+ */
+ public CallLogFragment(int filterType, int logLimit, long dateLimit) {
+ mCallTypeFilter = filterType;
+ mLogLimit = logLimit;
+ mDateLimit = dateLimit;
+ }
+
@Override
public void onCreate(Bundle state) {
LogUtil.d("CallLogFragment.onCreate", toString());
@@ -128,13 +188,16 @@ public class CallLogFragment extends Fragment
mRefreshDataRequired = true;
if (state != null) {
mCallTypeFilter = state.getInt(KEY_FILTER_TYPE, mCallTypeFilter);
+ mLogLimit = state.getInt(KEY_LOG_LIMIT, mLogLimit);
+ mDateLimit = state.getLong(KEY_DATE_LIMIT, mDateLimit);
+ mIsCallLogActivity = state.getBoolean(KEY_IS_CALL_LOG_ACTIVITY, mIsCallLogActivity);
mHasReadCallLogPermission = state.getBoolean(KEY_HAS_READ_CALL_LOG_PERMISSION, false);
mRefreshDataRequired = state.getBoolean(KEY_REFRESH_DATA_REQUIRED, mRefreshDataRequired);
}
final Activity activity = getActivity();
final ContentResolver resolver = activity.getContentResolver();
- mCallLogQueryHandler = new CallLogQueryHandler(activity, resolver, this);
+ mCallLogQueryHandler = new CallLogQueryHandler(activity, resolver, this, mLogLimit);
mKeyguardManager = (KeyguardManager) activity.getSystemService(Context.KEYGUARD_SERVICE);
resolver.registerContentObserver(CallLog.CONTENT_URI, true, mCallLogObserver);
resolver.registerContentObserver(
@@ -226,7 +289,10 @@ public class CallLogFragment extends Fragment
}
protected void setupData() {
- int activityType = CallLogAdapter.ACTIVITY_TYPE_DIALTACTS;
+ int activityType =
+ mIsCallLogActivity
+ ? CallLogAdapter.ACTIVITY_TYPE_CALL_LOG
+ : CallLogAdapter.ACTIVITY_TYPE_DIALTACTS;
String currentCountryIso = GeoUtil.getCurrentCountryIso(getActivity());
mContactInfoCache =
@@ -244,6 +310,7 @@ public class CallLogFragment extends Fragment
CallLogCache.getCallLogCache(getActivity()),
mContactInfoCache,
getVoicemailPlaybackPresenter(),
+ new FilteredNumberAsyncQueryHandler(getActivity()),
activityType);
mRecyclerView.setAdapter(mAdapter);
fetchCalls();
@@ -324,6 +391,9 @@ public class CallLogFragment extends Fragment
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(KEY_FILTER_TYPE, mCallTypeFilter);
+ outState.putInt(KEY_LOG_LIMIT, mLogLimit);
+ outState.putLong(KEY_DATE_LIMIT, mDateLimit);
+ outState.putBoolean(KEY_IS_CALL_LOG_ACTIVITY, mIsCallLogActivity);
outState.putBoolean(KEY_HAS_READ_CALL_LOG_PERMISSION, mHasReadCallLogPermission);
outState.putBoolean(KEY_REFRESH_DATA_REQUIRED, mRefreshDataRequired);
@@ -334,8 +404,10 @@ public class CallLogFragment extends Fragment
@Override
public void fetchCalls() {
- mCallLogQueryHandler.fetchCalls(mCallTypeFilter);
- ((ListsFragment) getParentFragment()).updateTabUnreadCounts();
+ mCallLogQueryHandler.fetchCalls(mCallTypeFilter, mDateLimit);
+ if (!mIsCallLogActivity) {
+ ((ListsFragment) getParentFragment()).updateTabUnreadCounts();
+ }
}
private void updateEmptyMessage(int filterType) {
@@ -366,7 +438,9 @@ public class CallLogFragment extends Fragment
"Unexpected filter type in CallLogFragment: " + filterType);
}
mEmptyListView.setDescription(messageId);
- if (filterType == CallLogQueryHandler.CALL_TYPE_ALL) {
+ if (mIsCallLogActivity) {
+ mEmptyListView.setActionLabel(EmptyContentView.NO_LABEL);
+ } else if (filterType == CallLogQueryHandler.CALL_TYPE_ALL) {
mEmptyListView.setActionLabel(R.string.call_log_all_empty_action);
}
}
@@ -420,7 +494,7 @@ public class CallLogFragment extends Fragment
if (mKeyguardManager != null
&& !mKeyguardManager.inKeyguardRestrictedInputMode()
&& mCallTypeFilter == Calls.VOICEMAIL_TYPE) {
- CallLogNotificationsHelper.updateVoicemailNotifications(getActivity());
+ CallLogNotificationsQueryHelper.updateVoicemailNotifications(getActivity());
}
}
@@ -434,7 +508,8 @@ public class CallLogFragment extends Fragment
if (!PermissionsUtil.hasPermission(activity, READ_CALL_LOG)) {
FragmentCompat.requestPermissions(
this, new String[] {READ_CALL_LOG}, READ_CALL_LOG_PERMISSION_REQUEST_CODE);
- } else {
+ } else if (!mIsCallLogActivity) {
+ // Show dialpad if we are not in the call log activity.
((HostInterface) activity).showDialpad();
}
}
diff --git a/java/com/android/dialer/app/calllog/CallLogListItemHelper.java b/java/com/android/dialer/app/calllog/CallLogListItemHelper.java
index ea2119c83..a5df8cca1 100644
--- a/java/com/android/dialer/app/calllog/CallLogListItemHelper.java
+++ b/java/com/android/dialer/app/calllog/CallLogListItemHelper.java
@@ -21,18 +21,16 @@ import android.provider.CallLog.Calls;
import android.support.annotation.WorkerThread;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
-import android.util.Log;
-import com.android.dialer.app.PhoneCallDetails;
import com.android.dialer.app.R;
import com.android.dialer.app.calllog.calllogcache.CallLogCache;
+import com.android.dialer.calllogutils.PhoneCallDetails;
import com.android.dialer.common.Assert;
+import com.android.dialer.common.LogUtil;
import com.android.dialer.compat.AppCompatConstants;
/** Helper class to fill in the views of a call log entry. */
/* package */ class CallLogListItemHelper {
- private static final String TAG = "CallLogListItemHelper";
-
/** Helper for populating the details of a phone call. */
private final PhoneCallDetailsHelper mPhoneCallDetailsHelper;
/** Resources to look up strings. */
@@ -105,7 +103,9 @@ import com.android.dialer.compat.AppCompatConstants;
*/
public void setActionContentDescriptions(CallLogListItemViewHolder views) {
if (views.nameOrNumber == null) {
- Log.e(TAG, "setActionContentDescriptions; name or number is null.");
+ LogUtil.e(
+ "CallLogListItemHelper.setActionContentDescriptions",
+ "setActionContentDescriptions; name or number is null.");
}
// Calling expandTemplate with a null parameter will cause a NullPointerException.
@@ -170,7 +170,6 @@ import com.android.dialer.compat.AppCompatConstants;
*
* <p>2 calls. Answered call from John Doe mobile 1 hour ago.
*
- * @param context The application context.
* @param details Details of call.
* @return Return call action description.
*/
diff --git a/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java b/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java
index 6abd36078..8a2d94499 100644
--- a/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java
+++ b/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java
@@ -25,9 +25,11 @@ import android.os.AsyncTask;
import android.provider.CallLog;
import android.provider.CallLog.Calls;
import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.support.annotation.VisibleForTesting;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
import android.telephony.PhoneNumberUtils;
import android.text.BidiFormatter;
import android.text.TextDirectionHeuristics;
@@ -56,7 +58,7 @@ import com.android.dialer.blocking.FilteredNumberCompat;
import com.android.dialer.blocking.FilteredNumbersUtil;
import com.android.dialer.callcomposer.CallComposerActivity;
import com.android.dialer.callcomposer.nano.CallComposerContact;
-import com.android.dialer.common.ConfigProviderBindings;
+import com.android.dialer.calldetails.nano.CallDetailsEntries;
import com.android.dialer.common.LogUtil;
import com.android.dialer.compat.CompatUtils;
import com.android.dialer.logging.Logger;
@@ -78,8 +80,6 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener,
MenuItem.OnMenuItemClickListener,
View.OnCreateContextMenuListener {
- private static final String CONFIG_SHARE_VOICEMAIL_ALLOWED = "share_voicemail_allowed";
-
/** The root view of the call log list item */
public final View rootView;
/** The quick contact badge for the contact. */
@@ -201,6 +201,7 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder
public boolean isAttachedToWindow;
public AsyncTask<Void, Void, ?> asyncTask;
+ private CallDetailsEntries callDetailsEntries;
private CallLogListItemViewHolder(
Context context,
@@ -549,10 +550,6 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder
}
}
- private static boolean isShareVoicemailAllowed(Context context) {
- return ConfigProviderBindings.get(context).getBoolean(CONFIG_SHARE_VOICEMAIL_ALLOWED, true);
- }
-
/**
* Binds text titles, click handlers and intents to the voicemail, details and callback action
* buttons.
@@ -577,13 +574,14 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder
unblockView.setVisibility(View.GONE);
reportNotSpamView.setVisibility(View.GONE);
- if (isShareVoicemailAllowed(mContext)) {
- sendVoicemailButtonView.setVisibility(View.VISIBLE);
- }
voicemailPlaybackView.setVisibility(View.VISIBLE);
Uri uri = Uri.parse(voicemailUri);
mVoicemailPlaybackPresenter.setPlaybackView(
- voicemailPlaybackView, rowId, uri, mVoicemailPrimaryActionButtonClicked);
+ voicemailPlaybackView,
+ rowId,
+ uri,
+ mVoicemailPrimaryActionButtonClicked,
+ sendVoicemailButtonView);
mVoicemailPrimaryActionButtonClicked = false;
CallLogAsyncTaskUtil.markVoicemailAsRead(mContext, uri);
return;
@@ -621,14 +619,14 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder
&& mVoicemailPlaybackPresenter != null
&& !TextUtils.isEmpty(voicemailUri)) {
voicemailPlaybackView.setVisibility(View.VISIBLE);
- if (isShareVoicemailAllowed(mContext)) {
- Logger.get(mContext).logImpression(DialerImpression.Type.VVM_SHARE_VISIBLE);
- sendVoicemailButtonView.setVisibility(View.VISIBLE);
- }
Uri uri = Uri.parse(voicemailUri);
mVoicemailPlaybackPresenter.setPlaybackView(
- voicemailPlaybackView, rowId, uri, mVoicemailPrimaryActionButtonClicked);
+ voicemailPlaybackView,
+ rowId,
+ uri,
+ mVoicemailPrimaryActionButtonClicked,
+ sendVoicemailButtonView);
mVoicemailPrimaryActionButtonClicked = false;
CallLogAsyncTaskUtil.markVoicemailAsRead(mContext, uri);
} else {
@@ -640,7 +638,8 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder
detailsButtonView.setVisibility(View.GONE);
} else {
detailsButtonView.setVisibility(View.VISIBLE);
- detailsButtonView.setTag(IntentProvider.getCallDetailIntentProvider(rowId, callIds, null));
+ detailsButtonView.setTag(
+ IntentProvider.getCallDetailIntentProvider(callDetailsEntries, buildContact()));
}
boolean isBlockedOrSpam = blockId != null || (isSpamFeatureEnabled && isSpam);
@@ -776,6 +775,8 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder
contactType = ContactPhotoManager.TYPE_VOICEMAIL;
} else if (isBusiness) {
contactType = ContactPhotoManager.TYPE_BUSINESS;
+ } else if (numberPresentation == TelecomManager.PRESENTATION_RESTRICTED) {
+ contactType = ContactPhotoManager.TYPE_GENERIC_AVATAR;
}
final String lookupKey =
@@ -854,20 +855,9 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder
} else if (view.getId() == R.id.call_compose_action) {
LogUtil.i("CallLogListItemViewHolder.onClick", "share and call pressed");
Logger.get(mContext).logImpression(DialerImpression.Type.CALL_LOG_SHARE_AND_CALL);
- CallComposerContact contact = new CallComposerContact();
- contact.photoId = info.photoId;
- contact.photoUri = info.photoUri == null ? null : info.photoUri.toString();
- contact.contactUri = info.lookupUri == null ? null : info.lookupUri.toString();
- contact.nameOrNumber = (String) nameOrNumber;
- contact.isBusiness = isBusiness;
- contact.number = number;
- /* second line of contact view. */
- contact.displayNumber = TextUtils.isEmpty(info.name) ? null : displayNumber;
- /* phone number type (e.g. mobile) in second line of contact view */
- contact.numberLabel = numberType;
Activity activity = (Activity) mContext;
activity.startActivityForResult(
- CallComposerActivity.newIntent(activity, contact),
+ CallComposerActivity.newIntent(activity, buildContact()),
DialtactsActivity.ACTIVITY_REQUEST_CODE_CALL_COMPOSE);
} else if (view.getId() == R.id.share_voicemail) {
Logger.get(mContext).logImpression(DialerImpression.Type.VVM_SHARE_PRESSED);
@@ -885,6 +875,21 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder
}
}
+ private CallComposerContact buildContact() {
+ CallComposerContact contact = new CallComposerContact();
+ contact.photoId = info.photoId;
+ contact.photoUri = info.photoUri == null ? null : info.photoUri.toString();
+ contact.contactUri = info.lookupUri == null ? null : info.lookupUri.toString();
+ contact.nameOrNumber = (String) nameOrNumber;
+ contact.isBusiness = isBusiness;
+ contact.number = number;
+ /* second line of contact view. */
+ contact.displayNumber = TextUtils.isEmpty(info.name) ? null : displayNumber;
+ /* phone number type (e.g. mobile) in second line of contact view */
+ contact.numberLabel = numberType;
+ return contact;
+ }
+
private void logCallLogAction(int id) {
if (id == R.id.send_message_action) {
Logger.get(mContext).logImpression(DialerImpression.Type.CALL_LOG_SEND_MESSAGE);
@@ -931,6 +936,15 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder
}
}
+ public void setDetailedPhoneDetails(CallDetailsEntries callDetailsEntries) {
+ this.callDetailsEntries = callDetailsEntries;
+ }
+
+ @VisibleForTesting
+ public CallDetailsEntries getDetailedPhoneDetails() {
+ return callDetailsEntries;
+ }
+
public interface OnClickListener {
void onBlockReportSpam(
diff --git a/java/com/android/dialer/app/calllog/CallLogNotificationsHelper.java b/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java
index 8f664d1a4..f12837e6f 100644
--- a/java/com/android/dialer/app/calllog/CallLogNotificationsHelper.java
+++ b/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java
@@ -18,37 +18,41 @@ package com.android.dialer.app.calllog;
import android.Manifest;
import android.annotation.TargetApi;
+import android.app.NotificationManager;
import android.content.ContentResolver;
import android.content.ContentUris;
+import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build.VERSION_CODES;
import android.provider.CallLog.Calls;
import android.support.annotation.Nullable;
+import android.support.annotation.WorkerThread;
+import android.support.v4.os.UserManagerCompat;
import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
-import android.util.Log;
import com.android.contacts.common.GeoUtil;
import com.android.dialer.app.R;
+import com.android.dialer.calllogutils.PhoneNumberDisplayUtil;
+import com.android.dialer.common.LogUtil;
+import com.android.dialer.notification.GroupedNotificationUtil;
import com.android.dialer.phonenumbercache.ContactInfo;
import com.android.dialer.phonenumbercache.ContactInfoHelper;
-import com.android.dialer.telecom.TelecomUtil;
import com.android.dialer.util.PermissionsUtil;
import java.util.ArrayList;
import java.util.List;
/** Helper class operating on call log notifications. */
-public class CallLogNotificationsHelper {
+public class CallLogNotificationsQueryHelper {
private static final String TAG = "CallLogNotifHelper";
- private static CallLogNotificationsHelper sInstance;
private final Context mContext;
private final NewCallsQuery mNewCallsQuery;
private final ContactInfoHelper mContactInfoHelper;
private final String mCurrentCountryIso;
- CallLogNotificationsHelper(
+ CallLogNotificationsQueryHelper(
Context context,
NewCallsQuery newCallsQuery,
ContactInfoHelper contactInfoHelper,
@@ -59,29 +63,60 @@ public class CallLogNotificationsHelper {
mCurrentCountryIso = countryIso;
}
- /** Returns the singleton instance of the {@link CallLogNotificationsHelper}. */
- public static CallLogNotificationsHelper getInstance(Context context) {
- if (sInstance == null) {
- ContentResolver contentResolver = context.getContentResolver();
- String countryIso = GeoUtil.getCurrentCountryIso(context);
- sInstance =
- new CallLogNotificationsHelper(
- context,
- createNewCallsQuery(context, contentResolver),
- new ContactInfoHelper(context, countryIso),
- countryIso);
- }
- return sInstance;
+ /** Returns an instance of {@link CallLogNotificationsQueryHelper}. */
+ public static CallLogNotificationsQueryHelper getInstance(Context context) {
+ ContentResolver contentResolver = context.getContentResolver();
+ String countryIso = GeoUtil.getCurrentCountryIso(context);
+ return new CallLogNotificationsQueryHelper(
+ context,
+ createNewCallsQuery(context, contentResolver),
+ new ContactInfoHelper(context, countryIso),
+ countryIso);
}
- /** Removes the missed call notifications. */
- public static void removeMissedCallNotifications(Context context) {
- TelecomUtil.cancelMissedCallsNotification(context);
+ /**
+ * Removes the missed call notifications and marks calls as read. If a callUri is provided, only
+ * that call is marked as read.
+ */
+ @WorkerThread
+ public static void removeMissedCallNotifications(Context context, @Nullable Uri callUri) {
+ // Call log is only accessible when unlocked. If that's the case, clear the list of
+ // new missed calls from the call log.
+ if (UserManagerCompat.isUserUnlocked(context) && PermissionsUtil.hasPhonePermissions(context)) {
+ ContentValues values = new ContentValues();
+ values.put(Calls.NEW, 0);
+ values.put(Calls.IS_READ, 1);
+ StringBuilder where = new StringBuilder();
+ where.append(Calls.NEW);
+ where.append(" = 1 AND ");
+ where.append(Calls.TYPE);
+ where.append(" = ?");
+ try {
+ context
+ .getContentResolver()
+ .update(
+ callUri == null ? Calls.CONTENT_URI : callUri,
+ values,
+ where.toString(),
+ new String[] {Integer.toString(Calls.MISSED_TYPE)});
+ } catch (IllegalArgumentException e) {
+ LogUtil.e(
+ "CallLogNotificationsQueryHelper.removeMissedCallNotifications",
+ "contacts provider update command failed",
+ e);
+ }
+ }
+
+ GroupedNotificationUtil.removeNotification(
+ context.getSystemService(NotificationManager.class),
+ callUri != null ? callUri.toString() : null,
+ R.id.notification_missed_call,
+ MissedCallNotifier.NOTIFICATION_TAG);
}
/** Update the voice mail notifications. */
public static void updateVoicemailNotifications(Context context) {
- CallLogNotificationsService.updateVoicemailNotifications(context, null);
+ CallLogNotificationsService.updateVoicemailNotifications(context);
}
/** Create a new instance of {@link NewCallsQuery}. */
@@ -251,7 +286,7 @@ public class CallLogNotificationsHelper {
@TargetApi(VERSION_CODES.M)
public List<NewCall> query(int type) {
if (!PermissionsUtil.hasPermission(mContext, Manifest.permission.READ_CALL_LOG)) {
- Log.w(TAG, "No READ_CALL_LOG permission, returning null for calls lookup.");
+ LogUtil.w(TAG, "No READ_CALL_LOG permission, returning null for calls lookup.");
return null;
}
final String selection = String.format("%s = 1 AND %s = ?", Calls.NEW, Calls.TYPE);
@@ -272,7 +307,7 @@ public class CallLogNotificationsHelper {
}
return newCalls;
} catch (RuntimeException e) {
- Log.w(TAG, "Exception when querying Contacts Provider for calls lookup");
+ LogUtil.w(TAG, "Exception when querying Contacts Provider for calls lookup");
return null;
}
}
diff --git a/java/com/android/dialer/app/calllog/CallLogNotificationsService.java b/java/com/android/dialer/app/calllog/CallLogNotificationsService.java
index 820528126..b0d48eee5 100644
--- a/java/com/android/dialer/app/calllog/CallLogNotificationsService.java
+++ b/java/com/android/dialer/app/calllog/CallLogNotificationsService.java
@@ -20,6 +20,7 @@ import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
+import android.support.annotation.Nullable;
import com.android.dialer.common.LogUtil;
import com.android.dialer.telecom.TelecomUtil;
import com.android.dialer.util.PermissionsUtil;
@@ -44,21 +45,10 @@ public class CallLogNotificationsService extends IntentService {
/** Action to mark all the new voicemails as old. */
public static final String ACTION_MARK_NEW_VOICEMAILS_AS_OLD =
"com.android.dialer.calllog.ACTION_MARK_NEW_VOICEMAILS_AS_OLD";
- /**
- * Action to update voicemail notifications.
- *
- * <p>May include an optional extra {@link #EXTRA_NEW_VOICEMAIL_URI}.
- */
+ /** Action to update voicemail notifications. */
public static final String ACTION_UPDATE_VOICEMAIL_NOTIFICATIONS =
"com.android.dialer.calllog.UPDATE_VOICEMAIL_NOTIFICATIONS";
/**
- * Extra to included with {@link #ACTION_UPDATE_VOICEMAIL_NOTIFICATIONS} to identify the new
- * voicemail that triggered an update.
- *
- * <p>It must be a {@link Uri}.
- */
- public static final String EXTRA_NEW_VOICEMAIL_URI = "NEW_VOICEMAIL_URI";
- /**
* Action to update the missed call notifications.
*
* <p>Includes optional extras {@link #EXTRA_MISSED_CALL_NUMBER} and {@link
@@ -66,9 +56,15 @@ public class CallLogNotificationsService extends IntentService {
*/
public static final String ACTION_UPDATE_MISSED_CALL_NOTIFICATIONS =
"com.android.dialer.calllog.UPDATE_MISSED_CALL_NOTIFICATIONS";
+
/** Action to mark all the new missed calls as old. */
public static final String ACTION_MARK_NEW_MISSED_CALLS_AS_OLD =
"com.android.dialer.calllog.ACTION_MARK_NEW_MISSED_CALLS_AS_OLD";
+
+ /** Action to update missed call notifications with a post call note. */
+ public static final String ACTION_INCOMING_POST_CALL =
+ "com.android.dialer.calllog.INCOMING_POST_CALL";
+
/** Action to call back a missed call. */
public static final String ACTION_CALL_BACK_FROM_MISSED_CALL_NOTIFICATION =
"com.android.dialer.calllog.CALL_BACK_FROM_MISSED_CALL_NOTIFICATION";
@@ -92,6 +88,21 @@ public class CallLogNotificationsService extends IntentService {
*/
public static final String EXTRA_MISSED_CALL_COUNT = "MISSED_CALL_COUNT";
+ /**
+ * Extra to be included with {@link #ACTION_INCOMING_POST_CALL} to represent a post call note.
+ *
+ * <p>It must be a {@link String}
+ */
+ public static final String EXTRA_POST_CALL_NOTE = "POST_CALL_NOTE";
+
+ /**
+ * Extra to be included with {@link #ACTION_INCOMING_POST_CALL} to represent the phone number the
+ * post call note came from.
+ *
+ * <p>It must be a {@link String}
+ */
+ public static final String EXTRA_POST_CALL_NUMBER = "POST_CALL_NUMBER";
+
public static final int UNKNOWN_MISSED_CALL_COUNT = -1;
private VoicemailQueryHandler mVoicemailQueryHandler;
@@ -103,10 +114,8 @@ public class CallLogNotificationsService extends IntentService {
* Updates notifications for any new voicemails.
*
* @param context a valid context.
- * @param voicemailUri The uri pointing to the voicemail to update the notification for. If {@code
- * null}, then notifications for all new voicemails will be updated.
*/
- public static void updateVoicemailNotifications(Context context, Uri voicemailUri) {
+ public static void updateVoicemailNotifications(Context context) {
if (!TelecomUtil.isDefaultDialer(context)) {
LogUtil.i(
"CallLogNotificationsService.updateVoicemailNotifications",
@@ -116,10 +125,6 @@ public class CallLogNotificationsService extends IntentService {
if (TelecomUtil.hasReadWriteVoicemailPermissions(context)) {
Intent serviceIntent = new Intent(context, CallLogNotificationsService.class);
serviceIntent.setAction(CallLogNotificationsService.ACTION_UPDATE_VOICEMAIL_NOTIFICATIONS);
- // If voicemailUri is null, then notifications for all voicemails will be updated.
- if (voicemailUri != null) {
- serviceIntent.putExtra(CallLogNotificationsService.EXTRA_NEW_VOICEMAIL_URI, voicemailUri);
- }
context.startService(serviceIntent);
}
}
@@ -139,9 +144,25 @@ public class CallLogNotificationsService extends IntentService {
context.startService(serviceIntent);
}
- public static void markNewVoicemailsAsOld(Context context) {
+ public static void insertPostCallNote(Context context, String number, String postCallNote) {
+ Intent serviceIntent = new Intent(context, CallLogNotificationsService.class);
+ serviceIntent.setAction(ACTION_INCOMING_POST_CALL);
+ serviceIntent.putExtra(EXTRA_POST_CALL_NUMBER, number);
+ serviceIntent.putExtra(EXTRA_POST_CALL_NOTE, postCallNote);
+ context.startService(serviceIntent);
+ }
+
+ public static void markNewVoicemailsAsOld(Context context, @Nullable Uri voicemailUri) {
Intent serviceIntent = new Intent(context, CallLogNotificationsService.class);
serviceIntent.setAction(CallLogNotificationsService.ACTION_MARK_NEW_VOICEMAILS_AS_OLD);
+ serviceIntent.setData(voicemailUri);
+ context.startService(serviceIntent);
+ }
+
+ public static void markNewMissedCallsAsOld(Context context, @Nullable Uri callUri) {
+ Intent serviceIntent = new Intent(context, CallLogNotificationsService.class);
+ serviceIntent.setAction(ACTION_MARK_NEW_MISSED_CALLS_AS_OLD);
+ serviceIntent.setData(callUri);
context.startService(serviceIntent);
}
@@ -172,11 +193,10 @@ public class CallLogNotificationsService extends IntentService {
if (mVoicemailQueryHandler == null) {
mVoicemailQueryHandler = new VoicemailQueryHandler(this, getContentResolver());
}
- mVoicemailQueryHandler.markNewVoicemailsAsOld();
+ mVoicemailQueryHandler.markNewVoicemailsAsOld(intent.getData());
break;
case ACTION_UPDATE_VOICEMAIL_NOTIFICATIONS:
- Uri voicemailUri = intent.getParcelableExtra(EXTRA_NEW_VOICEMAIL_URI);
- DefaultVoicemailNotifier.getInstance(this).updateNotification(voicemailUri);
+ DefaultVoicemailNotifier.getInstance(this).updateNotification();
break;
case ACTION_UPDATE_MISSED_CALL_NOTIFICATIONS:
int count = intent.getIntExtra(EXTRA_MISSED_CALL_COUNT, UNKNOWN_MISSED_CALL_COUNT);
@@ -184,16 +204,24 @@ public class CallLogNotificationsService extends IntentService {
MissedCallNotifier.getInstance(this).updateMissedCallNotification(count, number);
updateBadgeCount(this, count);
break;
+ case ACTION_INCOMING_POST_CALL:
+ String note = intent.getStringExtra(EXTRA_POST_CALL_NOTE);
+ String phoneNumber = intent.getStringExtra(EXTRA_POST_CALL_NUMBER);
+ MissedCallNotifier.getInstance(this).insertPostCallNotification(phoneNumber, note);
+ break;
case ACTION_MARK_NEW_MISSED_CALLS_AS_OLD:
- CallLogNotificationsHelper.removeMissedCallNotifications(this);
+ CallLogNotificationsQueryHelper.removeMissedCallNotifications(this, intent.getData());
+ TelecomUtil.cancelMissedCallsNotification(this);
break;
case ACTION_CALL_BACK_FROM_MISSED_CALL_NOTIFICATION:
MissedCallNotifier.getInstance(this)
- .callBackFromMissedCall(intent.getStringExtra(EXTRA_MISSED_CALL_NUMBER));
+ .callBackFromMissedCall(
+ intent.getStringExtra(EXTRA_MISSED_CALL_NUMBER), intent.getData());
break;
case ACTION_SEND_SMS_FROM_MISSED_CALL_NOTIFICATION:
MissedCallNotifier.getInstance(this)
- .sendSmsFromMissedCall(intent.getStringExtra(EXTRA_MISSED_CALL_NUMBER));
+ .sendSmsFromMissedCall(
+ intent.getStringExtra(EXTRA_MISSED_CALL_NUMBER), intent.getData());
break;
default:
LogUtil.d("CallLogNotificationsService.onHandleIntent", "could not handle: " + intent);
diff --git a/java/com/android/dialer/app/calllog/CallLogReceiver.java b/java/com/android/dialer/app/calllog/CallLogReceiver.java
index a781b0887..8fd1502bc 100644
--- a/java/com/android/dialer/app/calllog/CallLogReceiver.java
+++ b/java/com/android/dialer/app/calllog/CallLogReceiver.java
@@ -38,9 +38,9 @@ public class CallLogReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
if (VoicemailContract.ACTION_NEW_VOICEMAIL.equals(intent.getAction())) {
checkVoicemailStatus(context);
- CallLogNotificationsService.updateVoicemailNotifications(context, intent.getData());
+ CallLogNotificationsService.updateVoicemailNotifications(context);
} else if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
- CallLogNotificationsService.updateVoicemailNotifications(context, null);
+ CallLogNotificationsService.updateVoicemailNotifications(context);
} else {
LogUtil.w("CallLogReceiver.onReceive", "could not handle: " + intent);
}
diff --git a/java/com/android/dialer/app/calllog/CallTypeHelper.java b/java/com/android/dialer/app/calllog/CallTypeHelper.java
deleted file mode 100644
index f3c27a1ac..000000000
--- a/java/com/android/dialer/app/calllog/CallTypeHelper.java
+++ /dev/null
@@ -1,136 +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.app.calllog;
-
-import android.content.res.Resources;
-import com.android.dialer.app.R;
-import com.android.dialer.compat.AppCompatConstants;
-
-/** Helper class to perform operations related to call types. */
-public class CallTypeHelper {
-
- /** Name used to identify incoming calls. */
- private final CharSequence mIncomingName;
- /** Name used to identify incoming calls which were transferred to another device. */
- private final CharSequence mIncomingPulledName;
- /** Name used to identify outgoing calls. */
- private final CharSequence mOutgoingName;
- /** Name used to identify outgoing calls which were transferred to another device. */
- private final CharSequence mOutgoingPulledName;
- /** Name used to identify missed calls. */
- private final CharSequence mMissedName;
- /** Name used to identify incoming video calls. */
- private final CharSequence mIncomingVideoName;
- /** Name used to identify incoming video calls which were transferred to another device. */
- private final CharSequence mIncomingVideoPulledName;
- /** Name used to identify outgoing video calls. */
- private final CharSequence mOutgoingVideoName;
- /** Name used to identify outgoing video calls which were transferred to another device. */
- private final CharSequence mOutgoingVideoPulledName;
- /** Name used to identify missed video calls. */
- private final CharSequence mMissedVideoName;
- /** Name used to identify voicemail calls. */
- private final CharSequence mVoicemailName;
- /** Name used to identify rejected calls. */
- private final CharSequence mRejectedName;
- /** Name used to identify blocked calls. */
- private final CharSequence mBlockedName;
- /** Name used to identify calls which were answered on another device. */
- private final CharSequence mAnsweredElsewhereName;
-
- public CallTypeHelper(Resources resources) {
- // Cache these values so that we do not need to look them up each time.
- mIncomingName = resources.getString(R.string.type_incoming);
- mIncomingPulledName = resources.getString(R.string.type_incoming_pulled);
- mOutgoingName = resources.getString(R.string.type_outgoing);
- mOutgoingPulledName = resources.getString(R.string.type_outgoing_pulled);
- mMissedName = resources.getString(R.string.type_missed);
- mIncomingVideoName = resources.getString(R.string.type_incoming_video);
- mIncomingVideoPulledName = resources.getString(R.string.type_incoming_video_pulled);
- mOutgoingVideoName = resources.getString(R.string.type_outgoing_video);
- mOutgoingVideoPulledName = resources.getString(R.string.type_outgoing_video_pulled);
- mMissedVideoName = resources.getString(R.string.type_missed_video);
- mVoicemailName = resources.getString(R.string.type_voicemail);
- mRejectedName = resources.getString(R.string.type_rejected);
- mBlockedName = resources.getString(R.string.type_blocked);
- mAnsweredElsewhereName = resources.getString(R.string.type_answered_elsewhere);
- }
-
- public static boolean isMissedCallType(int callType) {
- return (callType != AppCompatConstants.CALLS_INCOMING_TYPE
- && callType != AppCompatConstants.CALLS_OUTGOING_TYPE
- && callType != AppCompatConstants.CALLS_VOICEMAIL_TYPE
- && callType != AppCompatConstants.CALLS_ANSWERED_EXTERNALLY_TYPE);
- }
-
- /** Returns the text used to represent the given call type. */
- public CharSequence getCallTypeText(int callType, boolean isVideoCall, boolean isPulledCall) {
- switch (callType) {
- case AppCompatConstants.CALLS_INCOMING_TYPE:
- if (isVideoCall) {
- if (isPulledCall) {
- return mIncomingVideoPulledName;
- } else {
- return mIncomingVideoName;
- }
- } else {
- if (isPulledCall) {
- return mIncomingPulledName;
- } else {
- return mIncomingName;
- }
- }
-
- case AppCompatConstants.CALLS_OUTGOING_TYPE:
- if (isVideoCall) {
- if (isPulledCall) {
- return mOutgoingVideoPulledName;
- } else {
- return mOutgoingVideoName;
- }
- } else {
- if (isPulledCall) {
- return mOutgoingPulledName;
- } else {
- return mOutgoingName;
- }
- }
-
- case AppCompatConstants.CALLS_MISSED_TYPE:
- if (isVideoCall) {
- return mMissedVideoName;
- } else {
- return mMissedName;
- }
-
- case AppCompatConstants.CALLS_VOICEMAIL_TYPE:
- return mVoicemailName;
-
- case AppCompatConstants.CALLS_REJECTED_TYPE:
- return mRejectedName;
-
- case AppCompatConstants.CALLS_BLOCKED_TYPE:
- return mBlockedName;
-
- case AppCompatConstants.CALLS_ANSWERED_EXTERNALLY_TYPE:
- return mAnsweredElsewhereName;
-
- default:
- return mMissedName;
- }
- }
-}
diff --git a/java/com/android/dialer/app/calllog/CallTypeIconsView.java b/java/com/android/dialer/app/calllog/CallTypeIconsView.java
deleted file mode 100644
index cd5c5460c..000000000
--- a/java/com/android/dialer/app/calllog/CallTypeIconsView.java
+++ /dev/null
@@ -1,221 +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.app.calllog;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.PorterDuff;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.view.View;
-import com.android.contacts.common.util.BitmapUtil;
-import com.android.dialer.app.R;
-import com.android.dialer.compat.AppCompatConstants;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * View that draws one or more symbols for different types of calls (missed calls, outgoing etc).
- * The symbols are set up horizontally. As this view doesn't create subviews, it is better suited
- * for ListView-recycling that a regular LinearLayout using ImageViews.
- */
-public class CallTypeIconsView extends View {
-
- private static Resources sResources;
- private List<Integer> mCallTypes = new ArrayList<>(3);
- private boolean mShowVideo = false;
- private int mWidth;
- private int mHeight;
-
- public CallTypeIconsView(Context context) {
- this(context, null);
- }
-
- public CallTypeIconsView(Context context, AttributeSet attrs) {
- super(context, attrs);
- if (sResources == null) {
- sResources = new Resources(context);
- }
- }
-
- public void clear() {
- mCallTypes.clear();
- mWidth = 0;
- mHeight = 0;
- invalidate();
- }
-
- public void add(int callType) {
- mCallTypes.add(callType);
-
- final Drawable drawable = getCallTypeDrawable(callType);
- mWidth += drawable.getIntrinsicWidth() + sResources.iconMargin;
- mHeight = Math.max(mHeight, drawable.getIntrinsicHeight());
- invalidate();
- }
-
- /**
- * Determines whether the video call icon will be shown.
- *
- * @param showVideo True where the video icon should be shown.
- */
- public void setShowVideo(boolean showVideo) {
- mShowVideo = showVideo;
- if (showVideo) {
- mWidth += sResources.videoCall.getIntrinsicWidth();
- mHeight = Math.max(mHeight, sResources.videoCall.getIntrinsicHeight());
- invalidate();
- }
- }
-
- /**
- * Determines if the video icon should be shown.
- *
- * @return True if the video icon should be shown.
- */
- public boolean isVideoShown() {
- return mShowVideo;
- }
-
- public int getCount() {
- return mCallTypes.size();
- }
-
- public int getCallType(int index) {
- return mCallTypes.get(index);
- }
-
- private Drawable getCallTypeDrawable(int callType) {
- switch (callType) {
- case AppCompatConstants.CALLS_INCOMING_TYPE:
- case AppCompatConstants.CALLS_ANSWERED_EXTERNALLY_TYPE:
- return sResources.incoming;
- case AppCompatConstants.CALLS_OUTGOING_TYPE:
- return sResources.outgoing;
- case AppCompatConstants.CALLS_MISSED_TYPE:
- return sResources.missed;
- case AppCompatConstants.CALLS_VOICEMAIL_TYPE:
- return sResources.voicemail;
- case AppCompatConstants.CALLS_BLOCKED_TYPE:
- return sResources.blocked;
- default:
- // It is possible for users to end up with calls with unknown call types in their
- // call history, possibly due to 3rd party call log implementations (e.g. to
- // distinguish between rejected and missed calls). Instead of crashing, just
- // assume that all unknown call types are missed calls.
- return sResources.missed;
- }
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- setMeasuredDimension(mWidth, mHeight);
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- int left = 0;
- for (Integer callType : mCallTypes) {
- final Drawable drawable = getCallTypeDrawable(callType);
- final int right = left + drawable.getIntrinsicWidth();
- drawable.setBounds(left, 0, right, drawable.getIntrinsicHeight());
- drawable.draw(canvas);
- left = right + sResources.iconMargin;
- }
-
- // If showing the video call icon, draw it scaled appropriately.
- if (mShowVideo) {
- final Drawable drawable = sResources.videoCall;
- final int right = left + sResources.videoCall.getIntrinsicWidth();
- drawable.setBounds(left, 0, right, sResources.videoCall.getIntrinsicHeight());
- drawable.draw(canvas);
- }
- }
-
- private static class Resources {
-
- // Drawable representing an incoming answered call.
- public final Drawable incoming;
-
- // Drawable respresenting an outgoing call.
- public final Drawable outgoing;
-
- // Drawable representing an incoming missed call.
- public final Drawable missed;
-
- // Drawable representing a voicemail.
- public final Drawable voicemail;
-
- // Drawable representing a blocked call.
- public final Drawable blocked;
-
- // Drawable repesenting a video call.
- public final Drawable videoCall;
-
- /** The margin to use for icons. */
- public final int iconMargin;
-
- /**
- * Configures the call icon drawables. A single white call arrow which points down and left is
- * used as a basis for all of the call arrow icons, applying rotation and colors as needed.
- *
- * @param context The current context.
- */
- public Resources(Context context) {
- final android.content.res.Resources r = context.getResources();
-
- incoming = r.getDrawable(R.drawable.ic_call_arrow);
- incoming.setColorFilter(r.getColor(R.color.answered_call), PorterDuff.Mode.MULTIPLY);
-
- // Create a rotated instance of the call arrow for outgoing calls.
- outgoing = BitmapUtil.getRotatedDrawable(r, R.drawable.ic_call_arrow, 180f);
- outgoing.setColorFilter(r.getColor(R.color.answered_call), PorterDuff.Mode.MULTIPLY);
-
- // Need to make a copy of the arrow drawable, otherwise the same instance colored
- // above will be recolored here.
- missed = r.getDrawable(R.drawable.ic_call_arrow).mutate();
- missed.setColorFilter(r.getColor(R.color.missed_call), PorterDuff.Mode.MULTIPLY);
-
- voicemail = r.getDrawable(R.drawable.quantum_ic_voicemail_white_18);
- voicemail.setColorFilter(
- r.getColor(R.color.dialer_secondary_text_color), PorterDuff.Mode.MULTIPLY);
-
- blocked = getScaledBitmap(context, R.drawable.ic_block_24dp);
- blocked.setColorFilter(r.getColor(R.color.blocked_call), PorterDuff.Mode.MULTIPLY);
-
- videoCall = getScaledBitmap(context, R.drawable.quantum_ic_videocam_white_24);
- videoCall.setColorFilter(
- r.getColor(R.color.dialer_secondary_text_color), PorterDuff.Mode.MULTIPLY);
-
- iconMargin = r.getDimensionPixelSize(R.dimen.call_log_icon_margin);
- }
-
- // Gets the icon, scaled to the height of the call type icons. This helps display all the
- // icons to be the same height, while preserving their width aspect ratio.
- private Drawable getScaledBitmap(Context context, int resourceId) {
- Bitmap icon = BitmapFactory.decodeResource(context.getResources(), resourceId);
- int scaledHeight = context.getResources().getDimensionPixelSize(R.dimen.call_type_icon_size);
- int scaledWidth =
- (int) ((float) icon.getWidth() * ((float) scaledHeight / (float) icon.getHeight()));
- Bitmap scaledIcon = Bitmap.createScaledBitmap(icon, scaledWidth, scaledHeight, false);
- return new BitmapDrawable(context.getResources(), scaledIcon);
- }
- }
-}
diff --git a/java/com/android/dialer/app/calllog/DefaultVoicemailNotifier.java b/java/com/android/dialer/app/calllog/DefaultVoicemailNotifier.java
index 651a0ccb8..cc1dc4f20 100644
--- a/java/com/android/dialer/app/calllog/DefaultVoicemailNotifier.java
+++ b/java/com/android/dialer/app/calllog/DefaultVoicemailNotifier.java
@@ -19,31 +19,33 @@ package com.android.dialer.app.calllog;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
+import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
import android.support.v4.util.Pair;
-import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.ArrayMap;
-import android.util.Log;
import com.android.contacts.common.compat.TelephonyManagerCompat;
import com.android.contacts.common.util.ContactDisplayUtils;
import com.android.dialer.app.DialtactsActivity;
import com.android.dialer.app.R;
-import com.android.dialer.app.calllog.CallLogNotificationsHelper.NewCall;
+import com.android.dialer.app.calllog.CallLogNotificationsQueryHelper.NewCall;
+import com.android.dialer.app.contactinfo.ContactPhotoLoader;
import com.android.dialer.app.list.ListsFragment;
import com.android.dialer.blocking.FilteredNumbersUtil;
-import com.android.dialer.telecom.TelecomUtil;
+import com.android.dialer.common.LogUtil;
+import com.android.dialer.notification.NotificationChannelManager;
+import com.android.dialer.notification.NotificationChannelManager.Channel;
+import com.android.dialer.phonenumbercache.ContactInfo;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -54,26 +56,23 @@ public class DefaultVoicemailNotifier {
public static final String TAG = "VoicemailNotifier";
/** The tag used to identify notifications from this class. */
- private static final String NOTIFICATION_TAG = "DefaultVoicemailNotifier";
+ static final String NOTIFICATION_TAG = "DefaultVoicemailNotifier";
/** The identifier of the notification of new voicemails. */
- private static final int NOTIFICATION_ID = 1;
+ private static final int NOTIFICATION_ID = R.id.notification_voicemail;
- /** The singleton instance of {@link DefaultVoicemailNotifier}. */
- private static DefaultVoicemailNotifier sInstance;
+ private final Context context;
+ private final CallLogNotificationsQueryHelper queryHelper;
- private final Context mContext;
-
- private DefaultVoicemailNotifier(Context context) {
- mContext = context;
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ DefaultVoicemailNotifier(Context context, CallLogNotificationsQueryHelper queryHelper) {
+ this.context = context;
+ this.queryHelper = queryHelper;
}
- /** Returns the singleton instance of the {@link DefaultVoicemailNotifier}. */
+ /** Returns an instance of {@link DefaultVoicemailNotifier}. */
public static DefaultVoicemailNotifier getInstance(Context context) {
- if (sInstance == null) {
- ContentResolver contentResolver = context.getContentResolver();
- sInstance = new DefaultVoicemailNotifier(context);
- }
- return sInstance;
+ return new DefaultVoicemailNotifier(
+ context, CallLogNotificationsQueryHelper.getInstance(context));
}
/**
@@ -84,34 +83,23 @@ public class DefaultVoicemailNotifier {
*
* <p>It is not safe to call this method from the main thread.
*/
- public void updateNotification(Uri newCallUri) {
+ public void updateNotification() {
// Lookup the list of new voicemails to include in the notification.
- // TODO: Move this into a service, to avoid holding the receiver up.
- final List<NewCall> newCalls =
- CallLogNotificationsHelper.getInstance(mContext).getNewVoicemails();
+ final List<NewCall> newCalls = queryHelper.getNewVoicemails();
if (newCalls == null) {
// Query failed, just return.
return;
}
- if (newCalls.isEmpty()) {
- // No voicemails to notify about: clear the notification.
- getNotificationManager().cancel(NOTIFICATION_TAG, NOTIFICATION_ID);
- return;
- }
-
- Resources resources = mContext.getResources();
+ Resources resources = context.getResources();
// This represents a list of names to include in the notification.
String callers = null;
// Maps each number into a name: if a number is in the map, it has already left a more
// recent voicemail.
- final Map<String, String> names = new ArrayMap<>();
-
- // Determine the call corresponding to the new voicemail we have to notify about.
- NewCall callToNotify = null;
+ final Map<String, ContactInfo> contactInfos = new ArrayMap<>();
// Iterate over the new voicemails to determine all the information above.
Iterator<NewCall> itr = newCalls.iterator();
@@ -120,95 +108,64 @@ public class DefaultVoicemailNotifier {
// Skip notifying for numbers which are blocked.
if (FilteredNumbersUtil.shouldBlockVoicemail(
- mContext, newCall.number, newCall.countryIso, newCall.dateMs)) {
+ context, newCall.number, newCall.countryIso, newCall.dateMs)) {
itr.remove();
// Delete the voicemail.
- mContext.getContentResolver().delete(newCall.voicemailUri, null, null);
+ context.getContentResolver().delete(newCall.voicemailUri, null, null);
continue;
}
// Check if we already know the name associated with this number.
- String name = names.get(newCall.number);
- if (name == null) {
- name =
- CallLogNotificationsHelper.getInstance(mContext)
- .getName(newCall.number, newCall.numberPresentation, newCall.countryIso);
- names.put(newCall.number, name);
+ ContactInfo contactInfo = contactInfos.get(newCall.number);
+ if (contactInfo == null) {
+ contactInfo =
+ queryHelper.getContactInfo(
+ newCall.number, newCall.numberPresentation, newCall.countryIso);
+ contactInfos.put(newCall.number, contactInfo);
// This is a new caller. Add it to the back of the list of callers.
if (TextUtils.isEmpty(callers)) {
- callers = name;
+ callers = contactInfo.name;
} else {
callers =
- resources.getString(R.string.notification_voicemail_callers_list, callers, name);
+ resources.getString(
+ R.string.notification_voicemail_callers_list, callers, contactInfo.name);
}
}
- // Check if this is the new call we need to notify about.
- if (newCallUri != null
- && newCall.voicemailUri != null
- && ContentUris.parseId(newCallUri) == ContentUris.parseId(newCall.voicemailUri)) {
- callToNotify = newCall;
- }
}
- // All the potential new voicemails have been removed, e.g. if they were spam.
if (newCalls.isEmpty()) {
+ // No voicemails to notify about: clear the notification.
+ CallLogNotificationsService.markNewVoicemailsAsOld(context, null);
return;
}
- // If there is only one voicemail, set its transcription as the "long text".
- String transcription = null;
- if (newCalls.size() == 1) {
- transcription = newCalls.get(0).transcription;
- }
-
- if (newCallUri != null && callToNotify == null) {
- Log.e(TAG, "The new call could not be found in the call log: " + newCallUri);
- }
-
- // Determine the title of the notification and the icon for it.
- final String title =
- resources.getQuantityString(
- R.plurals.notification_voicemail_title, newCalls.size(), newCalls.size());
- // TODO: Use the photo of contact if all calls are from the same person.
- final int icon = android.R.drawable.stat_notify_voicemail;
-
- Pair<Uri, Integer> info = getNotificationInfo(callToNotify);
-
- Notification.Builder notificationBuilder =
- new Notification.Builder(mContext)
- .setSmallIcon(icon)
- .setContentTitle(title)
+ Notification.Builder groupSummary =
+ createNotificationBuilder()
+ .setContentTitle(
+ resources.getQuantityString(
+ R.plurals.notification_voicemail_title, newCalls.size(), newCalls.size()))
.setContentText(callers)
- .setColor(resources.getColor(R.color.dialer_theme_color))
- .setSound(info.first)
- .setDefaults(info.second)
- .setDeleteIntent(createMarkNewVoicemailsAsOldIntent())
- .setAutoCancel(true);
-
- if (!TextUtils.isEmpty(transcription)) {
- notificationBuilder.setStyle(new Notification.BigTextStyle().bigText(transcription));
+ .setDeleteIntent(createMarkNewVoicemailsAsOldIntent(null))
+ .setGroupSummary(true)
+ .setContentIntent(newVoicemailIntent(null));
+
+ NotificationChannelManager.applyChannel(
+ groupSummary,
+ context,
+ Channel.VOICEMAIL,
+ PhoneAccountHandles.getAccount(context, newCalls.get(0)));
+
+ LogUtil.i(TAG, "Creating voicemail notification");
+ getNotificationManager().notify(NOTIFICATION_TAG, NOTIFICATION_ID, groupSummary.build());
+
+ for (NewCall voicemail : newCalls) {
+ getNotificationManager()
+ .notify(
+ voicemail.voicemailUri.toString(),
+ NOTIFICATION_ID,
+ createNotificationForVoicemail(voicemail, contactInfos));
}
-
- // Determine the intent to fire when the notification is clicked on.
- final Intent contentIntent;
- // Open the call log.
- contentIntent = DialtactsActivity.getShowTabIntent(mContext, ListsFragment.TAB_INDEX_VOICEMAIL);
- contentIntent.putExtra(DialtactsActivity.EXTRA_CLEAR_NEW_VOICEMAILS, true);
- notificationBuilder.setContentIntent(
- PendingIntent.getActivity(mContext, 0, contentIntent, PendingIntent.FLAG_UPDATE_CURRENT));
-
- // The text to show in the ticker, describing the new event.
- if (callToNotify != null) {
- CharSequence msg =
- ContactDisplayUtils.getTtsSpannedPhoneNumber(
- resources,
- R.string.notification_new_voicemail_ticker,
- names.get(callToNotify.number));
- notificationBuilder.setTicker(msg);
- }
- Log.i(TAG, "Creating voicemail notification");
- getNotificationManager().notify(NOTIFICATION_TAG, NOTIFICATION_ID, notificationBuilder.build());
}
/**
@@ -216,30 +173,15 @@ public class DefaultVoicemailNotifier {
* for the given call.
*/
private Pair<Uri, Integer> getNotificationInfo(@Nullable NewCall callToNotify) {
- Log.v(TAG, "getNotificationInfo");
+ LogUtil.v(TAG, "getNotificationInfo");
if (callToNotify == null) {
- Log.i(TAG, "callToNotify == null");
+ LogUtil.i(TAG, "callToNotify == null");
return new Pair<>(null, 0);
}
- PhoneAccountHandle accountHandle;
- if (callToNotify.accountComponentName == null || callToNotify.accountId == null) {
- Log.v(TAG, "accountComponentName == null || callToNotify.accountId == null");
- accountHandle = TelecomUtil.getDefaultOutgoingPhoneAccount(mContext, PhoneAccount.SCHEME_TEL);
- if (accountHandle == null) {
- Log.i(TAG, "No default phone account found, using default notification ringtone");
- return new Pair<>(null, Notification.DEFAULT_ALL);
- }
-
- } else {
- accountHandle =
- new PhoneAccountHandle(
- ComponentName.unflattenFromString(callToNotify.accountComponentName),
- callToNotify.accountId);
- }
- if (accountHandle.getComponentName() != null) {
- Log.v(TAG, "PhoneAccountHandle.ComponentInfo:" + accountHandle.getComponentName());
- } else {
- Log.i(TAG, "PhoneAccountHandle.ComponentInfo: null");
+ PhoneAccountHandle accountHandle = PhoneAccountHandles.getAccount(context, callToNotify);
+ if (accountHandle == null) {
+ LogUtil.i(TAG, "No default phone account found, using default notification ringtone");
+ return new Pair<>(null, Notification.DEFAULT_ALL);
}
return new Pair<>(
TelephonyManagerCompat.getVoicemailRingtoneUri(getTelephonyManager(), accountHandle),
@@ -257,17 +199,79 @@ public class DefaultVoicemailNotifier {
}
/** Creates a pending intent that marks all new voicemails as old. */
- private PendingIntent createMarkNewVoicemailsAsOldIntent() {
- Intent intent = new Intent(mContext, CallLogNotificationsService.class);
+ private PendingIntent createMarkNewVoicemailsAsOldIntent(@Nullable Uri voicemailUri) {
+ Intent intent = new Intent(context, CallLogNotificationsService.class);
intent.setAction(CallLogNotificationsService.ACTION_MARK_NEW_VOICEMAILS_AS_OLD);
- return PendingIntent.getService(mContext, 0, intent, 0);
+ intent.setData(voicemailUri);
+ return PendingIntent.getService(context, 0, intent, 0);
}
private NotificationManager getNotificationManager() {
- return (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
}
private TelephonyManager getTelephonyManager() {
- return (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ return (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+ }
+
+ private Notification createNotificationForVoicemail(
+ @NonNull NewCall voicemail, @NonNull Map<String, ContactInfo> contactInfos) {
+ Pair<Uri, Integer> notificationInfo = getNotificationInfo(voicemail);
+ ContactInfo contactInfo = contactInfos.get(voicemail.number);
+
+ Notification.Builder notificationBuilder =
+ createNotificationBuilder()
+ .setContentTitle(
+ context
+ .getResources()
+ .getQuantityString(R.plurals.notification_voicemail_title, 1, 1))
+ .setContentText(
+ ContactDisplayUtils.getTtsSpannedPhoneNumber(
+ context.getResources(),
+ R.string.notification_new_voicemail_ticker,
+ contactInfo.name))
+ .setWhen(voicemail.dateMs)
+ .setSound(notificationInfo.first)
+ .setDefaults(notificationInfo.second)
+ .setDeleteIntent(createMarkNewVoicemailsAsOldIntent(voicemail.voicemailUri));
+
+ NotificationChannelManager.applyChannel(
+ notificationBuilder,
+ context,
+ Channel.VOICEMAIL,
+ PhoneAccountHandles.getAccount(context, voicemail));
+
+ ContactPhotoLoader loader = new ContactPhotoLoader(context, contactInfo);
+ Bitmap photoIcon = loader.loadPhotoIcon();
+ if (photoIcon != null) {
+ notificationBuilder.setLargeIcon(photoIcon);
+ }
+
+ if (!TextUtils.isEmpty(voicemail.transcription)) {
+ notificationBuilder.setStyle(
+ new Notification.BigTextStyle().bigText(voicemail.transcription));
+ }
+ notificationBuilder.setContentIntent(newVoicemailIntent(voicemail));
+
+ return notificationBuilder.build();
+ }
+
+ private Notification.Builder createNotificationBuilder() {
+ return new Notification.Builder(context)
+ .setSmallIcon(android.R.drawable.stat_notify_voicemail)
+ .setColor(context.getColor(R.color.dialer_theme_color))
+ .setGroup(NOTIFICATION_TAG)
+ .setOnlyAlertOnce(true)
+ .setAutoCancel(true);
+ }
+
+ private PendingIntent newVoicemailIntent(@Nullable NewCall voicemail) {
+ Intent intent = DialtactsActivity.getShowTabIntent(context, ListsFragment.TAB_INDEX_VOICEMAIL);
+ // TODO (b/35486204): scroll to this voicemail
+ if (voicemail != null) {
+ intent.setData(voicemail.voicemailUri);
+ }
+ intent.putExtra(DialtactsActivity.EXTRA_CLEAR_NEW_VOICEMAILS, true);
+ return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
}
diff --git a/java/com/android/dialer/app/calllog/IntentProvider.java b/java/com/android/dialer/app/calllog/IntentProvider.java
index 879ac353d..c53e3ec5e 100644
--- a/java/com/android/dialer/app/calllog/IntentProvider.java
+++ b/java/com/android/dialer/app/calllog/IntentProvider.java
@@ -16,7 +16,6 @@
package com.android.dialer.app.calllog;
-import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
@@ -25,10 +24,11 @@ import android.provider.ContactsContract;
import android.telecom.PhoneAccountHandle;
import com.android.contacts.common.model.Contact;
import com.android.contacts.common.model.ContactLoader;
-import com.android.dialer.app.CallDetailActivity;
+import com.android.dialer.callcomposer.nano.CallComposerContact;
+import com.android.dialer.calldetails.CallDetailsActivity;
+import com.android.dialer.calldetails.nano.CallDetailsEntries;
import com.android.dialer.callintent.CallIntentBuilder;
import com.android.dialer.callintent.nano.CallInitiationType;
-import com.android.dialer.telecom.TelecomUtil;
import com.android.dialer.util.CallUtil;
import com.android.dialer.util.IntentUtil;
import java.util.ArrayList;
@@ -97,29 +97,16 @@ public abstract class IntentProvider {
/**
* Retrieves the call details intent provider for an entry in the call log.
*
- * @param id The call ID of the first call in the call group.
- * @param extraIds The call ID of the other calls grouped together with the call.
- * @param voicemailUri If call log entry is for a voicemail, the voicemail URI.
+ * @param callDetailsEntries The call details of the other calls grouped together with the call.
+ * @param contact The contact with which this call details intent pertains to.
* @return The call details intent provider.
*/
public static IntentProvider getCallDetailIntentProvider(
- final long id, final long[] extraIds, final String voicemailUri) {
+ CallDetailsEntries callDetailsEntries, CallComposerContact contact) {
return new IntentProvider() {
@Override
public Intent getIntent(Context context) {
- Intent intent = new Intent(context, CallDetailActivity.class);
- // Check if the first item is a voicemail.
- if (voicemailUri != null) {
- intent.putExtra(CallDetailActivity.EXTRA_VOICEMAIL_URI, Uri.parse(voicemailUri));
- }
-
- if (extraIds != null && extraIds.length > 0) {
- intent.putExtra(CallDetailActivity.EXTRA_CALL_LOG_IDS, extraIds);
- } else {
- // If there is a single item, use the direct URI for it.
- intent.setData(ContentUris.withAppendedId(TelecomUtil.getCallLogUri(context), id));
- }
- return intent;
+ return CallDetailsActivity.newInstance(context, callDetailsEntries, contact);
}
};
}
diff --git a/java/com/android/dialer/app/calllog/MissedCallNotifier.java b/java/com/android/dialer/app/calllog/MissedCallNotifier.java
index 2fa3dae65..5b5661615 100644
--- a/java/com/android/dialer/app/calllog/MissedCallNotifier.java
+++ b/java/com/android/dialer/app/calllog/MissedCallNotifier.java
@@ -16,16 +16,20 @@
package com.android.dialer.app.calllog;
import android.app.Notification;
+import android.app.Notification.Builder;
import android.app.NotificationManager;
import android.app.PendingIntent;
-import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
-import android.os.AsyncTask;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
import android.provider.CallLog.Calls;
+import android.service.notification.StatusBarNotification;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
+import android.support.annotation.WorkerThread;
import android.support.v4.os.UserManagerCompat;
import android.text.BidiFormatter;
import android.text.TextDirectionHeuristics;
@@ -34,109 +38,117 @@ import com.android.contacts.common.ContactsUtils;
import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
import com.android.dialer.app.DialtactsActivity;
import com.android.dialer.app.R;
-import com.android.dialer.app.calllog.CallLogNotificationsHelper.NewCall;
+import com.android.dialer.app.calllog.CallLogNotificationsQueryHelper.NewCall;
import com.android.dialer.app.contactinfo.ContactPhotoLoader;
import com.android.dialer.app.list.ListsFragment;
import com.android.dialer.callintent.CallIntentBuilder;
import com.android.dialer.callintent.nano.CallInitiationType;
-import com.android.dialer.common.ConfigProviderBindings;
import com.android.dialer.common.LogUtil;
+import com.android.dialer.notification.NotificationChannelManager;
+import com.android.dialer.notification.NotificationChannelManager.Channel;
import com.android.dialer.phonenumbercache.ContactInfo;
import com.android.dialer.phonenumberutil.PhoneNumberHelper;
+import com.android.dialer.telecom.TelecomUtil;
import com.android.dialer.util.DialerUtils;
import com.android.dialer.util.IntentUtil;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/** Creates a notification for calls that the user missed (neither answered nor rejected). */
public class MissedCallNotifier {
/** The tag used to identify notifications from this class. */
- private static final String NOTIFICATION_TAG = "MissedCallNotifier";
+ static final String NOTIFICATION_TAG = "MissedCallNotifier";
/** The identifier of the notification of new missed calls. */
- private static final int NOTIFICATION_ID = 1;
+ private static final int NOTIFICATION_ID = R.id.notification_missed_call;
- private static MissedCallNotifier sInstance;
- private Context mContext;
- private CallLogNotificationsHelper mCalllogNotificationsHelper;
+ private final Context context;
+ private final CallLogNotificationsQueryHelper callLogNotificationsQueryHelper;
@VisibleForTesting
- MissedCallNotifier(Context context, CallLogNotificationsHelper callLogNotificationsHelper) {
- mContext = context;
- mCalllogNotificationsHelper = callLogNotificationsHelper;
+ MissedCallNotifier(
+ Context context, CallLogNotificationsQueryHelper callLogNotificationsQueryHelper) {
+ this.context = context;
+ this.callLogNotificationsQueryHelper = callLogNotificationsQueryHelper;
}
- /** Returns the singleton instance of the {@link MissedCallNotifier}. */
+ /** Returns an instance of {@link MissedCallNotifier}. */
public static MissedCallNotifier getInstance(Context context) {
- if (sInstance == null) {
- CallLogNotificationsHelper callLogNotificationsHelper =
- CallLogNotificationsHelper.getInstance(context);
- sInstance = new MissedCallNotifier(context, callLogNotificationsHelper);
- }
- return sInstance;
+ CallLogNotificationsQueryHelper callLogNotificationsQueryHelper =
+ CallLogNotificationsQueryHelper.getInstance(context);
+ return new MissedCallNotifier(context, callLogNotificationsQueryHelper);
}
/**
- * Creates a missed call notification with a post call message if there are no existing missed
- * calls.
+ * Update missed call notifications from the call log. Accepts default information in case call
+ * log cannot be accessed.
+ *
+ * @param count the number of missed calls to display if call log cannot be accessed. May be
+ * {@link CallLogNotificationsService#UNKNOWN_MISSED_CALL_COUNT} if unknown.
+ * @param number the phone number of the most recent call to display if the call log cannot be
+ * accessed. May be null if unknown.
*/
- public void createPostCallMessageNotification(String number, String message) {
- int count = CallLogNotificationsService.UNKNOWN_MISSED_CALL_COUNT;
- if (ConfigProviderBindings.get(mContext).getBoolean("enable_call_compose", false)) {
- updateMissedCallNotification(count, number, message);
- } else {
- updateMissedCallNotification(count, number, null);
- }
- }
-
- /** Creates a missed call notification. */
- public void updateMissedCallNotification(int count, String number) {
- updateMissedCallNotification(count, number, null);
- }
-
- private void updateMissedCallNotification(
- int count, String number, @Nullable String postCallMessage) {
+ @WorkerThread
+ public void updateMissedCallNotification(int count, @Nullable String number) {
final int titleResId;
CharSequence expandedText; // The text in the notification's line 1 and 2.
- final List<NewCall> newCalls = mCalllogNotificationsHelper.getNewMissedCalls();
+ List<NewCall> newCalls = callLogNotificationsQueryHelper.getNewMissedCalls();
- if (count == CallLogNotificationsService.UNKNOWN_MISSED_CALL_COUNT) {
- if (newCalls == null) {
- // If the intent did not contain a count, and we are unable to get a count from the
- // call log, then no notification can be shown.
- return;
+ if ((newCalls != null && newCalls.isEmpty()) || count == 0) {
+ // No calls to notify about: clear the notification.
+ CallLogNotificationsQueryHelper.removeMissedCallNotifications(context, null);
+ return;
+ }
+
+ if (newCalls != null) {
+ if (count != CallLogNotificationsService.UNKNOWN_MISSED_CALL_COUNT
+ && count != newCalls.size()) {
+ LogUtil.w(
+ "MissedCallNotifier.updateMissedCallNotification",
+ "Call count does not match call log count."
+ + " count: "
+ + count
+ + " newCalls.size(): "
+ + newCalls.size());
}
count = newCalls.size();
}
- if (count == 0) {
- // No voicemails to notify about: clear the notification.
- clearMissedCalls();
+ if (count == CallLogNotificationsService.UNKNOWN_MISSED_CALL_COUNT) {
+ // If the intent did not contain a count, and we are unable to get a count from the
+ // call log, then no notification can be shown.
return;
}
- // The call log has been updated, use that information preferentially.
- boolean useCallLog = newCalls != null && newCalls.size() == count;
- NewCall newestCall = useCallLog ? newCalls.get(0) : null;
- long timeMs = useCallLog ? newestCall.dateMs : System.currentTimeMillis();
- String missedNumber = useCallLog ? newestCall.number : number;
+ Notification.Builder groupSummary = createNotificationBuilder();
+ boolean useCallList = newCalls != null;
- Notification.Builder builder = new Notification.Builder(mContext);
- // Display the first line of the notification:
- // 1 missed call: <caller name || handle>
- // More than 1 missed call: <number of calls> + "missed calls"
if (count == 1) {
+ NewCall call =
+ useCallList
+ ? newCalls.get(0)
+ : new NewCall(
+ null,
+ null,
+ number,
+ Calls.PRESENTATION_ALLOWED,
+ null,
+ null,
+ null,
+ null,
+ System.currentTimeMillis());
+
//TODO: look up caller ID that is not in contacts.
ContactInfo contactInfo =
- mCalllogNotificationsHelper.getContactInfo(
- missedNumber,
- useCallLog ? newestCall.numberPresentation : Calls.PRESENTATION_ALLOWED,
- useCallLog ? newestCall.countryIso : null);
-
+ callLogNotificationsQueryHelper.getContactInfo(
+ call.number, call.numberPresentation, call.countryIso);
titleResId =
contactInfo.userType == ContactsUtils.USER_TYPE_WORK
? R.string.notification_missedWorkCallTitle
: R.string.notification_missedCallTitle;
+
if (TextUtils.equals(contactInfo.name, contactInfo.formattedNumber)
|| TextUtils.equals(contactInfo.name, contactInfo.number)) {
expandedText =
@@ -147,134 +159,195 @@ public class MissedCallNotifier {
expandedText = contactInfo.name;
}
- if (!TextUtils.isEmpty(postCallMessage)) {
- // Ex. "John Doe: Hey dude"
- expandedText =
- mContext.getString(
- R.string.post_call_notification_message, expandedText, postCallMessage);
- }
- ContactPhotoLoader loader = new ContactPhotoLoader(mContext, contactInfo);
+ ContactPhotoLoader loader = new ContactPhotoLoader(context, contactInfo);
Bitmap photoIcon = loader.loadPhotoIcon();
if (photoIcon != null) {
- builder.setLargeIcon(photoIcon);
+ groupSummary.setLargeIcon(photoIcon);
}
} else {
titleResId = R.string.notification_missedCallsTitle;
- expandedText = mContext.getString(R.string.notification_missedCallsMsg, count);
+ expandedText = context.getString(R.string.notification_missedCallsMsg, count);
}
// Create a public viewable version of the notification, suitable for display when sensitive
// notification content is hidden.
- Notification.Builder publicBuilder = new Notification.Builder(mContext);
- publicBuilder
- .setSmallIcon(android.R.drawable.stat_notify_missed_call)
- .setColor(mContext.getResources().getColor(R.color.dialer_theme_color))
- // Show "Phone" for notification title.
- .setContentTitle(mContext.getText(R.string.userCallActivityLabel))
- // Notification details shows that there are missed call(s), but does not reveal
- // the missed caller information.
- .setContentText(mContext.getText(titleResId))
+ Notification.Builder publicSummaryBuilder = createNotificationBuilder();
+ publicSummaryBuilder
+ .setContentTitle(context.getText(titleResId))
.setContentIntent(createCallLogPendingIntent())
- .setAutoCancel(true)
- .setWhen(timeMs)
- .setShowWhen(true)
- .setDeleteIntent(createClearMissedCallsPendingIntent());
+ .setDeleteIntent(createClearMissedCallsPendingIntent(null));
+ // Create the notification summary suitable for display when sensitive information is showing.
+ groupSummary
+ .setContentTitle(context.getText(titleResId))
+ .setContentText(expandedText)
+ .setContentIntent(createCallLogPendingIntent())
+ .setDeleteIntent(createClearMissedCallsPendingIntent(null))
+ .setGroupSummary(useCallList)
+ .setOnlyAlertOnce(useCallList)
+ .setPublicVersion(publicSummaryBuilder.build());
+
+ NotificationChannelManager.applyChannel(
+ groupSummary,
+ context,
+ Channel.MISSED_CALL,
+ PhoneAccountHandles.getAccount(context, useCallList ? newCalls.get(0) : null));
+
+ Notification notification = groupSummary.build();
+ configureLedOnNotification(notification);
+
+ LogUtil.i("MissedCallNotifier.updateMissedCallNotification", "adding missed call notification");
+ getNotificationMgr().notify(NOTIFICATION_TAG, NOTIFICATION_ID, notification);
+
+ if (useCallList) {
+ // Do not repost active notifications to prevent erasing post call notes.
+ NotificationManager manager = getNotificationMgr();
+ Set<String> activeTags = new HashSet<>();
+ for (StatusBarNotification activeNotification : manager.getActiveNotifications()) {
+ activeTags.add(activeNotification.getTag());
+ }
+
+ for (NewCall call : newCalls) {
+ String callTag = call.callsUri.toString();
+ if (!activeTags.contains(callTag)) {
+ manager.notify(callTag, NOTIFICATION_ID, getNotificationForCall(call, null));
+ }
+ }
+ }
+ }
+
+ public void insertPostCallNotification(@NonNull String number, @NonNull String note) {
+ List<NewCall> newCalls = callLogNotificationsQueryHelper.getNewMissedCalls();
+ if (newCalls != null && !newCalls.isEmpty()) {
+ for (NewCall call : newCalls) {
+ if (call.number.equals(number.replace("tel:", ""))) {
+ // Update the first notification that matches our post call note sender.
+ getNotificationMgr()
+ .notify(
+ call.callsUri.toString(), NOTIFICATION_ID, getNotificationForCall(call, note));
+ break;
+ }
+ }
+ }
+ }
+
+ private Notification getNotificationForCall(
+ @NonNull NewCall call, @Nullable String postCallMessage) {
+ ContactInfo contactInfo =
+ callLogNotificationsQueryHelper.getContactInfo(
+ call.number, call.numberPresentation, call.countryIso);
+
+ // Create a public viewable version of the notification, suitable for display when sensitive
+ // notification content is hidden.
+ int titleResId =
+ contactInfo.userType == ContactsUtils.USER_TYPE_WORK
+ ? R.string.notification_missedWorkCallTitle
+ : R.string.notification_missedCallTitle;
+ Notification.Builder publicBuilder =
+ createNotificationBuilder(call).setContentTitle(context.getText(titleResId));
+
+ Notification.Builder builder = createNotificationBuilder(call);
+ CharSequence expandedText;
+ if (TextUtils.equals(contactInfo.name, contactInfo.formattedNumber)
+ || TextUtils.equals(contactInfo.name, contactInfo.number)) {
+ expandedText =
+ PhoneNumberUtilsCompat.createTtsSpannable(
+ BidiFormatter.getInstance()
+ .unicodeWrap(contactInfo.name, TextDirectionHeuristics.LTR));
+ } else {
+ expandedText = contactInfo.name;
+ }
+
+ if (postCallMessage != null) {
+ expandedText =
+ context.getString(R.string.post_call_notification_message, expandedText, postCallMessage);
+ }
+
+ ContactPhotoLoader loader = new ContactPhotoLoader(context, contactInfo);
+ Bitmap photoIcon = loader.loadPhotoIcon();
+ if (photoIcon != null) {
+ builder.setLargeIcon(photoIcon);
+ }
// Create the notification suitable for display when sensitive information is showing.
builder
- .setSmallIcon(android.R.drawable.stat_notify_missed_call)
- .setColor(mContext.getResources().getColor(R.color.dialer_theme_color))
- .setContentTitle(mContext.getText(titleResId))
+ .setContentTitle(context.getText(titleResId))
.setContentText(expandedText)
- .setContentIntent(createCallLogPendingIntent())
- .setAutoCancel(true)
- .setWhen(timeMs)
- .setShowWhen(true)
- .setDefaults(Notification.DEFAULT_VIBRATE)
- .setDeleteIntent(createClearMissedCallsPendingIntent())
// Include a public version of the notification to be shown when the missed call
// notification is shown on the user's lock screen and they have chosen to hide
// sensitive notification information.
.setPublicVersion(publicBuilder.build());
- // Add additional actions when there is only 1 missed call and the user isn't locked
- if (UserManagerCompat.isUserUnlocked(mContext) && count == 1) {
- if (!TextUtils.isEmpty(missedNumber)
- && !TextUtils.equals(missedNumber, mContext.getString(R.string.handle_restricted))) {
+ // Add additional actions when the user isn't locked
+ if (UserManagerCompat.isUserUnlocked(context)) {
+ if (!TextUtils.isEmpty(call.number)
+ && !TextUtils.equals(call.number, context.getString(R.string.handle_restricted))) {
builder.addAction(
- R.drawable.ic_phone_24dp,
- mContext.getString(R.string.notification_missedCall_call_back),
- createCallBackPendingIntent(missedNumber));
+ new Notification.Action.Builder(
+ Icon.createWithResource(context, R.drawable.ic_phone_24dp),
+ context.getString(R.string.notification_missedCall_call_back),
+ createCallBackPendingIntent(call.number, call.callsUri))
+ .build());
- if (!PhoneNumberHelper.isUriNumber(missedNumber)) {
+ if (!PhoneNumberHelper.isUriNumber(call.number)) {
builder.addAction(
- R.drawable.ic_message_24dp,
- mContext.getString(R.string.notification_missedCall_message),
- createSendSmsFromNotificationPendingIntent(missedNumber));
+ new Notification.Action.Builder(
+ Icon.createWithResource(context, R.drawable.ic_message_24dp),
+ context.getString(R.string.notification_missedCall_message),
+ createSendSmsFromNotificationPendingIntent(call.number, call.callsUri))
+ .build());
}
}
}
Notification notification = builder.build();
configureLedOnNotification(notification);
+ return notification;
+ }
- LogUtil.i("MissedCallNotifier.updateMissedCallNotification", "adding missed call notification");
- getNotificationMgr().notify(NOTIFICATION_TAG, NOTIFICATION_ID, notification);
+ private Notification.Builder createNotificationBuilder() {
+ return new Notification.Builder(context)
+ .setGroup(NOTIFICATION_TAG)
+ .setSmallIcon(android.R.drawable.stat_notify_missed_call)
+ .setColor(context.getResources().getColor(R.color.dialer_theme_color, null))
+ .setAutoCancel(true)
+ .setOnlyAlertOnce(true)
+ .setShowWhen(true)
+ .setDefaults(Notification.DEFAULT_VIBRATE);
}
- private void clearMissedCalls() {
- AsyncTask.execute(
- new Runnable() {
- @Override
- public void run() {
- // Call log is only accessible when unlocked. If that's the case, clear the list of
- // new missed calls from the call log.
- if (UserManagerCompat.isUserUnlocked(mContext)) {
- ContentValues values = new ContentValues();
- values.put(Calls.NEW, 0);
- values.put(Calls.IS_READ, 1);
- StringBuilder where = new StringBuilder();
- where.append(Calls.NEW);
- where.append(" = 1 AND ");
- where.append(Calls.TYPE);
- where.append(" = ?");
- try {
- mContext
- .getContentResolver()
- .update(
- Calls.CONTENT_URI,
- values,
- where.toString(),
- new String[] {Integer.toString(Calls.MISSED_TYPE)});
- } catch (IllegalArgumentException e) {
- LogUtil.e(
- "MissedCallNotifier.clearMissedCalls",
- "contacts provider update command failed",
- e);
- }
- }
- getNotificationMgr().cancel(NOTIFICATION_TAG, NOTIFICATION_ID);
- }
- });
+ private Notification.Builder createNotificationBuilder(@NonNull NewCall call) {
+ Builder builder =
+ createNotificationBuilder()
+ .setWhen(call.dateMs)
+ .setDeleteIntent(createClearMissedCallsPendingIntent(call.callsUri))
+ .setContentIntent(createCallLogPendingIntent(call.callsUri));
+
+ NotificationChannelManager.applyChannel(
+ builder, context, Channel.MISSED_CALL, PhoneAccountHandles.getAccount(context, call));
+ return builder;
}
/** Trigger an intent to make a call from a missed call number. */
- public void callBackFromMissedCall(String number) {
- closeSystemDialogs(mContext);
- CallLogNotificationsHelper.removeMissedCallNotifications(mContext);
+ @WorkerThread
+ public void callBackFromMissedCall(String number, Uri callUri) {
+ closeSystemDialogs(context);
+ CallLogNotificationsQueryHelper.removeMissedCallNotifications(context, callUri);
+ TelecomUtil.cancelMissedCallsNotification(context);
DialerUtils.startActivityWithErrorToast(
- mContext,
+ context,
new CallIntentBuilder(number, CallInitiationType.Type.MISSED_CALL_NOTIFICATION)
.build()
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
/** Trigger an intent to send an sms from a missed call number. */
- public void sendSmsFromMissedCall(String number) {
- closeSystemDialogs(mContext);
- CallLogNotificationsHelper.removeMissedCallNotifications(mContext);
+ @WorkerThread
+ public void sendSmsFromMissedCall(String number, Uri callUri) {
+ closeSystemDialogs(context);
+ CallLogNotificationsQueryHelper.removeMissedCallNotifications(context, callUri);
+ TelecomUtil.cancelMissedCallsNotification(context);
DialerUtils.startActivityWithErrorToast(
- mContext, IntentUtil.getSendSmsIntent(number).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ context, IntentUtil.getSendSmsIntent(number).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
/**
@@ -283,34 +356,50 @@ public class MissedCallNotifier {
* @return The pending intent.
*/
private PendingIntent createCallLogPendingIntent() {
+ return createCallLogPendingIntent(null);
+ }
+
+ /**
+ * Creates a new pending intent that sends the user to the call log.
+ *
+ * @return The pending intent.
+ * @param callUri Uri of the call to jump to. May be null
+ */
+ private PendingIntent createCallLogPendingIntent(@Nullable Uri callUri) {
Intent contentIntent =
- DialtactsActivity.getShowTabIntent(mContext, ListsFragment.TAB_INDEX_HISTORY);
- return PendingIntent.getActivity(mContext, 0, contentIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+ DialtactsActivity.getShowTabIntent(context, ListsFragment.TAB_INDEX_HISTORY);
+ // TODO (b/35486204): scroll to call
+ contentIntent.setData(callUri);
+ return PendingIntent.getActivity(context, 0, contentIntent, PendingIntent.FLAG_UPDATE_CURRENT);
}
/** Creates a pending intent that marks all new missed calls as old. */
- private PendingIntent createClearMissedCallsPendingIntent() {
- Intent intent = new Intent(mContext, CallLogNotificationsService.class);
+ private PendingIntent createClearMissedCallsPendingIntent(@Nullable Uri callUri) {
+ Intent intent = new Intent(context, CallLogNotificationsService.class);
intent.setAction(CallLogNotificationsService.ACTION_MARK_NEW_MISSED_CALLS_AS_OLD);
- return PendingIntent.getService(mContext, 0, intent, 0);
+ intent.setData(callUri);
+ return PendingIntent.getService(context, 0, intent, 0);
}
- private PendingIntent createCallBackPendingIntent(String number) {
- Intent intent = new Intent(mContext, CallLogNotificationsService.class);
+ private PendingIntent createCallBackPendingIntent(String number, @NonNull Uri callUri) {
+ Intent intent = new Intent(context, CallLogNotificationsService.class);
intent.setAction(CallLogNotificationsService.ACTION_CALL_BACK_FROM_MISSED_CALL_NOTIFICATION);
intent.putExtra(CallLogNotificationsService.EXTRA_MISSED_CALL_NUMBER, number);
+ intent.setData(callUri);
// Use FLAG_UPDATE_CURRENT to make sure any previous pending intent is updated with the new
// extra.
- return PendingIntent.getService(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
- private PendingIntent createSendSmsFromNotificationPendingIntent(String number) {
- Intent intent = new Intent(mContext, CallLogNotificationsService.class);
+ private PendingIntent createSendSmsFromNotificationPendingIntent(
+ String number, @NonNull Uri callUri) {
+ Intent intent = new Intent(context, CallLogNotificationsService.class);
intent.setAction(CallLogNotificationsService.ACTION_SEND_SMS_FROM_MISSED_CALL_NOTIFICATION);
intent.putExtra(CallLogNotificationsService.EXTRA_MISSED_CALL_NUMBER, number);
+ intent.setData(callUri);
// Use FLAG_UPDATE_CURRENT to make sure any previous pending intent is updated with the new
// extra.
- return PendingIntent.getService(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
/** Configures a notification to emit the blinky notification light. */
@@ -325,6 +414,6 @@ public class MissedCallNotifier {
}
private NotificationManager getNotificationMgr() {
- return (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
}
}
diff --git a/java/com/android/dialer/app/calllog/PhoneAccountHandles.java b/java/com/android/dialer/app/calllog/PhoneAccountHandles.java
new file mode 100644
index 000000000..6d51b853c
--- /dev/null
+++ b/java/com/android/dialer/app/calllog/PhoneAccountHandles.java
@@ -0,0 +1,41 @@
+package com.android.dialer.app.calllog;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
+import com.android.dialer.app.calllog.CallLogNotificationsQueryHelper.NewCall;
+import com.android.dialer.common.LogUtil;
+import com.android.dialer.telecom.TelecomUtil;
+
+/** Methods to help extract {@link PhoneAccount} information from database and Telecomm sources. */
+class PhoneAccountHandles {
+
+ @Nullable
+ public static PhoneAccountHandle getAccount(@NonNull Context context, @Nullable NewCall call) {
+ PhoneAccountHandle handle;
+ if (call == null || call.accountComponentName == null || call.accountId == null) {
+ LogUtil.v(
+ "PhoneAccountUtils.getAccount",
+ "accountComponentName == null || callToNotify.accountId == null");
+ handle = TelecomUtil.getDefaultOutgoingPhoneAccount(context, PhoneAccount.SCHEME_TEL);
+ if (handle == null) {
+ return null;
+ }
+ } else {
+ handle =
+ new PhoneAccountHandle(
+ ComponentName.unflattenFromString(call.accountComponentName), call.accountId);
+ }
+ if (handle.getComponentName() != null) {
+ LogUtil.v(
+ "PhoneAccountUtils.getAccount",
+ "PhoneAccountHandle.ComponentInfo:" + handle.getComponentName());
+ } else {
+ LogUtil.i("PhoneAccountUtils.getAccount", "PhoneAccountHandle.ComponentInfo: null");
+ }
+ return handle;
+ }
+}
diff --git a/java/com/android/dialer/app/calllog/PhoneAccountUtils.java b/java/com/android/dialer/app/calllog/PhoneAccountUtils.java
deleted file mode 100644
index c6d94d341..000000000
--- a/java/com/android/dialer/app/calllog/PhoneAccountUtils.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2013 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.app.calllog;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.support.annotation.Nullable;
-import android.telecom.PhoneAccount;
-import android.telecom.PhoneAccountHandle;
-import android.text.TextUtils;
-import com.android.dialer.telecom.TelecomUtil;
-import java.util.ArrayList;
-import java.util.List;
-
-/** Methods to help extract {@code PhoneAccount} information from database and Telecomm sources. */
-public class PhoneAccountUtils {
-
- /** Return a list of phone accounts that are subscription/SIM accounts. */
- public static List<PhoneAccountHandle> getSubscriptionPhoneAccounts(Context context) {
- List<PhoneAccountHandle> subscriptionAccountHandles = new ArrayList<PhoneAccountHandle>();
- final List<PhoneAccountHandle> accountHandles =
- TelecomUtil.getCallCapablePhoneAccounts(context);
- for (PhoneAccountHandle accountHandle : accountHandles) {
- PhoneAccount account = TelecomUtil.getPhoneAccount(context, accountHandle);
- if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
- subscriptionAccountHandles.add(accountHandle);
- }
- }
- return subscriptionAccountHandles;
- }
-
- /** Compose PhoneAccount object from component name and account id. */
- @Nullable
- public static PhoneAccountHandle getAccount(
- @Nullable String componentString, @Nullable String accountId) {
- if (TextUtils.isEmpty(componentString) || TextUtils.isEmpty(accountId)) {
- return null;
- }
- final ComponentName componentName = ComponentName.unflattenFromString(componentString);
- if (componentName == null) {
- return null;
- }
- return new PhoneAccountHandle(componentName, accountId);
- }
-
- /** Extract account label from PhoneAccount object. */
- @Nullable
- public static String getAccountLabel(
- Context context, @Nullable PhoneAccountHandle accountHandle) {
- PhoneAccount account = getAccountOrNull(context, accountHandle);
- if (account != null && account.getLabel() != null) {
- return account.getLabel().toString();
- }
- return null;
- }
-
- /** Extract account color from PhoneAccount object. */
- public static int getAccountColor(Context context, @Nullable PhoneAccountHandle accountHandle) {
- final PhoneAccount account = TelecomUtil.getPhoneAccount(context, 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();
- }
-
- /**
- * Determine whether a phone account supports call subjects.
- *
- * @return {@code true} if call subjects are supported, {@code false} otherwise.
- */
- public static boolean getAccountSupportsCallSubject(
- Context context, @Nullable PhoneAccountHandle accountHandle) {
- final PhoneAccount account = TelecomUtil.getPhoneAccount(context, accountHandle);
-
- return account != null && account.hasCapabilities(PhoneAccount.CAPABILITY_CALL_SUBJECT);
- }
-
- /**
- * Retrieve the account metadata, but if the account does not exist or the device has only a
- * single registered and enabled account, return null.
- */
- @Nullable
- private static PhoneAccount getAccountOrNull(
- Context context, @Nullable PhoneAccountHandle accountHandle) {
- if (TelecomUtil.getCallCapablePhoneAccounts(context).size() <= 1) {
- return null;
- }
- return TelecomUtil.getPhoneAccount(context, accountHandle);
- }
-}
diff --git a/java/com/android/dialer/app/calllog/PhoneCallDetailsHelper.java b/java/com/android/dialer/app/calllog/PhoneCallDetailsHelper.java
index b18270bb3..acbccb39f 100644
--- a/java/com/android/dialer/app/calllog/PhoneCallDetailsHelper.java
+++ b/java/com/android/dialer/app/calllog/PhoneCallDetailsHelper.java
@@ -27,9 +27,10 @@ import android.text.TextUtils;
import android.text.format.DateUtils;
import android.view.View;
import android.widget.TextView;
-import com.android.dialer.app.PhoneCallDetails;
import com.android.dialer.app.R;
import com.android.dialer.app.calllog.calllogcache.CallLogCache;
+import com.android.dialer.calllogutils.PhoneCallDetails;
+import com.android.dialer.oem.MotorolaUtils;
import com.android.dialer.phonenumberutil.PhoneNumberHelper;
import com.android.dialer.util.DialerUtils;
import java.util.ArrayList;
@@ -84,6 +85,8 @@ public class PhoneCallDetailsHelper {
// Show the video icon if the call had video enabled.
views.callTypeIcons.setShowVideo(
(details.features & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO);
+ views.callTypeIcons.setShowHd(
+ MotorolaUtils.shouldShowHdIconInCallLog(mContext, details.features));
views.callTypeIcons.requestLayout();
views.callTypeIcons.setVisibility(View.VISIBLE);
diff --git a/java/com/android/dialer/app/calllog/PhoneCallDetailsViews.java b/java/com/android/dialer/app/calllog/PhoneCallDetailsViews.java
index 476996826..e2e27a179 100644
--- a/java/com/android/dialer/app/calllog/PhoneCallDetailsViews.java
+++ b/java/com/android/dialer/app/calllog/PhoneCallDetailsViews.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.view.View;
import android.widget.TextView;
import com.android.dialer.app.R;
+import com.android.dialer.calllogutils.CallTypeIconsView;
/** Encapsulates the views that are used to display the details of a phone call in the call log. */
public final class PhoneCallDetailsViews {
diff --git a/java/com/android/dialer/app/calllog/PhoneNumberDisplayUtil.java b/java/com/android/dialer/app/calllog/PhoneNumberDisplayUtil.java
deleted file mode 100644
index 410d4cc37..000000000
--- a/java/com/android/dialer/app/calllog/PhoneNumberDisplayUtil.java
+++ /dev/null
@@ -1,85 +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.app.calllog;
-
-import android.content.Context;
-import android.provider.CallLog.Calls;
-import android.text.BidiFormatter;
-import android.text.TextDirectionHeuristics;
-import android.text.TextUtils;
-import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
-import com.android.dialer.app.R;
-import com.android.dialer.phonenumberutil.PhoneNumberHelper;
-
-/** Helper for formatting and managing the display of phone numbers. */
-public class PhoneNumberDisplayUtil {
-
- /** Returns the string to display for the given phone number if there is no matching contact. */
- /* package */
- static CharSequence getDisplayName(
- Context context, CharSequence number, int presentation, boolean isVoicemail) {
- if (presentation == Calls.PRESENTATION_UNKNOWN) {
- return context.getResources().getString(R.string.unknown);
- }
- if (presentation == Calls.PRESENTATION_RESTRICTED) {
- return PhoneNumberHelper.getDisplayNameForRestrictedNumber(context);
- }
- if (presentation == Calls.PRESENTATION_PAYPHONE) {
- return context.getResources().getString(R.string.payphone);
- }
- if (isVoicemail) {
- return context.getResources().getString(R.string.voicemail);
- }
- if (PhoneNumberHelper.isLegacyUnknownNumbers(number)) {
- return context.getResources().getString(R.string.unknown);
- }
- return "";
- }
-
- /**
- * Returns the string to display for the given phone number.
- *
- * @param number the number to display
- * @param formattedNumber the formatted number if available, may be null
- */
- public static CharSequence getDisplayNumber(
- Context context,
- CharSequence number,
- int presentation,
- CharSequence formattedNumber,
- CharSequence postDialDigits,
- boolean isVoicemail) {
- final CharSequence displayName = getDisplayName(context, number, presentation, isVoicemail);
- if (!TextUtils.isEmpty(displayName)) {
- return getTtsSpannableLtrNumber(displayName);
- }
-
- if (!TextUtils.isEmpty(formattedNumber)) {
- return getTtsSpannableLtrNumber(formattedNumber);
- } else if (!TextUtils.isEmpty(number)) {
- return getTtsSpannableLtrNumber(number.toString() + postDialDigits);
- } else {
- return context.getResources().getString(R.string.unknown);
- }
- }
-
- /** Returns number annotated as phone number in LTR direction. */
- public static CharSequence getTtsSpannableLtrNumber(CharSequence number) {
- return PhoneNumberUtilsCompat.createTtsSpannable(
- BidiFormatter.getInstance().unicodeWrap(number.toString(), TextDirectionHeuristics.LTR));
- }
-}
diff --git a/java/com/android/dialer/app/calllog/VisualVoicemailCallLogFragment.java b/java/com/android/dialer/app/calllog/VisualVoicemailCallLogFragment.java
index e539ceef6..6f101f580 100644
--- a/java/com/android/dialer/app/calllog/VisualVoicemailCallLogFragment.java
+++ b/java/com/android/dialer/app/calllog/VisualVoicemailCallLogFragment.java
@@ -40,10 +40,13 @@ public class VisualVoicemailCallLogFragment extends CallLogFragment {
private VoicemailErrorManager mVoicemailAlertManager;
+ public VisualVoicemailCallLogFragment() {
+ super(CallLog.Calls.VOICEMAIL_TYPE);
+ }
+
@Override
public void onCreate(Bundle state) {
super.onCreate(state);
- mCallTypeFilter = CallLog.Calls.VOICEMAIL_TYPE;
mVoicemailPlaybackPresenter = VoicemailPlaybackPresenter.getInstance(getActivity(), state);
getActivity()
.getContentResolver()
diff --git a/java/com/android/dialer/app/calllog/VoicemailQueryHandler.java b/java/com/android/dialer/app/calllog/VoicemailQueryHandler.java
index d6d8354ec..e73684e70 100644
--- a/java/com/android/dialer/app/calllog/VoicemailQueryHandler.java
+++ b/java/com/android/dialer/app/calllog/VoicemailQueryHandler.java
@@ -15,13 +15,18 @@
*/
package com.android.dialer.app.calllog;
+import android.app.NotificationManager;
import android.content.AsyncQueryHandler;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
+import android.net.Uri;
import android.provider.CallLog.Calls;
-import android.util.Log;
+import android.support.annotation.Nullable;
+import com.android.dialer.app.R;
+import com.android.dialer.common.LogUtil;
+import com.android.dialer.notification.GroupedNotificationUtil;
/** Handles asynchronous queries to the call log for voicemail. */
public class VoicemailQueryHandler extends AsyncQueryHandler {
@@ -39,7 +44,7 @@ public class VoicemailQueryHandler extends AsyncQueryHandler {
}
/** Updates all new voicemails to mark them as old. */
- public void markNewVoicemailsAsOld() {
+ public void markNewVoicemailsAsOld(@Nullable Uri voicemailUri) {
// Mark all "new" voicemails as not new anymore.
StringBuilder where = new StringBuilder();
where.append(Calls.NEW);
@@ -47,6 +52,10 @@ public class VoicemailQueryHandler extends AsyncQueryHandler {
where.append(Calls.TYPE);
where.append(" = ?");
+ if (voicemailUri != null) {
+ where.append(" AND ").append(Calls.VOICEMAIL_URI).append(" = ?");
+ }
+
ContentValues values = new ContentValues(1);
values.put(Calls.NEW, "0");
@@ -56,7 +65,15 @@ public class VoicemailQueryHandler extends AsyncQueryHandler {
Calls.CONTENT_URI_WITH_VOICEMAIL,
values,
where.toString(),
- new String[] {Integer.toString(Calls.VOICEMAIL_TYPE)});
+ voicemailUri == null
+ ? new String[] {Integer.toString(Calls.VOICEMAIL_TYPE)}
+ : new String[] {Integer.toString(Calls.VOICEMAIL_TYPE), voicemailUri.toString()});
+
+ GroupedNotificationUtil.removeNotification(
+ mContext.getSystemService(NotificationManager.class),
+ voicemailUri != null ? voicemailUri.toString() : null,
+ R.id.notification_voicemail,
+ DefaultVoicemailNotifier.NOTIFICATION_TAG);
}
@Override
@@ -67,7 +84,7 @@ public class VoicemailQueryHandler extends AsyncQueryHandler {
serviceIntent.setAction(CallLogNotificationsService.ACTION_UPDATE_VOICEMAIL_NOTIFICATIONS);
mContext.startService(serviceIntent);
} else {
- Log.w(TAG, "Unknown update completed: ignoring: " + token);
+ LogUtil.w(TAG, "Unknown update completed: ignoring: " + token);
}
}
}
diff --git a/java/com/android/dialer/app/calllog/calllogcache/CallLogCacheLollipopMr1.java b/java/com/android/dialer/app/calllog/calllogcache/CallLogCacheLollipopMr1.java
index c342b7e3b..039998780 100644
--- a/java/com/android/dialer/app/calllog/calllogcache/CallLogCacheLollipopMr1.java
+++ b/java/com/android/dialer/app/calllog/calllogcache/CallLogCacheLollipopMr1.java
@@ -20,10 +20,10 @@ import android.content.Context;
import android.support.annotation.VisibleForTesting;
import android.telecom.PhoneAccountHandle;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.Pair;
-import com.android.dialer.app.calllog.PhoneAccountUtils;
+import com.android.dialer.calllogutils.PhoneAccountUtils;
import com.android.dialer.phonenumberutil.PhoneNumberHelper;
-import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -45,9 +45,9 @@ class CallLogCacheLollipopMr1 extends CallLogCache {
final Map<Pair<PhoneAccountHandle, CharSequence>, Boolean> mVoicemailQueryCache =
new ConcurrentHashMap<>();
- private final Map<PhoneAccountHandle, String> mPhoneAccountLabelCache = new HashMap<>();
- private final Map<PhoneAccountHandle, Integer> mPhoneAccountColorCache = new HashMap<>();
- private final Map<PhoneAccountHandle, Boolean> mPhoneAccountCallWithNoteCache = new HashMap<>();
+ private final Map<PhoneAccountHandle, String> mPhoneAccountLabelCache = new ArrayMap<>();
+ private final Map<PhoneAccountHandle, Integer> mPhoneAccountColorCache = new ArrayMap<>();
+ private final Map<PhoneAccountHandle, Boolean> mPhoneAccountCallWithNoteCache = new ArrayMap<>();
/* package */ CallLogCacheLollipopMr1(Context context) {
super(context);
diff --git a/java/com/android/dialer/app/contactinfo/ContactInfoCache.java b/java/com/android/dialer/app/contactinfo/ContactInfoCache.java
index 4135cb7b8..6c35711a8 100644
--- a/java/com/android/dialer/app/contactinfo/ContactInfoCache.java
+++ b/java/com/android/dialer/app/contactinfo/ContactInfoCache.java
@@ -29,8 +29,8 @@ import java.util.concurrent.BlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
/**
- * This is a cache of contact details for the phone numbers in the c all log. The key is the phone
- * number with the country in which teh call was placed or received. The content of the cache is
+ * This is a cache of contact details for the phone numbers in the call log. The key is the phone
+ * number with the country in which the call was placed or received. The content of the cache is
* expired (but not purged) whenever the application comes to the foreground.
*
* <p>This cache queues request for information and queries for information on a background thread,
diff --git a/java/com/android/dialer/app/contactinfo/ContactPhotoLoader.java b/java/com/android/dialer/app/contactinfo/ContactPhotoLoader.java
index a8c718502..71e4a16ad 100644
--- a/java/com/android/dialer/app/contactinfo/ContactPhotoLoader.java
+++ b/java/com/android/dialer/app/contactinfo/ContactPhotoLoader.java
@@ -104,7 +104,7 @@ public class ContactPhotoLoader {
final RoundedBitmapDrawable drawable =
RoundedBitmapDrawableFactory.create(mContext.getResources(), bitmap);
drawable.setAntiAlias(true);
- drawable.setCornerRadius(bitmap.getHeight() / 2);
+ drawable.setCircular(true);
return drawable;
} catch (IOException e) {
LogUtil.e("ContactPhotoLoader.createPhotoIconDrawable", e.toString());
diff --git a/java/com/android/dialer/app/dialpad/DialpadFragment.java b/java/com/android/dialer/app/dialpad/DialpadFragment.java
index 18bb250ce..4785ab16f 100644
--- a/java/com/android/dialer/app/dialpad/DialpadFragment.java
+++ b/java/com/android/dialer/app/dialpad/DialpadFragment.java
@@ -78,9 +78,9 @@ import com.android.dialer.app.DialtactsActivity;
import com.android.dialer.app.R;
import com.android.dialer.app.SpecialCharSequenceMgr;
import com.android.dialer.app.calllog.CallLogAsync;
-import com.android.dialer.app.calllog.PhoneAccountUtils;
import com.android.dialer.callintent.CallIntentBuilder;
import com.android.dialer.callintent.nano.CallInitiationType;
+import com.android.dialer.calllogutils.PhoneAccountUtils;
import com.android.dialer.common.LogUtil;
import com.android.dialer.dialpadview.DialpadKeyButton;
import com.android.dialer.dialpadview.DialpadView;
@@ -598,6 +598,7 @@ public class DialpadFragment extends Fragment
@Override
public void onStart() {
+ LogUtil.d("DialpadFragment.onStart", "first launch: %b", mFirstLaunch);
Trace.beginSection(TAG + " onStart");
super.onStart();
// if the mToneGenerator creation fails, just continue without it. It is
@@ -624,6 +625,7 @@ public class DialpadFragment extends Fragment
@Override
public void onResume() {
+ LogUtil.d("DialpadFragment.onResume", "");
Trace.beginSection(TAG + " onResume");
super.onResume();
diff --git a/java/com/android/dialer/app/filterednumber/BlockedNumbersSettingsActivity.java b/java/com/android/dialer/app/filterednumber/BlockedNumbersSettingsActivity.java
index eef920710..9ec6042c0 100644
--- a/java/com/android/dialer/app/filterednumber/BlockedNumbersSettingsActivity.java
+++ b/java/com/android/dialer/app/filterednumber/BlockedNumbersSettingsActivity.java
@@ -135,11 +135,6 @@ public class BlockedNumbersSettingsActivity extends AppCompatActivity
}
@Override
- public int getActionBarHideOffset() {
- return 0;
- }
-
- @Override
public int getActionBarHeight() {
return 0;
}
diff --git a/java/com/android/dialer/app/legacybindings/DialerLegacyBindings.java b/java/com/android/dialer/app/legacybindings/DialerLegacyBindings.java
index 2125a1524..1cdeb2175 100644
--- a/java/com/android/dialer/app/legacybindings/DialerLegacyBindings.java
+++ b/java/com/android/dialer/app/legacybindings/DialerLegacyBindings.java
@@ -17,12 +17,14 @@
package com.android.dialer.app.legacybindings;
import android.app.Activity;
+import android.support.annotation.NonNull;
import android.view.ViewGroup;
import com.android.dialer.app.calllog.CallLogAdapter;
import com.android.dialer.app.calllog.calllogcache.CallLogCache;
import com.android.dialer.app.contactinfo.ContactInfoCache;
import com.android.dialer.app.list.RegularSearchFragment;
import com.android.dialer.app.voicemail.VoicemailPlaybackPresenter;
+import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler;
/**
* These are old bindings between Dialer and the container application. All new bindings should be
@@ -41,6 +43,7 @@ public interface DialerLegacyBindings {
CallLogCache callLogCache,
ContactInfoCache contactInfoCache,
VoicemailPlaybackPresenter voicemailPlaybackPresenter,
+ @NonNull FilteredNumberAsyncQueryHandler filteredNumberAsyncQueryHandler,
int activityType);
RegularSearchFragment newRegularSearchFragment();
diff --git a/java/com/android/dialer/app/legacybindings/DialerLegacyBindingsStub.java b/java/com/android/dialer/app/legacybindings/DialerLegacyBindingsStub.java
index f01df78f8..6e32843ba 100644
--- a/java/com/android/dialer/app/legacybindings/DialerLegacyBindingsStub.java
+++ b/java/com/android/dialer/app/legacybindings/DialerLegacyBindingsStub.java
@@ -17,12 +17,14 @@
package com.android.dialer.app.legacybindings;
import android.app.Activity;
+import android.support.annotation.NonNull;
import android.view.ViewGroup;
import com.android.dialer.app.calllog.CallLogAdapter;
import com.android.dialer.app.calllog.calllogcache.CallLogCache;
import com.android.dialer.app.contactinfo.ContactInfoCache;
import com.android.dialer.app.list.RegularSearchFragment;
import com.android.dialer.app.voicemail.VoicemailPlaybackPresenter;
+import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler;
/** Default implementation for dialer legacy bindings. */
public class DialerLegacyBindingsStub implements DialerLegacyBindings {
@@ -35,6 +37,7 @@ public class DialerLegacyBindingsStub implements DialerLegacyBindings {
CallLogCache callLogCache,
ContactInfoCache contactInfoCache,
VoicemailPlaybackPresenter voicemailPlaybackPresenter,
+ @NonNull FilteredNumberAsyncQueryHandler filteredNumberAsyncQueryHandler,
int activityType) {
return new CallLogAdapter(
activity,
@@ -43,6 +46,7 @@ public class DialerLegacyBindingsStub implements DialerLegacyBindings {
callLogCache,
contactInfoCache,
voicemailPlaybackPresenter,
+ filteredNumberAsyncQueryHandler,
activityType);
}
diff --git a/java/com/android/dialer/app/list/ListsFragment.java b/java/com/android/dialer/app/list/ListsFragment.java
index 725ad3001..13938f29a 100644
--- a/java/com/android/dialer/app/list/ListsFragment.java
+++ b/java/com/android/dialer/app/list/ListsFragment.java
@@ -30,19 +30,16 @@ import android.support.annotation.Nullable;
import android.support.v13.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
-import android.support.v7.app.ActionBar;
-import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.android.contacts.common.list.ViewPagerTabs;
import com.android.dialer.app.R;
import com.android.dialer.app.calllog.CallLogFragment;
-import com.android.dialer.app.calllog.CallLogNotificationsHelper;
+import com.android.dialer.app.calllog.CallLogNotificationsService;
import com.android.dialer.app.calllog.VisualVoicemailCallLogFragment;
import com.android.dialer.app.voicemail.error.VoicemailStatusCorruptionHandler;
import com.android.dialer.app.voicemail.error.VoicemailStatusCorruptionHandler.Source;
-import com.android.dialer.app.widget.ActionBarController;
import com.android.dialer.common.LogUtil;
import com.android.dialer.database.CallLogQueryHandler;
import com.android.dialer.logging.Logger;
@@ -92,7 +89,6 @@ public class ListsFragment extends Fragment
public static final int TAB_COUNT_DEFAULT = 3;
public static final int TAB_COUNT_WITH_VOICEMAIL = 4;
private static final String TAG = "ListsFragment";
- private ActionBar mActionBar;
private ViewPager mViewPager;
private ViewPagerTabs mViewPagerTabs;
private ViewPagerAdapter mViewPagerAdapter;
@@ -108,8 +104,7 @@ public class ListsFragment extends Fragment
private boolean mHasFetchedVoicemailStatus;
private boolean mShowVoicemailTabAfterVoicemailStatusIsFetched;
private VoicemailStatusHelper mVoicemailStatusHelper;
- private ArrayList<OnPageChangeListener> mOnPageChangeListeners =
- new ArrayList<OnPageChangeListener>();
+ private final ArrayList<OnPageChangeListener> mOnPageChangeListeners = new ArrayList<>();
private String[] mTabTitles;
private int[] mTabIcons;
/** The position of the currently selected tab. */
@@ -149,7 +144,6 @@ public class ListsFragment extends Fragment
Trace.beginSection(TAG + " onResume");
super.onResume();
- mActionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
if (getUserVisibleHint()) {
sendScreenViewForCurrentPosition();
}
@@ -329,7 +323,7 @@ public class ListsFragment extends Fragment
.putBoolean(
VisualVoicemailEnabledChecker.PREF_KEY_HAS_ACTIVE_VOICEMAIL_PROVIDER,
hasActiveVoicemailProvider)
- .commit();
+ .apply();
}
if (hasActiveVoicemailProvider) {
@@ -403,7 +397,7 @@ public class ListsFragment extends Fragment
public void markMissedCallsAsReadAndRemoveNotifications() {
if (mCallLogQueryHandler != null) {
mCallLogQueryHandler.markMissedCallsAsRead();
- CallLogNotificationsHelper.removeMissedCallNotifications(getActivity());
+ CallLogNotificationsService.markNewMissedCallsAsOld(getContext(), null);
}
}
@@ -413,11 +407,6 @@ public class ListsFragment extends Fragment
mRemoveView.animate().alpha(show ? 1 : 0).start();
}
- public boolean shouldShowActionBar() {
- // TODO: Update this based on scroll state.
- return mActionBar != null;
- }
-
public SpeedDialFragment getSpeedDialFragment() {
return mSpeedDialFragment;
}
@@ -486,11 +475,6 @@ public class ListsFragment extends Fragment
throw new IllegalStateException("No fragment at position " + position);
}
- public interface HostInterface {
-
- ActionBarController getActionBarController();
- }
-
public class ViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragments = new ArrayList<>();
@@ -518,7 +502,7 @@ public class ListsFragment extends Fragment
return mSpeedDialFragment;
case TAB_INDEX_HISTORY:
if (mHistoryFragment == null) {
- mHistoryFragment = new CallLogFragment();
+ mHistoryFragment = new CallLogFragment(CallLogQueryHandler.CALL_TYPE_ALL);
}
return mHistoryFragment;
case TAB_INDEX_ALL_CONTACTS:
diff --git a/java/com/android/dialer/app/list/SearchFragment.java b/java/com/android/dialer/app/list/SearchFragment.java
index 4a7d48ae4..e6615aa8d 100644
--- a/java/com/android/dialer/app/list/SearchFragment.java
+++ b/java/com/android/dialer/app/list/SearchFragment.java
@@ -98,6 +98,7 @@ public class SearchFragment extends PhoneNumberPickerFragment {
@Override
public void onStart() {
+ LogUtil.d("SearchFragment.onStart", "");
super.onStart();
if (isSearchMode()) {
getAdapter().setHasHeader(0, false);
@@ -301,6 +302,7 @@ public class SearchFragment extends PhoneNumberPickerFragment {
* shown. This can be optionally animated.
*/
public void updatePosition(boolean animate) {
+ LogUtil.d("SearchFragment.updatePosition", "animate: %b", animate);
if (mActivity == null) {
// Activity will be set in onStart, and this method will be called again
return;
@@ -363,6 +365,13 @@ public class SearchFragment extends PhoneNumberPickerFragment {
return;
}
int spacerHeight = mActivity.isDialpadShown() ? mActivity.getDialpadHeight() : 0;
+ LogUtil.d(
+ "SearchFragment.resizeListView",
+ "spacerHeight: %d -> %d, isDialpadShown: %b, dialpad height: %d",
+ mSpacer.getHeight(),
+ spacerHeight,
+ mActivity.isDialpadShown(),
+ mActivity.getDialpadHeight());
if (spacerHeight != mSpacer.getHeight()) {
final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mSpacer.getLayoutParams();
lp.height = spacerHeight;
@@ -418,8 +427,6 @@ public class SearchFragment extends PhoneNumberPickerFragment {
int getDialpadHeight();
- int getActionBarHideOffset();
-
int getActionBarHeight();
}
}
diff --git a/java/com/android/dialer/app/manifests/activities/AndroidManifest.xml b/java/com/android/dialer/app/manifests/activities/AndroidManifest.xml
index 247b34f4c..7e450c4cd 100644
--- a/java/com/android/dialer/app/manifests/activities/AndroidManifest.xml
+++ b/java/com/android/dialer/app/manifests/activities/AndroidManifest.xml
@@ -29,18 +29,6 @@
android:theme="@style/SettingsStyle">
</activity>
- <activity
- android:label="@string/callDetailTitle"
- android:name="com.android.dialer.app.CallDetailActivity"
- android:parentActivityName="com.android.dialer.calllog.CallLogActivity"
- android:theme="@style/CallDetailActivityTheme">
- <intent-filter>
- <action android:name="android.intent.action.VIEW"/>
- <category android:name="android.intent.category.DEFAULT"/>
- <data android:mimeType="vnd.android.cursor.item/calls"/>
- </intent-filter>
- </activity>
-
<!-- The entrance point for Phone UI.
stateAlwaysHidden is set to suppress keyboard show up on
dialpad screen. -->
diff --git a/java/com/android/dialer/app/res/drawable-hdpi/ic_call_arrow.png b/java/com/android/dialer/app/res/drawable-hdpi/ic_call_arrow.png
deleted file mode 100644
index 14a33e39f..000000000
--- a/java/com/android/dialer/app/res/drawable-hdpi/ic_call_arrow.png
+++ /dev/null
Binary files differ
diff --git a/java/com/android/dialer/app/res/drawable-mdpi/ic_call_arrow.png b/java/com/android/dialer/app/res/drawable-mdpi/ic_call_arrow.png
deleted file mode 100644
index 169cf2934..000000000
--- a/java/com/android/dialer/app/res/drawable-mdpi/ic_call_arrow.png
+++ /dev/null
Binary files differ
diff --git a/java/com/android/dialer/app/res/drawable-xhdpi/ic_call_arrow.png b/java/com/android/dialer/app/res/drawable-xhdpi/ic_call_arrow.png
deleted file mode 100644
index 6f1366018..000000000
--- a/java/com/android/dialer/app/res/drawable-xhdpi/ic_call_arrow.png
+++ /dev/null
Binary files differ
diff --git a/java/com/android/dialer/app/res/drawable-xxhdpi/ic_call_arrow.png b/java/com/android/dialer/app/res/drawable-xxhdpi/ic_call_arrow.png
deleted file mode 100644
index 0364ee015..000000000
--- a/java/com/android/dialer/app/res/drawable-xxhdpi/ic_call_arrow.png
+++ /dev/null
Binary files differ
diff --git a/java/com/android/dialer/app/res/drawable-xxxhdpi/ic_call_arrow.png b/java/com/android/dialer/app/res/drawable-xxxhdpi/ic_call_arrow.png
deleted file mode 100644
index 8243c2536..000000000
--- a/java/com/android/dialer/app/res/drawable-xxxhdpi/ic_call_arrow.png
+++ /dev/null
Binary files differ
diff --git a/java/com/android/dialer/app/res/drawable-xxxhdpi/search_shadow.9.png b/java/com/android/dialer/app/res/drawable-xxxhdpi/search_shadow.9.png
new file mode 100644
index 000000000..ff55620d0
--- /dev/null
+++ b/java/com/android/dialer/app/res/drawable-xxxhdpi/search_shadow.9.png
Binary files differ
diff --git a/java/com/android/dialer/app/res/layout/call_detail.xml b/java/com/android/dialer/app/res/layout/call_detail.xml
deleted file mode 100644
index 58a7bf0dc..000000000
--- a/java/com/android/dialer/app/res/layout/call_detail.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 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.
--->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/call_detail"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@color/background_dialer_call_log">
-
- <!--
- The list view is under everything.
- It contains a first header element which is hidden under the controls UI.
- When scrolling, the controls move up until the name bar hits the top.
- -->
- <ListView
- android:id="@+id/history"
- android:layout_width="match_parent"
- android:layout_height="fill_parent"/>
-
-</FrameLayout>
diff --git a/java/com/android/dialer/app/res/layout/call_detail_footer.xml b/java/com/android/dialer/app/res/layout/call_detail_footer.xml
deleted file mode 100644
index 57713448e..000000000
--- a/java/com/android/dialer/app/res/layout/call_detail_footer.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 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.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <View
- android:layout_width="match_parent"
- android:layout_height="@dimen/divider_line_thickness"
- android:background="@color/call_log_action_divider"/>
-
- <TextView
- android:id="@+id/call_detail_action_copy"
- style="@style/CallDetailActionItemStyle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:drawableStart="@drawable/ic_call_detail_content_copy"
- android:text="@string/action_copy_number_text"/>
-
- <TextView
- android:id="@+id/call_detail_action_edit_before_call"
- style="@style/CallDetailActionItemStyle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:drawableStart="@drawable/ic_call_detail_edit"
- android:text="@string/action_edit_number_before_call"
- android:visibility="gone"/>
-
- <TextView
- android:id="@+id/call_detail_action_report"
- style="@style/CallDetailActionItemStyle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:drawableStart="@drawable/ic_call_detail_report"
- android:text="@string/action_report_number"
- android:visibility="gone"/>
-
-</LinearLayout>
diff --git a/java/com/android/dialer/app/res/layout/call_detail_header.xml b/java/com/android/dialer/app/res/layout/call_detail_header.xml
deleted file mode 100644
index fd85f0af1..000000000
--- a/java/com/android/dialer/app/res/layout/call_detail_header.xml
+++ /dev/null
@@ -1,89 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 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.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/caller_information"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="@dimen/call_detail_top_margin"
- android:paddingBottom="@dimen/call_detail_bottom_margin"
- android:paddingStart="@dimen/call_detail_horizontal_margin"
- android:background="@color/background_dialer_white"
- android:baselineAligned="false"
- android:elevation="@dimen/call_detail_elevation"
- android:focusable="true"
- android:orientation="horizontal">
-
- <QuickContactBadge
- android:id="@+id/quick_contact_photo"
- android:layout_width="@dimen/contact_photo_size"
- android:layout_height="@dimen/contact_photo_size"
- android:layout_marginTop="3dp"
- android:layout_alignParentStart="true"
- android:layout_gravity="top"
- android:focusable="true"/>
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_marginStart="@dimen/call_detail_horizontal_margin"
- android:gravity="center_vertical"
- android:orientation="vertical">
-
- <TextView
- android:id="@+id/caller_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="2dp"
- android:layout_marginBottom="3dp"
- android:includeFontPadding="false"
- android:singleLine="true"
- android:textColor="?android:textColorPrimary"
- android:textSize="@dimen/call_log_primary_text_size"/>
-
- <TextView
- android:id="@+id/caller_number"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="1dp"
- android:singleLine="true"
- android:textColor="?android:textColorSecondary"
- android:textSize="@dimen/call_log_detail_text_size"/>
-
- <TextView
- android:id="@+id/phone_account_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:textColor="?android:textColorSecondary"
- android:textSize="@dimen/call_log_detail_text_size"
- android:visibility="gone"/>
-
- </LinearLayout>
-
- <ImageView
- android:id="@+id/call_back_button"
- android:layout_width="@dimen/call_log_list_item_primary_action_dimen"
- android:layout_height="@dimen/call_log_list_item_primary_action_dimen"
- android:layout_marginEnd="4dp"
- android:background="?android:attr/selectableItemBackgroundBorderless"
- android:contentDescription="@string/description_call_log_call_action"
- android:scaleType="center"
- android:src="@drawable/ic_call_24dp"
- android:tint="@color/call_log_list_item_primary_action_icon_tint"
- android:visibility="gone"/>
-
-</LinearLayout>
diff --git a/java/com/android/dialer/app/res/layout/call_detail_history_item.xml b/java/com/android/dialer/app/res/layout/call_detail_history_item.xml
index 5958ee81c..0184a42f2 100644
--- a/java/com/android/dialer/app/res/layout/call_detail_history_item.xml
+++ b/java/com/android/dialer/app/res/layout/call_detail_history_item.xml
@@ -27,9 +27,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
- <view
+ <com.android.dialer.calllogutils.CallTypeIconsView
android:id="@+id/call_type_icon"
- class="com.android.dialer.app.calllog.CallTypeIconsView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"/>
diff --git a/java/com/android/dialer/app/res/layout/call_log_activity.xml b/java/com/android/dialer/app/res/layout/call_log_activity.xml
new file mode 100644
index 000000000..4e2b1887c
--- /dev/null
+++ b/java/com/android/dialer/app/res/layout/call_log_activity.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/calllog_frame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+ <com.android.contacts.common.list.ViewPagerTabs
+ android:id="@+id/viewpager_header"
+ style="@style/DialtactsActionBarTabTextStyle"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/tab_height"
+ android:layout_gravity="top"
+ android:elevation="@dimen/tab_elevation"
+ android:orientation="horizontal"
+ android:textAllCaps="true"/>
+ <android.support.v4.view.ViewPager
+ android:id="@+id/call_log_pager"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+ <RelativeLayout
+ android:id="@+id/floating_action_button_container"
+ android:layout_width="0dp"
+ android:layout_height="0dp"/>
+</LinearLayout>
diff --git a/java/com/android/dialer/app/res/layout/call_log_list_item.xml b/java/com/android/dialer/app/res/layout/call_log_list_item.xml
index c22ac861d..1592aa928 100644
--- a/java/com/android/dialer/app/res/layout/call_log_list_item.xml
+++ b/java/com/android/dialer/app/res/layout/call_log_list_item.xml
@@ -93,8 +93,7 @@
android:layout_height="wrap_content"
android:orientation="horizontal">
- <view
- class="com.android.dialer.app.calllog.CallTypeIconsView"
+ <com.android.dialer.calllogutils.CallTypeIconsView
android:id="@+id/call_type_icons"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/java/com/android/dialer/app/res/menu/call_log_options.xml b/java/com/android/dialer/app/res/menu/call_log_options.xml
new file mode 100644
index 000000000..e78b72e3c
--- /dev/null
+++ b/java/com/android/dialer/app/res/menu/call_log_options.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:id="@+id/delete_all"
+ android:orderInCategory="1"
+ android:showAsAction="never"
+ android:title="@string/call_log_delete_all"/>
+</menu>
diff --git a/java/com/android/dialer/app/res/menu/dialtacts_options.xml b/java/com/android/dialer/app/res/menu/dialtacts_options.xml
index 434aa81d9..25a3e1811 100644
--- a/java/com/android/dialer/app/res/menu/dialtacts_options.xml
+++ b/java/com/android/dialer/app/res/menu/dialtacts_options.xml
@@ -16,13 +16,17 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
- android:id="@+id/menu_delete_all"
- android:title="@string/call_log_delete_all"/>
+ android:id="@+id/menu_history"
+ android:icon="@drawable/ic_menu_history_lt"
+ android:title="@string/action_menu_call_history_description"/>
<item
android:id="@+id/menu_clear_frequents"
android:title="@string/menu_clear_frequents"/>
<item
android:id="@+id/menu_call_settings"
android:title="@string/dialer_settings_label"/>
+ <item
+ android:id="@+id/menu_simulator_submenu"
+ android:title="@string/simulator_submenu_label"/>
</menu>
diff --git a/java/com/android/dialer/app/res/values/colors.xml b/java/com/android/dialer/app/res/values/colors.xml
index b88e55276..cf6b926be 100644
--- a/java/com/android/dialer/app/res/values/colors.xml
+++ b/java/com/android/dialer/app/res/values/colors.xml
@@ -16,7 +16,6 @@
<resources>
<color name="dialer_red_highlight_color">#ff1744</color>
- <color name="dialer_green_highlight_color">#00c853</color>
<color name="dialer_button_text_color">#fff</color>
<color name="dialer_flat_button_text_color">@color/dialer_theme_color</color>
@@ -84,13 +83,6 @@
as call back, play voicemail, etc. -->
<color name="call_log_action_text">@color/dialer_theme_color</color>
- <!-- Color for missed call icons. -->
- <color name="missed_call">#ff2e58</color>
- <!-- Color for answered or outgoing call icons. -->
- <color name="answered_call">@color/dialer_green_highlight_color</color>
- <!-- Color for blocked call icons. -->
- <color name="blocked_call">@color/dialer_secondary_text_color</color>
-
<color name="dialer_dialpad_touch_tint">@color/dialer_theme_color_20pct</color>
<color name="floating_action_button_touch_tint">#80ffffff</color>
diff --git a/java/com/android/dialer/app/res/values/dimens.xml b/java/com/android/dialer/app/res/values/dimens.xml
index f3fd63350..7da29c7a3 100644
--- a/java/com/android/dialer/app/res/values/dimens.xml
+++ b/java/com/android/dialer/app/res/values/dimens.xml
@@ -28,7 +28,6 @@
<dimen name="call_log_horizontal_margin">8dp</dimen>
<dimen name="call_log_call_action_size">32dp</dimen>
<dimen name="call_log_call_action_width">54dp</dimen>
- <dimen name="call_log_icon_margin">4dp</dimen>
<dimen name="call_log_inner_margin">13dp</dimen>
<dimen name="call_log_outer_margin">8dp</dimen>
<dimen name="call_log_start_margin">8dp</dimen>
@@ -68,7 +67,7 @@
<item name="contact_tile_height_to_width_ratio" type="dimen">76%</item>
<dimen name="contact_tile_text_side_padding">12dp</dimen>
<dimen name="contact_tile_text_bottom_padding">9dp</dimen>
- <dimen name="favorites_row_top_padding">2dp</dimen>
+ <dimen name="favorites_row_top_padding">1dp</dimen>
<dimen name="favorites_row_bottom_padding">0dp</dimen>
<dimen name="favorites_row_start_padding">1dp</dimen>
@@ -143,6 +142,4 @@
<dimen name="blocked_number_search_text_size">14sp</dimen>
<dimen name="blocked_number_settings_description_text_size">14sp</dimen>
<dimen name="blocked_number_header_height">48dp</dimen>
-
- <dimen name="call_type_icon_size">12dp</dimen>
</resources>
diff --git a/java/com/android/dialer/app/res/values/strings.xml b/java/com/android/dialer/app/res/values/strings.xml
index 689ee1ba8..66bf70f1a 100644
--- a/java/com/android/dialer/app/res/values/strings.xml
+++ b/java/com/android/dialer/app/res/values/strings.xml
@@ -55,9 +55,6 @@
<!-- Label for action to unblock a number [CHAR LIMIT=48]-->
<string name="action_unblock_number">Unblock number</string>
- <!-- Menu item in call details used to remove a call or voicemail from the call log. -->
- <string name="call_details_delete">Delete</string>
-
<!-- Label for action to edit a number before calling it. [CHAR LIMIT=48] -->
<string name="action_edit_number_before_call">Edit number before call</string>
@@ -94,7 +91,7 @@
<!-- Missed call notification label, used when there are two or more missed calls -->
<string name="notification_missedCallsTitle">Missed calls</string>
<!-- Missed call notification message used when there are multiple missed calls -->
- <string name="notification_missedCallsMsg"><xliff:g id="num_missed_calls">%s</xliff:g> missed calls</string>
+ <string name="notification_missedCallsMsg"><xliff:g id="num_missed_calls">%d</xliff:g> missed calls</string>
<!-- Message for "call back" Action, which is displayed in the missed call notificaiton.
The user will be able to call back to the person or the phone number.
[CHAR LIMIT=18] -->
@@ -251,15 +248,13 @@
<!-- Label for the dialer app setting page [CHAR LIMIT=30]-->
<string name="dialer_settings_label">Settings</string>
+ <!-- Label for the simulator submenu. This is used to show actions that are useful for development
+ and testing. [CHAR LIMIT=30]-->
+ <string name="simulator_submenu_label">Simulator</string>
+
<!-- Menu item to display all contacts [CHAR LIMIT=30] -->
<string name="menu_allContacts">All contacts</string>
- <!-- Title bar for call detail screen -->
- <string name="callDetailTitle">Call details</string>
-
- <!-- Toast for call detail screen when couldn't read the requested details -->
- <string name="toast_call_detail_error">Details not available</string>
-
<!-- Item label: jump to the in-call DTMF dialpad.
(Part of a list of options shown in the dialer when another call
is already in progress.) -->
@@ -275,52 +270,6 @@
is already in progress.) -->
<string name="dialer_addAnotherCall">Add call</string>
- <!-- Title for incoming call type. [CHAR LIMIT=40] -->
- <string name="type_incoming">Incoming call</string>
-
- <!-- Title for incoming call which was transferred to another device. [CHAR LIMIT=60] -->
- <string name="type_incoming_pulled">Incoming call transferred to another device</string>
-
- <!-- Title for outgoing call type. [CHAR LIMIT=40] -->
- <string name="type_outgoing">Outgoing call</string>
-
- <!-- Title for outgoing call which was transferred to another device. [CHAR LIMIT=60] -->
- <string name="type_outgoing_pulled">Outgoing call transferred to another device</string>
-
- <!-- Title for missed call type. [CHAR LIMIT=40] -->
- <string name="type_missed">Missed call</string>
-
- <!-- Title for incoming video call in call details screen [CHAR LIMIT=60] -->
- <string name="type_incoming_video">Incoming video call</string>
-
- <!-- Title for incoming video call in call details screen which was transferred to another device.
- [CHAR LIMIT=60] -->
- <string name="type_incoming_video_pulled">Incoming video call transferred to another device</string>
-
- <!-- Title for outgoing video call in call details screen [CHAR LIMIT=60] -->
- <string name="type_outgoing_video">Outgoing video call</string>
-
- <!-- Title for outgoing video call in call details screen which was transferred to another device.
- [CHAR LIMIT=60] -->
- <string name="type_outgoing_video_pulled">Outgoing video call transferred to another device</string>
-
- <!-- Title for missed video call in call details screen [CHAR LIMIT=60] -->
- <string name="type_missed_video">Missed video call</string>
-
- <!-- Title for voicemail details screen -->
- <string name="type_voicemail">Voicemail</string>
-
- <!-- Title for rejected call type. [CHAR LIMIT=40] -->
- <string name="type_rejected">Declined call</string>
-
- <!-- Title for blocked call type. [CHAR LIMIT=40] -->
- <string name="type_blocked">Blocked call</string>
-
- <!-- Title for "answered elsewhere" call type. This will happen if a call was ringing
- simultaneously on multiple devices, and the user answered it on a device other than the
- current device. [CHAR LIMIT=60] -->
- <string name="type_answered_elsewhere">Call answered on another device</string>
-
<!-- Description for incoming calls going to voice mail vs. not -->
<string name="actionIncomingCall">Incoming calls</string>
@@ -623,28 +572,10 @@
[CHAR LIMIT=NONE] -->
<string name="description_outgoing_call">Call to <xliff:g example="John Smith" id="nameOrNumber">^1</xliff:g>, <xliff:g example="Mobile" id="typeOrLocation">^2</xliff:g>, <xliff:g example="2 min ago" id="timeOfCall">^3</xliff:g>, <xliff:g example="on SIM 1" id="phoneAccount">^4</xliff:g>.</string>
- <!-- String describing the phone account the call was made on or to. This string will be used
- in description_incoming_missed_call, description_incoming_answered_call, and
- description_outgoing_call.
- Note: AccessibilityServices uses this attribute to announce what the view represents.
- [CHAR LIMIT=NONE] -->
- <string name="description_phone_account">on <xliff:g example="SIM 1" id="phoneAccount">^1</xliff:g></string>
-
- <!-- String describing the secondary line number the call was received via.
- Note: AccessibilityServices use this attribute to announce what the view represents.
- [CHAR LIMIT=NONE]-->
- <string name="description_via_number">via <xliff:g example="(555) 555-5555" id="number">%1$s</xliff:g></string>
-
<!-- TextView text item showing the secondary line number the call was received via.
[CHAR LIMIT=NONE]-->
<string name="call_log_via_number">via <xliff:g example="(555) 555-5555" id="number">%1$s</xliff:g></string>
- <!-- String describing the PhoneAccount and via number that a call was received on, if both are
- visible.
- Note: AccessibilityServices use this attribute to announce what the view represents.
- [CHAR LIMIT=NONE]-->
- <string name="description_via_number_phone_account">on <xliff:g example="SIM 1" id="phoneAccount">%1$s</xliff:g>, via <xliff:g example="(555) 555-5555" id="number">%2$s</xliff:g></string>
-
<!-- The order of the PhoneAccount and via number that a call was received on,
if both are visible.
[CHAR LIMIT=NONE]-->
@@ -827,6 +758,9 @@
<!-- Label for the blocked numbers settings section [CHAR LIMIT=30] -->
<string name="manage_blocked_numbers_label">Call blocking</string>
+ <!-- Label for the voicemail settings section [CHAR LIMIT=30] -->
+ <string name="voicemail_settings_label">Voicemail</string>
+
<!-- Label for a section describing that call blocking is temporarily disabled because an
emergency call was made. [CHAR LIMIT=50] -->
<string name="blocked_numbers_disabled_emergency_header_label">
@@ -955,6 +889,6 @@
<string name="spam_number_call_log_label">Spam</string>
<!-- Shown as a message that notifies the user enriched calling isn't working -->
- <string name="call_composer_connection_failed"><xliff:g id="feature">%1$s</xliff:g> unavailable right now</string>
+ <string name="call_composer_connection_failed"><xliff:g id="name">%1$s</xliff:g> is offline and can\'t be reached</string>
</resources>
diff --git a/java/com/android/dialer/app/res/values/styles.xml b/java/com/android/dialer/app/res/values/styles.xml
index ac4422ba2..24521ddaf 100644
--- a/java/com/android/dialer/app/res/values/styles.xml
+++ b/java/com/android/dialer/app/res/values/styles.xml
@@ -111,11 +111,6 @@
<item name="android:fastScrollTrackDrawable">@null</item>
</style>
- <style name="CallDetailActivityTheme" parent="DialtactsThemeWithoutActionBarOverlay">
- <item name="android:windowBackground">@color/background_dialer_results</item>
- <item name="android:actionOverflowButtonStyle">@style/DialtactsActionBarOverflowWhite</item>
- </style>
-
<style name="CallDetailActionItemStyle">
<item name="android:foreground">?android:attr/selectableItemBackground</item>
<item name="android:clickable">true</item>
diff --git a/java/com/android/dialer/app/settings/DialerSettingsActivity.java b/java/com/android/dialer/app/settings/DialerSettingsActivity.java
index b04674013..bbf1cfae5 100644
--- a/java/com/android/dialer/app/settings/DialerSettingsActivity.java
+++ b/java/com/android/dialer/app/settings/DialerSettingsActivity.java
@@ -33,8 +33,11 @@ import com.android.dialer.app.R;
import com.android.dialer.blocking.FilteredNumberCompat;
import com.android.dialer.compat.CompatUtils;
import com.android.dialer.proguard.UsedByReflection;
+import com.android.voicemail.VoicemailComponent;
import java.util.List;
+/** Activity for dialer settings. */
+@SuppressWarnings("FragmentInjection") // Activity not exported
@UsedByReflection(value = "AndroidManifest-app.xml")
public class DialerSettingsActivity extends AppCompatPreferenceActivity {
@@ -115,6 +118,16 @@ public class DialerSettingsActivity extends AppCompatPreferenceActivity {
target.add(blockedCallsHeader);
migrationStatusOnBuildHeaders = FilteredNumberCompat.hasMigratedToNewBlocking(this);
}
+
+ String voicemailSettingsFragment =
+ VoicemailComponent.get(this).getVoicemailClient().getSettingsFragment();
+ if (isPrimaryUser && voicemailSettingsFragment != null) {
+ Header voicemailSettings = new Header();
+ voicemailSettings.titleRes = R.string.voicemail_settings_label;
+ voicemailSettings.fragment = voicemailSettingsFragment;
+ target.add(voicemailSettings);
+ }
+
if (isPrimaryUser
&& (TelephonyManagerCompat.isTtyModeSupported(telephonyManager)
|| TelephonyManagerCompat.isHearingAidCompatibilitySupported(telephonyManager))) {
diff --git a/java/com/android/dialer/app/voicemail/VoicemailPlaybackLayout.java b/java/com/android/dialer/app/voicemail/VoicemailPlaybackLayout.java
index fc6a37608..f40ed2794 100644
--- a/java/com/android/dialer/app/voicemail/VoicemailPlaybackLayout.java
+++ b/java/com/android/dialer/app/voicemail/VoicemailPlaybackLayout.java
@@ -30,7 +30,6 @@ import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
-import com.android.dialer.app.PhoneCallDetails;
import com.android.dialer.app.R;
import com.android.dialer.app.calllog.CallLogAsyncTaskUtil;
import com.android.dialer.app.calllog.CallLogListItemViewHolder;
@@ -347,16 +346,10 @@ public class VoicemailPlaybackLayout extends LinearLayout
}
@Override
- public void onDeleteCall() {}
-
- @Override
public void onDeleteVoicemail() {
mPresenter.onVoicemailDeletedInDatabase();
}
- @Override
- public void onGetCallDetails(PhoneCallDetails[] details) {}
-
private String getString(int resId) {
return mContext.getString(resId);
}
diff --git a/java/com/android/dialer/app/voicemail/VoicemailPlaybackPresenter.java b/java/com/android/dialer/app/voicemail/VoicemailPlaybackPresenter.java
index 657022291..994160ff9 100644
--- a/java/com/android/dialer/app/voicemail/VoicemailPlaybackPresenter.java
+++ b/java/com/android/dialer/app/voicemail/VoicemailPlaybackPresenter.java
@@ -39,6 +39,7 @@ import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.support.v4.content.FileProvider;
import android.text.TextUtils;
+import android.view.View;
import android.view.WindowManager.LayoutParams;
import android.webkit.MimeTypeMap;
import com.android.common.io.MoreCloseables;
@@ -47,8 +48,11 @@ import com.android.dialer.app.calllog.CallLogListItemViewHolder;
import com.android.dialer.common.Assert;
import com.android.dialer.common.AsyncTaskExecutor;
import com.android.dialer.common.AsyncTaskExecutors;
+import com.android.dialer.common.ConfigProviderBindings;
import com.android.dialer.common.LogUtil;
import com.android.dialer.constants.Constants;
+import com.android.dialer.logging.Logger;
+import com.android.dialer.logging.nano.DialerImpression;
import com.android.dialer.phonenumbercache.CallLogQuery;
import com.google.common.io.ByteStreams;
import java.io.File;
@@ -71,9 +75,9 @@ import javax.annotation.concurrent.ThreadSafe;
* assumptions about the behaviors and lifecycle of the call log, in particular in the {@link
* CallLogFragment} and {@link CallLogAdapter}.
*
- * <p>This controls a single {@link com.android.dialer.voicemail.VoicemailPlaybackLayout}. A single
- * instance can be reused for different such layouts, using {@link #setPlaybackView}. This is to
- * facilitate reuse across different voicemail call log entries.
+ * <p>This controls a single {@link com.android.dialer.app.voicemail.VoicemailPlaybackLayout}. A
+ * single instance can be reused for different such layouts, using {@link #setPlaybackView}. This is
+ * to facilitate reuse across different voicemail call log entries.
*
* <p>This class is not thread safe. The thread policy for this class is thread-confinement, all
* calls into this class from outside must be done from the main UI thread.
@@ -103,6 +107,8 @@ public class VoicemailPlaybackPresenter
private static final String IS_SPEAKERPHONE_ON_KEY =
VoicemailPlaybackPresenter.class.getName() + ".IS_SPEAKER_PHONE_ON";
private static final String VOICEMAIL_SHARE_FILE_NAME_DATE_FORMAT = "MM-dd-yy_hhmmaa";
+ private static final String CONFIG_SHARE_VOICEMAIL_ALLOWED = "share_voicemail_allowed";
+
private static VoicemailPlaybackPresenter sInstance;
private static ScheduledExecutorService mScheduledExecutorService;
/**
@@ -138,6 +144,7 @@ public class VoicemailPlaybackPresenter
private PowerManager.WakeLock mProximityWakeLock;
private VoicemailAudioManager mVoicemailAudioManager;
private OnVoicemailDeletedListener mOnVoicemailDeletedListener;
+ private View shareVoicemailButtonView;
/** Initialize variables which are activity-independent and state-independent. */
protected VoicemailPlaybackPresenter(Activity activity) {
@@ -222,11 +229,17 @@ public class VoicemailPlaybackPresenter
/** Specify the view which this presenter controls and the voicemail to prepare to play. */
public void setPlaybackView(
- PlaybackView view, long rowId, Uri voicemailUri, final boolean startPlayingImmediately) {
+ PlaybackView view,
+ long rowId,
+ Uri voicemailUri,
+ final boolean startPlayingImmediately,
+ View shareVoicemailButtonView) {
mRowId = rowId;
mView = view;
mView.setPresenter(this, voicemailUri);
mView.onSpeakerphoneOn(mIsSpeakerphoneOn);
+ this.shareVoicemailButtonView = shareVoicemailButtonView;
+ showShareVoicemailButton(false);
// Handles cases where the same entry is binded again when scrolling in list, or where
// the MediaPlayer was retained after an orientation change.
@@ -236,6 +249,7 @@ public class VoicemailPlaybackPresenter
// media player.
mPosition = mMediaPlayer.getCurrentPosition();
onPrepared(mMediaPlayer);
+ showShareVoicemailButton(true);
} else {
if (!voicemailUri.equals(mVoicemailUri)) {
mVoicemailUri = voicemailUri;
@@ -247,19 +261,17 @@ public class VoicemailPlaybackPresenter
* it if the content is not available.
*/
checkForContent(
- new OnContentCheckedListener() {
- @Override
- public void onContentChecked(boolean hasContent) {
- if (hasContent) {
- prepareContent();
- } else {
- if (startPlayingImmediately) {
- requestContent(PLAYBACK_REQUEST);
- }
- if (mView != null) {
- mView.resetSeekBar();
- mView.setClipPosition(0, mDuration.get());
- }
+ hasContent -> {
+ if (hasContent) {
+ showShareVoicemailButton(true);
+ prepareContent();
+ } else {
+ if (startPlayingImmediately) {
+ requestContent(PLAYBACK_REQUEST);
+ }
+ if (mView != null) {
+ mView.resetSeekBar();
+ mView.setClipPosition(0, mDuration.get());
}
}
});
@@ -547,6 +559,7 @@ public class VoicemailPlaybackPresenter
mPosition = 0;
mIsPlaying = false;
+ showShareVoicemailButton(false);
}
/** After done playing the voicemail clip, reset the clip position to the start. */
@@ -600,18 +613,16 @@ public class VoicemailPlaybackPresenter
* timeout, but succeeded.
*/
checkForContent(
- new OnContentCheckedListener() {
- @Override
- public void onContentChecked(boolean hasContent) {
- if (!hasContent) {
- // No local content, download from server. Queue playing if the request was
- // issued,
- mIsPlaying = requestContent(PLAYBACK_REQUEST);
- } else {
- // Queue playing once the media play loaded the content.
- mIsPlaying = true;
- prepareContent();
- }
+ hasContent -> {
+ if (!hasContent) {
+ // No local content, download from server. Queue playing if the request was
+ // issued,
+ mIsPlaying = requestContent(PLAYBACK_REQUEST);
+ } else {
+ showShareVoicemailButton(true);
+ // Queue playing once the media play loaded the content.
+ mIsPlaying = true;
+ prepareContent();
}
});
return;
@@ -813,6 +824,20 @@ public class VoicemailPlaybackPresenter
sInstance = null;
}
+ private void showShareVoicemailButton(boolean show) {
+ if (isShareVoicemailAllowed(mContext) && shareVoicemailButtonView != null) {
+ if (show) {
+ Logger.get(mContext).logImpression(DialerImpression.Type.VVM_SHARE_VISIBLE);
+ }
+ LogUtil.d("VoicemailPlaybackPresenter.showShareVoicemailButton", "show: %b", show);
+ shareVoicemailButtonView.setVisibility(show ? View.VISIBLE : View.GONE);
+ }
+ }
+
+ private static boolean isShareVoicemailAllowed(Context context) {
+ return ConfigProviderBindings.get(context).getBoolean(CONFIG_SHARE_VOICEMAIL_ALLOWED, true);
+ }
+
/**
* Share voicemail to be opened by user selected apps. This method will collect information, copy
* voicemail to a temporary file in background and launch a chooser intent to share it.
@@ -1041,6 +1066,7 @@ public class VoicemailPlaybackPresenter
public void onPostExecute(Boolean hasContent) {
if (hasContent && mContext != null && mIsWaitingForResult.getAndSet(false)) {
mContext.getContentResolver().unregisterContentObserver(FetchResultHandler.this);
+ showShareVoicemailButton(true);
prepareContent();
}
}
diff --git a/java/com/android/dialer/app/voicemail/error/OmtpVoicemailMessageCreator.java b/java/com/android/dialer/app/voicemail/error/OmtpVoicemailMessageCreator.java
index e36406d17..190426e6e 100644
--- a/java/com/android/dialer/app/voicemail/error/OmtpVoicemailMessageCreator.java
+++ b/java/com/android/dialer/app/voicemail/error/OmtpVoicemailMessageCreator.java
@@ -17,10 +17,18 @@
package com.android.dialer.app.voicemail.error;
import android.content.Context;
+import android.preference.PreferenceManager;
import android.provider.VoicemailContract.Status;
import android.support.annotation.Nullable;
+import android.telecom.PhoneAccountHandle;
import com.android.dialer.app.voicemail.error.VoicemailErrorMessage.Action;
+import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
+import com.android.dialer.common.PerAccountSharedPreferences;
+import com.android.dialer.logging.Logger;
+import com.android.dialer.logging.nano.DialerImpression;
+import com.android.voicemail.VoicemailClient;
+import com.android.voicemail.VoicemailComponent;
import java.util.ArrayList;
import java.util.List;
@@ -32,14 +40,18 @@ public class OmtpVoicemailMessageCreator {
private static final float QUOTA_NEAR_FULL_THRESHOLD = 0.9f;
private static final float QUOTA_FULL_THRESHOLD = 0.99f;
+ protected static final String VOICEMAIL_PROMO_DISMISSED_KEY =
+ "voicemail_archive_promo_was_dismissed";
+ protected static final String VOICEMAIL_PROMO_ALMOST_FULL_DISMISSED_KEY =
+ "voicemail_archive_almost_full_promo_was_dismissed";
@Nullable
- public static VoicemailErrorMessage create(Context context, VoicemailStatus status) {
+ public static VoicemailErrorMessage create(
+ Context context, VoicemailStatus status, final VoicemailStatusReader statusReader) {
if (Status.CONFIGURATION_STATE_OK == status.configurationState
&& Status.DATA_CHANNEL_STATE_OK == status.dataChannelState
&& Status.NOTIFICATION_CHANNEL_STATE_OK == status.notificationChannelState) {
-
- return checkQuota(context, status);
+ return checkQuota(context, status, statusReader);
}
// Initial state when the source is activating. Other error might be written into data and
// notification channel during activation.
@@ -120,24 +132,98 @@ public class OmtpVoicemailMessageCreator {
}
@Nullable
- private static VoicemailErrorMessage checkQuota(Context context, VoicemailStatus status) {
+ private static VoicemailErrorMessage checkQuota(
+ Context context, VoicemailStatus status, VoicemailStatusReader statusReader) {
if (status.quotaOccupied != Status.QUOTA_UNAVAILABLE
&& status.quotaTotal != Status.QUOTA_UNAVAILABLE) {
+
+ PhoneAccountHandle phoneAccountHandle = status.getPhoneAccountHandle();
+
+ VoicemailClient voicemailClient = VoicemailComponent.get(context).getVoicemailClient();
+
+ PerAccountSharedPreferences sharedPreferenceForAccount =
+ new PerAccountSharedPreferences(
+ context, phoneAccountHandle, PreferenceManager.getDefaultSharedPreferences(context));
+
+ boolean isVoicemailArchiveEnabled =
+ VoicemailComponent.get(context)
+ .getVoicemailClient()
+ .isVoicemailArchiveEnabled(context, phoneAccountHandle);
+
if ((float) status.quotaOccupied / (float) status.quotaTotal >= QUOTA_FULL_THRESHOLD) {
- return new VoicemailErrorMessage(
+ return createInboxErrorMessage(
+ context,
+ status,
+ status.getPhoneAccountHandle(),
+ statusReader,
+ sharedPreferenceForAccount,
+ voicemailClient,
+ isVoicemailArchiveEnabled,
+ context.getString(R.string.voicemail_error_inbox_full_turn_archive_on_title),
+ context.getString(R.string.voicemail_error_inbox_full_turn_archive_on_message),
context.getString(R.string.voicemail_error_inbox_full_title),
- context.getString(R.string.voicemail_error_inbox_full_message));
+ context.getString(R.string.voicemail_error_inbox_full_message),
+ VOICEMAIL_PROMO_DISMISSED_KEY);
}
if ((float) status.quotaOccupied / (float) status.quotaTotal >= QUOTA_NEAR_FULL_THRESHOLD) {
- return new VoicemailErrorMessage(
+ return createInboxErrorMessage(
+ context,
+ status,
+ status.getPhoneAccountHandle(),
+ statusReader,
+ sharedPreferenceForAccount,
+ voicemailClient,
+ isVoicemailArchiveEnabled,
+ context.getString(R.string.voicemail_error_inbox_almost_full_turn_archive_on_title),
+ context.getString(R.string.voicemail_error_inbox_almost_full_turn_archive_on_message),
context.getString(R.string.voicemail_error_inbox_near_full_title),
- context.getString(R.string.voicemail_error_inbox_near_full_message));
+ context.getString(R.string.voicemail_error_inbox_near_full_message),
+ VOICEMAIL_PROMO_ALMOST_FULL_DISMISSED_KEY);
}
}
return null;
}
+ private static VoicemailErrorMessage createInboxErrorMessage(
+ Context context,
+ VoicemailStatus status,
+ PhoneAccountHandle phoneAccountHandle,
+ VoicemailStatusReader statusReader,
+ PerAccountSharedPreferences sharedPreferenceForAccount,
+ VoicemailClient voicemailClient,
+ boolean isVoicemailArchiveEnabled,
+ String promoTitle,
+ String promoMessage,
+ String nonPromoTitle,
+ String nonPromoMessage,
+ String preferenceKey) {
+
+ boolean wasPromoDismissed = sharedPreferenceForAccount.getBoolean(preferenceKey, false);
+
+ if (!wasPromoDismissed && !isVoicemailArchiveEnabled) {
+ logArchiveImpression(
+ context,
+ preferenceKey,
+ DialerImpression.Type.VVM_USER_SHOWN_VM_ALMOST_FULL_PROMO,
+ DialerImpression.Type.VVM_USER_SHOWN_VM_FULL_PROMO);
+ return new VoicemailErrorMessage(
+ promoTitle,
+ promoMessage,
+ VoicemailErrorMessage.createDismissTurnArchiveOnAction(
+ context, statusReader, sharedPreferenceForAccount, preferenceKey),
+ VoicemailErrorMessage.createTurnArchiveOnAction(
+ context, status, voicemailClient, phoneAccountHandle, preferenceKey));
+ } else {
+ logArchiveImpression(
+ context,
+ preferenceKey,
+ DialerImpression.Type.VVM_USER_SHOWN_VM_ALMOST_FULL_ERROR_MESSAGE,
+ DialerImpression.Type.VVM_USER_SHOWN_VM_FULL_ERROR_MESSAGE);
+ return new VoicemailErrorMessage(nonPromoTitle, nonPromoMessage);
+ }
+ }
+
@Nullable
private static VoicemailErrorMessage createNoSignalMessage(
Context context, VoicemailStatus status) {
@@ -174,4 +260,15 @@ public class OmtpVoicemailMessageCreator {
}
return new VoicemailErrorMessage(title, description, actions);
}
+
+ protected static void logArchiveImpression(
+ Context context, String preference, int vmAlmostFullImpression, int vmFullImpression) {
+ if (preference.equals(VOICEMAIL_PROMO_DISMISSED_KEY)) {
+ Logger.get(context).logImpression(vmAlmostFullImpression);
+ } else if (preference.equals(VOICEMAIL_PROMO_ALMOST_FULL_DISMISSED_KEY)) {
+ Logger.get(context).logImpression(vmFullImpression);
+ } else {
+ throw Assert.createAssertionFailException("Invalid preference key " + preference);
+ }
+ }
}
diff --git a/java/com/android/dialer/app/voicemail/error/VoicemailErrorMessage.java b/java/com/android/dialer/app/voicemail/error/VoicemailErrorMessage.java
index 61572008b..f85d91186 100644
--- a/java/com/android/dialer/app/voicemail/error/VoicemailErrorMessage.java
+++ b/java/com/android/dialer/app/voicemail/error/VoicemailErrorMessage.java
@@ -22,12 +22,15 @@ import android.provider.Settings;
import android.provider.VoicemailContract;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.telecom.PhoneAccountHandle;
import android.telephony.TelephonyManager;
import android.view.View;
import android.view.View.OnClickListener;
+import com.android.dialer.common.PerAccountSharedPreferences;
import com.android.dialer.logging.Logger;
import com.android.dialer.logging.nano.DialerImpression;
import com.android.dialer.util.CallUtil;
+import com.android.voicemail.VoicemailClient;
import java.util.Arrays;
import java.util.List;
@@ -175,4 +178,52 @@ public class VoicemailErrorMessage {
}
});
}
+
+ @NonNull
+ public static Action createTurnArchiveOnAction(
+ final Context context,
+ final VoicemailStatus status,
+ VoicemailClient voicemailClient,
+ PhoneAccountHandle phoneAccountHandle,
+ String preference) {
+ return new Action(
+ context.getString(R.string.voicemail_action_turn_archive_on),
+ new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ OmtpVoicemailMessageCreator.logArchiveImpression(
+ context,
+ preference,
+ DialerImpression.Type.VVM_USER_ENABLED_ARCHIVE_FROM_VM_FULL_PROMO,
+ DialerImpression.Type.VVM_USER_ENABLED_ARCHIVE_FROM_VM_ALMOST_FULL_PROMO);
+
+ voicemailClient.setVoicemailArchiveEnabled(context, phoneAccountHandle, true);
+ Intent intent = new Intent(VoicemailContract.ACTION_SYNC_VOICEMAIL);
+ intent.setPackage(status.sourcePackage);
+ context.sendBroadcast(intent);
+ }
+ });
+ }
+
+ @NonNull
+ public static Action createDismissTurnArchiveOnAction(
+ final Context context,
+ VoicemailStatusReader statusReader,
+ PerAccountSharedPreferences sharedPreferenceForAccount,
+ String preferenceKeyToUpdate) {
+ return new Action(
+ context.getString(R.string.voicemail_action_dimiss),
+ new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ OmtpVoicemailMessageCreator.logArchiveImpression(
+ context,
+ preferenceKeyToUpdate,
+ DialerImpression.Type.VVM_USER_DISMISSED_VM_FULL_PROMO,
+ DialerImpression.Type.VVM_USER_DISMISSED_VM_ALMOST_FULL_PROMO);
+ sharedPreferenceForAccount.edit().putBoolean(preferenceKeyToUpdate, true);
+ statusReader.refresh();
+ }
+ });
+ }
}
diff --git a/java/com/android/dialer/app/voicemail/error/VoicemailErrorMessageCreator.java b/java/com/android/dialer/app/voicemail/error/VoicemailErrorMessageCreator.java
index 5ebef801d..7dc18f043 100644
--- a/java/com/android/dialer/app/voicemail/error/VoicemailErrorMessageCreator.java
+++ b/java/com/android/dialer/app/voicemail/error/VoicemailErrorMessageCreator.java
@@ -39,7 +39,7 @@ public class VoicemailErrorMessageCreator {
case Vvm3VoicemailMessageCreator.VVM_TYPE_VVM3:
return Vvm3VoicemailMessageCreator.create(context, status, statusReader);
default:
- return OmtpVoicemailMessageCreator.create(context, status);
+ return OmtpVoicemailMessageCreator.create(context, status, statusReader);
}
}
}
diff --git a/java/com/android/dialer/app/voicemail/error/VoicemailStatus.java b/java/com/android/dialer/app/voicemail/error/VoicemailStatus.java
index a09941de2..c429d6dcc 100644
--- a/java/com/android/dialer/app/voicemail/error/VoicemailStatus.java
+++ b/java/com/android/dialer/app/voicemail/error/VoicemailStatus.java
@@ -16,6 +16,7 @@
package com.android.dialer.app.voicemail.error;
+import android.content.ComponentName;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
@@ -25,6 +26,7 @@ import android.provider.Settings;
import android.provider.Settings.Global;
import android.provider.VoicemailContract.Status;
import android.support.annotation.Nullable;
+import android.telecom.PhoneAccountHandle;
import android.telephony.TelephonyManager;
import com.android.dialer.database.VoicemailStatusQuery;
@@ -257,4 +259,9 @@ public class VoicemailStatus {
}
return cursor.getString(index);
}
+
+ public PhoneAccountHandle getPhoneAccountHandle() {
+ return new PhoneAccountHandle(
+ ComponentName.unflattenFromString(phoneAccountComponentName), phoneAccountId);
+ }
}
diff --git a/java/com/android/dialer/app/voicemail/error/Vvm3VoicemailMessageCreator.java b/java/com/android/dialer/app/voicemail/error/Vvm3VoicemailMessageCreator.java
index 6e9405cbf..356131bb3 100644
--- a/java/com/android/dialer/app/voicemail/error/Vvm3VoicemailMessageCreator.java
+++ b/java/com/android/dialer/app/voicemail/error/Vvm3VoicemailMessageCreator.java
@@ -269,7 +269,7 @@ public class Vvm3VoicemailMessageCreator {
VoicemailErrorMessage.createSetPinAction(context));
}
- return OmtpVoicemailMessageCreator.create(context, status);
+ return OmtpVoicemailMessageCreator.create(context, status, statusReader);
}
@NonNull
diff --git a/java/com/android/dialer/app/voicemail/error/res/layout/voicemai_error_message_fragment.xml b/java/com/android/dialer/app/voicemail/error/res/layout/voicemai_error_message_fragment.xml
index 0dfb1c2fd..4a40857a0 100644
--- a/java/com/android/dialer/app/voicemail/error/res/layout/voicemai_error_message_fragment.xml
+++ b/java/com/android/dialer/app/voicemail/error/res/layout/voicemai_error_message_fragment.xml
@@ -48,7 +48,6 @@
<TextView
android:id="@+id/error_card_details"
- android:autoLink="web"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:lineSpacingExtra="@dimen/alert_line_spacing"
diff --git a/java/com/android/dialer/app/voicemail/error/res/layout/voicemail_tos_fragment.xml b/java/com/android/dialer/app/voicemail/error/res/layout/voicemail_tos_fragment.xml
index 2b9d17328..c193eaa47 100644
--- a/java/com/android/dialer/app/voicemail/error/res/layout/voicemail_tos_fragment.xml
+++ b/java/com/android/dialer/app/voicemail/error/res/layout/voicemail_tos_fragment.xml
@@ -31,7 +31,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="16dp"
- android:autoLink="web"
android:text="@string/verizon_terms_and_conditions_1.1_english"
android:textColor="@color/secondary_text_color"
android:textSize="@dimen/call_log_detail_text_size"/>
diff --git a/java/com/android/dialer/app/voicemail/error/res/values/strings.xml b/java/com/android/dialer/app/voicemail/error/res/values/strings.xml
index 1d39b9dcb..94d3dba11 100644
--- a/java/com/android/dialer/app/voicemail/error/res/values/strings.xml
+++ b/java/com/android/dialer/app/voicemail/error/res/values/strings.xml
@@ -54,6 +54,11 @@
<string name="voicemail_error_inbox_full_title">Can\'t receive new voicemails</string>
<string name="voicemail_error_inbox_full_message">Your inbox is full. Try deleting some messages to receive new voicemail.</string>
+ <string name="voicemail_error_inbox_full_turn_archive_on_title">Turn on extra storage and backup</string>
+ <string name="voicemail_error_inbox_full_turn_archive_on_message">Your mailbox is full. To free up space, turn on extra storage so Google can manage and backup your voicemail messages.</string>
+
+ <string name="voicemail_error_inbox_almost_full_turn_archive_on_title">Turn on extra storage and backup</string>
+ <string name="voicemail_error_inbox_almost_full_turn_archive_on_message">Your mailbox is almost full. To free up space, turn on extra storage so Google can manage and backup your voicemail messages.</string>
<string name="voicemail_error_pin_not_set_title">Set your voicemail PIN</string>
<string name="voicemail_error_pin_not_set_message">You\'ll need a voicemail PIN anytime you call to access your voicemail.</string>
@@ -63,6 +68,8 @@
<string name="voicemail_action_turn_off_airplane_mode">Airplane Mode Settings</string>
<string name="voicemail_action_set_pin">Set PIN</string>
<string name="voicemail_action_retry">Try Again</string>
+ <string name="voicemail_action_turn_archive_on">Turn on</string>
+ <string name="voicemail_action_dimiss">No Thanks</string>
<string name="voicemail_action_sync">Sync</string>
<string name="voicemail_action_call_voicemail">Call Voicemail</string>
<string name="voicemail_action_call_customer_support">Call Customer Support</string>
diff --git a/java/com/android/dialer/app/widget/ActionBarController.java b/java/com/android/dialer/app/widget/ActionBarController.java
index 7fe056c51..d0eb326ab 100644
--- a/java/com/android/dialer/app/widget/ActionBarController.java
+++ b/java/com/android/dialer/app/widget/ActionBarController.java
@@ -16,12 +16,9 @@
package com.android.dialer.app.widget;
import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.os.Bundle;
-import android.support.annotation.VisibleForTesting;
-import android.util.Log;
import com.android.dialer.animation.AnimUtils.AnimationCallback;
-import com.android.dialer.app.DialtactsActivity;
+import com.android.dialer.common.LogUtil;
/**
* Controls the various animated properties of the actionBar: showing/hiding, fading/revealing, and
@@ -30,8 +27,6 @@ import com.android.dialer.app.DialtactsActivity;
*/
public class ActionBarController {
- public static final boolean DEBUG = DialtactsActivity.DEBUG;
- public static final String TAG = "ActionBarController";
private static final String KEY_IS_SLID_UP = "key_actionbar_is_slid_up";
private static final String KEY_IS_FADED_OUT = "key_actionbar_is_faded_out";
private static final String KEY_IS_EXPANDED = "key_actionbar_is_expanded";
@@ -66,9 +61,8 @@ public class ActionBarController {
/** Called when the user has tapped on the collapsed search box, to start a new search query. */
public void onSearchBoxTapped() {
- if (DEBUG) {
- Log.d(TAG, "OnSearchBoxTapped: isInSearchUi " + mActivityUi.isInSearchUi());
- }
+ LogUtil.d(
+ "ActionBarController.onSearchBoxTapped", "isInSearchUi " + mActivityUi.isInSearchUi());
if (!mActivityUi.isInSearchUi()) {
mSearchBox.expand(true /* animate */, true /* requestFocus */);
}
@@ -76,16 +70,11 @@ public class ActionBarController {
/** Called when search UI has been exited for some reason. */
public void onSearchUiExited() {
- if (DEBUG) {
- Log.d(
- TAG,
- "OnSearchUIExited: isExpanded "
- + mSearchBox.isExpanded()
- + " isFadedOut: "
- + mSearchBox.isFadedOut()
- + " shouldShowActionBar: "
- + mActivityUi.shouldShowActionBar());
- }
+ LogUtil.d(
+ "ActionBarController.onSearchUIExited",
+ "isExpanded: %b, isFadedOut %b",
+ mSearchBox.isExpanded(),
+ mSearchBox.isFadedOut());
if (mSearchBox.isExpanded()) {
mSearchBox.collapse(true /* animate */);
}
@@ -93,11 +82,7 @@ public class ActionBarController {
mSearchBox.fadeIn();
}
- if (mActivityUi.shouldShowActionBar()) {
- slideActionBar(false /* slideUp */, false /* animate */);
- } else {
- slideActionBar(true /* slideUp */, false /* animate */);
- }
+ slideActionBar(false /* slideUp */, false /* animate */);
}
/**
@@ -105,18 +90,13 @@ public class ActionBarController {
* state changes have actually occurred.
*/
public void onDialpadDown() {
- if (DEBUG) {
- Log.d(
- TAG,
- "OnDialpadDown: isInSearchUi "
- + mActivityUi.isInSearchUi()
- + " hasSearchQuery: "
- + mActivityUi.hasSearchQuery()
- + " isFadedOut: "
- + mSearchBox.isFadedOut()
- + " isExpanded: "
- + mSearchBox.isExpanded());
- }
+ LogUtil.d(
+ "ActionBarController.onDialpadDown",
+ "isInSearchUi: %b, hasSearchQuery: %b, isFadedOut: %b, isExpanded: %b",
+ mActivityUi.isInSearchUi(),
+ mActivityUi.hasSearchQuery(),
+ mSearchBox.isFadedOut(),
+ mSearchBox.isExpanded());
if (mActivityUi.isInSearchUi()) {
if (mActivityUi.hasSearchQuery()) {
if (mSearchBox.isFadedOut()) {
@@ -137,9 +117,7 @@ public class ActionBarController {
* state changes have actually occurred.
*/
public void onDialpadUp() {
- if (DEBUG) {
- Log.d(TAG, "OnDialpadUp: isInSearchUi " + mActivityUi.isInSearchUi());
- }
+ LogUtil.d("ActionBarController.onDialpadUp", "isInSearchUi " + mActivityUi.isInSearchUi());
if (mActivityUi.isInSearchUi()) {
slideActionBar(true /* slideUp */, true /* animate */);
} else {
@@ -149,18 +127,14 @@ public class ActionBarController {
}
public void slideActionBar(boolean slideUp, boolean animate) {
- if (DEBUG) {
- Log.d(TAG, "Sliding actionBar - up: " + slideUp + " animate: " + animate);
- }
+ LogUtil.d("ActionBarController.slidingActionBar", "up: %b, animate: %b", slideUp, animate);
+
if (animate) {
ValueAnimator animator = slideUp ? ValueAnimator.ofFloat(0, 1) : ValueAnimator.ofFloat(1, 0);
animator.addUpdateListener(
- new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- final float value = (float) animation.getAnimatedValue();
- setHideOffset((int) (mActivityUi.getActionBarHeight() * value));
- }
+ animation -> {
+ final float value = (float) animation.getAnimatedValue();
+ setHideOffset((int) (mActivityUi.getActionBarHeight() * value));
});
animator.start();
} else {
@@ -173,20 +147,11 @@ public class ActionBarController {
mSearchBox.animate().alpha(alphaValue).start();
}
- /** @return The offset the action bar is being translated upwards by */
- public int getHideOffset() {
- return mActivityUi.getActionBarHideOffset();
- }
-
public void setHideOffset(int offset) {
mIsActionBarSlidUp = offset >= mActivityUi.getActionBarHeight();
mActivityUi.setActionBarHideOffset(offset);
}
- public int getActionBarHeight() {
- return mActivityUi.getActionBarHeight();
- }
-
/** Saves the current state of the action bar into a provided {@link Bundle} */
public void saveInstanceState(Bundle outState) {
outState.putBoolean(KEY_IS_SLID_UP, mIsActionBarSlidUp);
@@ -225,23 +190,14 @@ public class ActionBarController {
slideActionBar(mIsActionBarSlidUp /* slideUp */, false /* animate */);
}
- @VisibleForTesting
- public boolean getIsActionBarSlidUp() {
- return mIsActionBarSlidUp;
- }
-
public interface ActivityUi {
boolean isInSearchUi();
boolean hasSearchQuery();
- boolean shouldShowActionBar();
-
int getActionBarHeight();
- int getActionBarHideOffset();
-
void setActionBarHideOffset(int offset);
}
}