summaryrefslogtreecommitdiff
path: root/java/com
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2017-09-11 22:10:28 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2017-09-11 22:10:28 +0000
commit3523770fcf79ccf3b05ca2485af08b78f53b1294 (patch)
treeff70d3252b4b25337cc0ad18933e8fab02adc8a0 /java/com
parent03249752afd7d870ff708bf47d687a1643367ec5 (diff)
parent50715261119b30e6e23aaf58fcf3e28f16430f3d (diff)
Merge changes Ia566fce6,I36f03c07,I81492f7f
* changes: This is a rollforward of cl/167332236 Updating voicemail notifications Updating voicemail notifications for transcription, part 2
Diffstat (limited to 'java/com')
-rw-r--r--java/com/android/dialer/app/AndroidManifest.xml5
-rw-r--r--java/com/android/dialer/app/DialtactsActivity.java113
-rw-r--r--java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java58
-rw-r--r--java/com/android/dialer/app/calllog/MissedCallNotifier.java4
-rw-r--r--java/com/android/dialer/app/calllog/VisualVoicemailNotifier.java59
-rw-r--r--java/com/android/dialer/app/calllog/VisualVoicemailUpdateTask.java58
-rw-r--r--java/com/android/dialer/app/calllog/VoicemailNotificationJobService.java89
-rw-r--r--java/com/android/dialer/app/calllog/VoicemailQueryHandler.java10
-rw-r--r--java/com/android/dialer/app/widget/ActionBarController.java28
-rw-r--r--java/com/android/dialer/constants/ScheduledJobIds.java1
-rw-r--r--java/com/android/dialer/dialpadview/DialpadFragment.java12
-rw-r--r--java/com/android/dialer/logging/dialer_impression.proto7
12 files changed, 312 insertions, 132 deletions
diff --git a/java/com/android/dialer/app/AndroidManifest.xml b/java/com/android/dialer/app/AndroidManifest.xml
index 4200082a6..2ef5dad14 100644
--- a/java/com/android/dialer/app/AndroidManifest.xml
+++ b/java/com/android/dialer/app/AndroidManifest.xml
@@ -103,6 +103,11 @@
android:name="com.android.dialer.app.calllog.CallLogNotificationsService"
/>
+ <service
+ android:name="com.android.dialer.app.calllog.VoicemailNotificationJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE"
+ />
+
<receiver
android:directBootAware="true"
android:name="com.android.dialer.app.calllog.MissedCallNotificationReceiver">
diff --git a/java/com/android/dialer/app/DialtactsActivity.java b/java/com/android/dialer/app/DialtactsActivity.java
index 13b6eb92c..7f5a9b94a 100644
--- a/java/com/android/dialer/app/DialtactsActivity.java
+++ b/java/com/android/dialer/app/DialtactsActivity.java
@@ -49,7 +49,6 @@ import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.DragEvent;
import android.view.Gravity;
-import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
@@ -169,6 +168,7 @@ public class DialtactsActivity extends TransactionSafeActivity
private static final String TAG = "DialtactsActivity";
private static final String KEY_IN_REGULAR_SEARCH_UI = "in_regular_search_ui";
private static final String KEY_IN_DIALPAD_SEARCH_UI = "in_dialpad_search_ui";
+ private static final String KEY_IN_NEW_SEARCH_UI = "in_new_search_ui";
private static final String KEY_SEARCH_QUERY = "search_query";
private static final String KEY_FIRST_LAUNCH = "first_launch";
private static final String KEY_WAS_CONFIGURATION_CHANGE = "was_configuration_change";
@@ -213,6 +213,8 @@ public class DialtactsActivity extends TransactionSafeActivity
*/
private boolean mStateSaved;
+ private boolean mIsKeyboardOpen;
+ private boolean mInNewSearch;
private boolean mIsRestarting;
private boolean mInDialpadSearch;
private boolean mInRegularSearch;
@@ -330,27 +332,6 @@ public class DialtactsActivity extends TransactionSafeActivity
private int mActionBarHeight;
private int mPreviouslySelectedTabIndex;
- /** Handles the user closing the soft keyboard. */
- private final View.OnKeyListener mSearchEditTextLayoutListener =
- new View.OnKeyListener() {
- @Override
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
- if (TextUtils.isEmpty(mSearchView.getText().toString())) {
- // If the search term is empty, close the search UI.
- PerformanceReport.recordClick(UiAction.Type.CLOSE_SEARCH_WITH_HIDE_BUTTON);
- maybeExitSearchUi();
- } else {
- // If the search term is not empty, show the dialpad fab.
- if (!mFloatingActionButtonController.isVisible()) {
- PerformanceReport.recordClick(UiAction.Type.HIDE_KEYBOARD_IN_SEARCH);
- }
- showFabInSearchUi();
- }
- }
- return false;
- }
- };
/**
* The text returned from a voice search query. Set in {@link #onActivityResult} and used in
@@ -410,30 +391,20 @@ public class DialtactsActivity extends TransactionSafeActivity
SearchEditTextLayout searchEditTextLayout =
actionBar.getCustomView().findViewById(R.id.search_view_container);
- searchEditTextLayout.setPreImeKeyListener(mSearchEditTextLayoutListener);
mActionBarController = new ActionBarController(this, searchEditTextLayout);
mSearchView = searchEditTextLayout.findViewById(R.id.search_view);
mSearchView.addTextChangedListener(mPhoneSearchQueryTextListener);
mSearchView.setHint(getSearchBoxHint());
+
mVoiceSearchButton = searchEditTextLayout.findViewById(R.id.voice_search_button);
searchEditTextLayout
.findViewById(R.id.search_box_collapsed)
.setOnClickListener(mSearchViewOnClickListener);
- searchEditTextLayout.setCallback(
- new SearchEditTextLayout.Callback() {
- @Override
- public void onBackButtonClicked() {
- onBackPressed();
- }
-
- @Override
- public void onSearchViewClicked() {
- // Hide FAB, as the keyboard is shown.
- mFloatingActionButtonController.scaleOut();
- }
- });
+ searchEditTextLayout
+ .findViewById(R.id.search_back_button)
+ .setOnClickListener(v -> exitSearchUi());
mIsLandscape =
getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
@@ -460,6 +431,7 @@ public class DialtactsActivity extends TransactionSafeActivity
mSearchQuery = savedInstanceState.getString(KEY_SEARCH_QUERY);
mInRegularSearch = savedInstanceState.getBoolean(KEY_IN_REGULAR_SEARCH_UI);
mInDialpadSearch = savedInstanceState.getBoolean(KEY_IN_DIALPAD_SEARCH_UI);
+ mInNewSearch = savedInstanceState.getBoolean(KEY_IN_NEW_SEARCH_UI);
mFirstLaunch = savedInstanceState.getBoolean(KEY_FIRST_LAUNCH);
mWasConfigurationChange = savedInstanceState.getBoolean(KEY_WAS_CONFIGURATION_CHANGE);
mShowDialpadOnResume = savedInstanceState.getBoolean(KEY_IS_DIALPAD_SHOWN);
@@ -654,6 +626,7 @@ public class DialtactsActivity extends TransactionSafeActivity
outState.putString(KEY_SEARCH_QUERY, mSearchQuery);
outState.putBoolean(KEY_IN_REGULAR_SEARCH_UI, mInRegularSearch);
outState.putBoolean(KEY_IN_DIALPAD_SEARCH_UI, mInDialpadSearch);
+ outState.putBoolean(KEY_IN_NEW_SEARCH_UI, mInNewSearch);
outState.putBoolean(KEY_FIRST_LAUNCH, mFirstLaunch);
outState.putBoolean(KEY_IS_DIALPAD_SHOWN, mIsDialpadShown);
outState.putBoolean(KEY_WAS_CONFIGURATION_CHANGE, isChangingConfigurations());
@@ -893,14 +866,19 @@ public class DialtactsActivity extends TransactionSafeActivity
updateSearchFragmentPosition();
}
+ @Override
+ public void onCallPlacedFromDialpad() {
+ hideDialpadFragment(false /* animate */, true /*clearDialpad */);
+ exitSearchUi();
+ }
+
/**
* Initiates animations and other visual updates to hide the dialpad. The fragment is hidden in a
* callback after the hide animation ends.
*
* @see #commitDialpadFragmentHide
*/
- @Override
- public void hideDialpadFragment(boolean animate, boolean clearDialpad) {
+ private void hideDialpadFragment(boolean animate, boolean clearDialpad) {
LogUtil.enterBlock("DialtactsActivity.hideDialpadFragment");
if (mDialpadFragment == null || mDialpadFragment.getView() == null) {
return;
@@ -935,11 +913,6 @@ public class DialtactsActivity extends TransactionSafeActivity
mActionBarController.onDialpadDown();
- if (isInSearchUi()) {
- if (TextUtils.isEmpty(mSearchQuery)) {
- exitSearchUi();
- }
- }
// reset the title to normal.
setTitle(R.string.launcherActivityLabel);
}
@@ -987,7 +960,7 @@ public class DialtactsActivity extends TransactionSafeActivity
@Override
public boolean isInSearchUi() {
- return mInDialpadSearch || mInRegularSearch;
+ return mInDialpadSearch || mInRegularSearch || mInNewSearch;
}
@Override
@@ -998,6 +971,7 @@ public class DialtactsActivity extends TransactionSafeActivity
private void setNotInSearchUi() {
mInDialpadSearch = false;
mInRegularSearch = false;
+ mInNewSearch = false;
}
private void hideDialpadAndSearchUi() {
@@ -1171,17 +1145,21 @@ public class DialtactsActivity extends TransactionSafeActivity
}
final String tag;
+ mInDialpadSearch = false;
+ mInRegularSearch = false;
+ mInNewSearch = false;
boolean useNewSearch =
ConfigProviderBindings.get(this).getBoolean("enable_new_search_fragment", false);
if (useNewSearch) {
tag = TAG_NEW_SEARCH_FRAGMENT;
+ mInNewSearch = true;
} else if (smartDialSearch) {
tag = TAG_SMARTDIAL_SEARCH_FRAGMENT;
+ mInDialpadSearch = true;
} else {
tag = TAG_REGULAR_SEARCH_FRAGMENT;
+ mInRegularSearch = true;
}
- mInDialpadSearch = smartDialSearch;
- mInRegularSearch = !smartDialSearch;
mFloatingActionButtonController.scaleOut();
@@ -1304,43 +1282,34 @@ public class DialtactsActivity extends TransactionSafeActivity
return;
}
if (mIsDialpadShown) {
- if (TextUtils.isEmpty(mSearchQuery)
- || (mSmartDialSearchFragment != null
- && mSmartDialSearchFragment.isVisible()
- && mSmartDialSearchFragment.getAdapter().getCount() == 0)) {
- exitSearchUi();
- }
hideDialpadFragment(true, false);
} else if (isInSearchUi()) {
- exitSearchUi();
- DialerUtils.hideInputMethod(mParentLayout);
+ if (mIsKeyboardOpen) {
+ DialerUtils.hideInputMethod(mParentLayout);
+ PerformanceReport.recordClick(UiAction.Type.HIDE_KEYBOARD_IN_SEARCH);
+ } else {
+ exitSearchUi();
+ }
} else {
super.onBackPressed();
}
}
- private void maybeEnterSearchUi() {
- if (!isInSearchUi()) {
- enterSearchUi(true /* isSmartDial */, mSearchQuery, false);
+ @Override
+ public void onConfigurationChanged(Configuration configuration) {
+ super.onConfigurationChanged(configuration);
+ // Checks whether a hardware keyboard is available
+ if (configuration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) {
+ mIsKeyboardOpen = true;
+ } else if (configuration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
+ mIsKeyboardOpen = false;
}
}
- /** @return True if the search UI was exited, false otherwise */
- private boolean maybeExitSearchUi() {
- if (isInSearchUi() && TextUtils.isEmpty(mSearchQuery)) {
- exitSearchUi();
- DialerUtils.hideInputMethod(mParentLayout);
- return true;
+ private void maybeEnterSearchUi() {
+ if (!isInSearchUi()) {
+ enterSearchUi(true /* isSmartDial */, mSearchQuery, false);
}
- return false;
- }
-
- private void showFabInSearchUi() {
- mFloatingActionButtonController.changeIcon(
- getResources().getDrawable(R.drawable.quantum_ic_dialpad_white_24, null),
- getResources().getString(R.string.action_menu_dialpad_button));
- mFloatingActionButtonController.align(getFabAlignment(), false /* animate */);
- mFloatingActionButtonController.scaleIn(FAB_SCALE_IN_DELAY_MS);
}
@Override
diff --git a/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java b/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java
index c749b65ba..2f8b1f476 100644
--- a/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java
+++ b/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java
@@ -24,7 +24,7 @@ import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
-import android.os.Build.VERSION_CODES;
+import android.os.Build;
import android.provider.CallLog.Calls;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@@ -35,14 +35,17 @@ import android.text.TextUtils;
import com.android.dialer.app.R;
import com.android.dialer.calllogutils.PhoneNumberDisplayUtil;
import com.android.dialer.common.LogUtil;
+import com.android.dialer.compat.android.provider.VoicemailCompat;
import com.android.dialer.location.GeoUtil;
import com.android.dialer.phonenumbercache.ContactInfo;
import com.android.dialer.phonenumbercache.ContactInfoHelper;
import com.android.dialer.util.PermissionsUtil;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/** Helper class operating on call log notifications. */
+@TargetApi(Build.VERSION_CODES.M)
public class CallLogNotificationsQueryHelper {
private final Context mContext;
@@ -133,6 +136,10 @@ public class CallLogNotificationsQueryHelper {
return new DefaultNewCallsQuery(context.getApplicationContext(), contentResolver);
}
+ NewCallsQuery getNewCallsQuery() {
+ return mNewCallsQuery;
+ }
+
/**
* Get all voicemails with the "new" flag set to 1.
*
@@ -216,6 +223,10 @@ public class CallLogNotificationsQueryHelper {
/** Returns the new calls of a certain type for which a notification should be generated. */
@Nullable
List<NewCall> query(int type);
+
+ /** Returns a {@link NewCall} pointed by the {@code callsUri} */
+ @Nullable
+ NewCall query(Uri callsUri);
}
/** Information about a new voicemail. */
@@ -230,6 +241,7 @@ public class CallLogNotificationsQueryHelper {
public final String transcription;
public final String countryIso;
public final long dateMs;
+ public final int transcriptionState;
public NewCall(
Uri callsUri,
@@ -240,7 +252,8 @@ public class CallLogNotificationsQueryHelper {
String accountId,
String transcription,
String countryIso,
- long dateMs) {
+ long dateMs,
+ int transcriptionState) {
this.callsUri = callsUri;
this.voicemailUri = voicemailUri;
this.number = number;
@@ -250,6 +263,7 @@ public class CallLogNotificationsQueryHelper {
this.transcription = transcription;
this.countryIso = countryIso;
this.dateMs = dateMs;
+ this.transcriptionState = transcriptionState;
}
}
@@ -270,6 +284,16 @@ public class CallLogNotificationsQueryHelper {
Calls.COUNTRY_ISO,
Calls.DATE
};
+
+ private static final String[] PROJECTION_O;
+
+ static {
+ List<String> list = new ArrayList<>();
+ list.addAll(Arrays.asList(PROJECTION));
+ list.add(VoicemailCompat.TRANSCRIPTION_STATE);
+ PROJECTION_O = list.toArray(new String[list.size()]);
+ }
+
private static final int ID_COLUMN_INDEX = 0;
private static final int NUMBER_COLUMN_INDEX = 1;
private static final int VOICEMAIL_URI_COLUMN_INDEX = 2;
@@ -279,6 +303,7 @@ public class CallLogNotificationsQueryHelper {
private static final int TRANSCRIPTION_COLUMN_INDEX = 6;
private static final int COUNTRY_ISO_COLUMN_INDEX = 7;
private static final int DATE_COLUMN_INDEX = 8;
+ private static final int TRANSCRIPTION_STATE_COLUMN_INDEX = 9;
private final ContentResolver mContentResolver;
private final Context mContext;
@@ -290,7 +315,7 @@ public class CallLogNotificationsQueryHelper {
@Override
@Nullable
- @TargetApi(VERSION_CODES.M)
+ @TargetApi(Build.VERSION_CODES.M)
public List<NewCall> query(int type) {
if (!PermissionsUtil.hasPermission(mContext, Manifest.permission.READ_CALL_LOG)) {
LogUtil.w(
@@ -309,7 +334,7 @@ public class CallLogNotificationsQueryHelper {
try (Cursor cursor =
mContentResolver.query(
Calls.CONTENT_URI_WITH_VOICEMAIL,
- PROJECTION,
+ (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) ? PROJECTION_O : PROJECTION,
selection,
selectionArgs,
Calls.DEFAULT_SORT_ORDER)) {
@@ -329,6 +354,26 @@ public class CallLogNotificationsQueryHelper {
}
}
+ @Nullable
+ @Override
+ public NewCall query(Uri callsUri) {
+ if (!PermissionsUtil.hasPermission(mContext, Manifest.permission.READ_CALL_LOG)) {
+ LogUtil.w(
+ "CallLogNotificationsQueryHelper.DefaultNewCallsQuery.query",
+ "No READ_CALL_LOG permission, returning null for calls lookup.");
+ return null;
+ }
+ try (Cursor cursor = mContentResolver.query(callsUri, PROJECTION, null, null, null)) {
+ if (cursor == null) {
+ return null;
+ }
+ if (!cursor.moveToFirst()) {
+ return null;
+ }
+ return createNewCallsFromCursor(cursor);
+ }
+ }
+
/** Returns an instance of {@link NewCall} created by using the values of the cursor. */
private NewCall createNewCallsFromCursor(Cursor cursor) {
String voicemailUriString = cursor.getString(VOICEMAIL_URI_COLUMN_INDEX);
@@ -345,7 +390,10 @@ public class CallLogNotificationsQueryHelper {
cursor.getString(PHONE_ACCOUNT_ID_COLUMN_INDEX),
cursor.getString(TRANSCRIPTION_COLUMN_INDEX),
cursor.getString(COUNTRY_ISO_COLUMN_INDEX),
- cursor.getLong(DATE_COLUMN_INDEX));
+ cursor.getLong(DATE_COLUMN_INDEX),
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
+ ? cursor.getInt(TRANSCRIPTION_STATE_COLUMN_INDEX)
+ : VoicemailCompat.TRANSCRIPTION_NOT_STARTED);
}
}
}
diff --git a/java/com/android/dialer/app/calllog/MissedCallNotifier.java b/java/com/android/dialer/app/calllog/MissedCallNotifier.java
index b363b5ab6..de766191a 100644
--- a/java/com/android/dialer/app/calllog/MissedCallNotifier.java
+++ b/java/com/android/dialer/app/calllog/MissedCallNotifier.java
@@ -47,6 +47,7 @@ import com.android.dialer.callintent.CallInitiationType;
import com.android.dialer.callintent.CallIntentBuilder;
import com.android.dialer.common.LogUtil;
import com.android.dialer.common.concurrent.DialerExecutor.Worker;
+import com.android.dialer.compat.android.provider.VoicemailCompat;
import com.android.dialer.notification.DialerNotificationManager;
import com.android.dialer.notification.NotificationChannelId;
import com.android.dialer.notification.NotificationManagerUtils;
@@ -153,7 +154,8 @@ public class MissedCallNotifier implements Worker<Pair<Integer, String>, Void> {
null,
null,
null,
- System.currentTimeMillis());
+ System.currentTimeMillis(),
+ VoicemailCompat.TRANSCRIPTION_NOT_STARTED);
// TODO: look up caller ID that is not in contacts.
ContactInfo contactInfo =
diff --git a/java/com/android/dialer/app/calllog/VisualVoicemailNotifier.java b/java/com/android/dialer/app/calllog/VisualVoicemailNotifier.java
index cbadfd317..ceae3d38e 100644
--- a/java/com/android/dialer/app/calllog/VisualVoicemailNotifier.java
+++ b/java/com/android/dialer/app/calllog/VisualVoicemailNotifier.java
@@ -27,7 +27,6 @@ import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import android.support.v4.os.BuildCompat;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telephony.TelephonyManager;
@@ -39,6 +38,7 @@ import com.android.dialer.app.calllog.CallLogNotificationsQueryHelper.NewCall;
import com.android.dialer.app.contactinfo.ContactPhotoLoader;
import com.android.dialer.app.list.DialtactsPagerAdapter;
import com.android.dialer.common.LogUtil;
+import com.android.dialer.compat.android.provider.VoicemailCompat;
import com.android.dialer.logging.DialerImpression;
import com.android.dialer.logging.Logger;
import com.android.dialer.notification.DialerNotificationManager;
@@ -54,9 +54,9 @@ final class VisualVoicemailNotifier {
/** Prefix used to generate a unique tag for each voicemail notification. */
private static final String NOTIFICATION_TAG_PREFIX = "VisualVoicemail_";
/** Common ID for all voicemail notifications. */
- private static final int NOTIFICATION_ID = 1;
+ static final int NOTIFICATION_ID = 1;
/** Tag for the group summary notification. */
- private static final String GROUP_SUMMARY_NOTIFICATION_TAG = "GroupSummary_VisualVoicemail";
+ static final String GROUP_SUMMARY_NOTIFICATION_TAG = "GroupSummary_VisualVoicemail";
/**
* Key used to associate all voicemail notifications and the summary as belonging to a single
* group.
@@ -84,7 +84,7 @@ final class VisualVoicemailNotifier {
.setGroupSummary(true)
.setContentIntent(newVoicemailIntent(context, null));
- if (BuildCompat.isAtLeastO()) {
+ if (VERSION.SDK_INT >= VERSION_CODES.O) {
groupSummary.setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN);
PhoneAccountHandle handle = getAccountForCall(context, newCalls.get(0));
groupSummary.setChannelId(NotificationChannelManager.getVoicemailChannelId(context, handle));
@@ -136,7 +136,7 @@ final class VisualVoicemailNotifier {
.setAutoCancel(true);
}
- private static Notification createNotificationForVoicemail(
+ static Notification createNotificationForVoicemail(
@NonNull Context context,
@NonNull NewCall voicemail,
@NonNull Map<String, ContactInfo> contactInfos) {
@@ -146,10 +146,6 @@ final class VisualVoicemailNotifier {
Notification.Builder builder =
createNotificationBuilder(context)
.setContentTitle(
- context
- .getResources()
- .getQuantityString(R.plurals.notification_voicemail_title, 1, 1))
- .setContentText(
ContactDisplayUtils.getTtsSpannedPhoneNumber(
context.getResources(),
R.string.notification_new_voicemail_ticker,
@@ -158,13 +154,51 @@ final class VisualVoicemailNotifier {
.setSound(getVoicemailRingtoneUri(context, handle))
.setDefaults(getNotificationDefaultFlags(context, handle));
+ if (!TextUtils.isEmpty(voicemail.transcription)) {
+ Logger.get(context)
+ .logImpression(DialerImpression.Type.VVM_NOTIFICATION_CREATED_WITH_TRANSCRIPTION);
+ builder.setContentText(voicemail.transcription);
+ } else {
+ switch (voicemail.transcriptionState) {
+ case VoicemailCompat.TRANSCRIPTION_IN_PROGRESS:
+ Logger.get(context)
+ .logImpression(DialerImpression.Type.VVM_NOTIFICATION_CREATED_WITH_IN_PROGRESS);
+ builder.setContentText(context.getString(R.string.voicemail_transcription_in_progress));
+ break;
+ case VoicemailCompat.TRANSCRIPTION_FAILED_NO_SPEECH_DETECTED:
+ Logger.get(context)
+ .logImpression(
+ DialerImpression.Type.VVM_NOTIFICATION_CREATED_WITH_TRANSCRIPTION_FAILURE);
+ builder.setContentText(
+ context.getString(R.string.voicemail_transcription_failed_no_speech));
+ break;
+ case VoicemailCompat.TRANSCRIPTION_FAILED_LANGUAGE_NOT_SUPPORTED:
+ Logger.get(context)
+ .logImpression(
+ DialerImpression.Type.VVM_NOTIFICATION_CREATED_WITH_TRANSCRIPTION_FAILURE);
+ builder.setContentText(
+ context.getString(R.string.voicemail_transcription_failed_language_not_supported));
+ break;
+ case VoicemailCompat.TRANSCRIPTION_FAILED:
+ Logger.get(context)
+ .logImpression(
+ DialerImpression.Type.VVM_NOTIFICATION_CREATED_WITH_TRANSCRIPTION_FAILURE);
+ builder.setContentText(context.getString(R.string.voicemail_transcription_failed));
+ break;
+ default:
+ Logger.get(context)
+ .logImpression(DialerImpression.Type.VVM_NOTIFICATION_CREATED_WITH_NO_TRANSCRIPTION);
+ break;
+ }
+ }
+
if (voicemail.voicemailUri != null) {
builder.setDeleteIntent(
CallLogNotificationsService.createMarkSingleNewVoicemailAsOldIntent(
context, voicemail.voicemailUri));
}
- if (BuildCompat.isAtLeastO()) {
+ if (VERSION.SDK_INT >= VERSION_CODES.O) {
builder.setChannelId(NotificationChannelManager.getVoicemailChannelId(context, handle));
}
@@ -173,11 +207,6 @@ final class VisualVoicemailNotifier {
if (photoIcon != null) {
builder.setLargeIcon(photoIcon);
}
- if (!TextUtils.isEmpty(voicemail.transcription)) {
- Logger.get(context)
- .logImpression(DialerImpression.Type.VVM_NOTIFICATION_CREATED_WITH_TRANSCRIPTION);
- builder.setStyle(new Notification.BigTextStyle().bigText(voicemail.transcription));
- }
builder.setContentIntent(newVoicemailIntent(context, voicemail));
Logger.get(context).logImpression(DialerImpression.Type.VVM_NOTIFICATION_CREATED);
return builder.build();
diff --git a/java/com/android/dialer/app/calllog/VisualVoicemailUpdateTask.java b/java/com/android/dialer/app/calllog/VisualVoicemailUpdateTask.java
index d6601be36..219ad676d 100644
--- a/java/com/android/dialer/app/calllog/VisualVoicemailUpdateTask.java
+++ b/java/com/android/dialer/app/calllog/VisualVoicemailUpdateTask.java
@@ -17,6 +17,8 @@
package com.android.dialer.app.calllog;
import android.content.Context;
+import android.net.Uri;
+import android.service.notification.StatusBarNotification;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.WorkerThread;
@@ -30,6 +32,7 @@ import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
import com.android.dialer.common.concurrent.DialerExecutor.Worker;
import com.android.dialer.common.concurrent.DialerExecutors;
+import com.android.dialer.notification.DialerNotificationManager;
import com.android.dialer.phonenumbercache.ContactInfo;
import com.android.dialer.telecom.TelecomUtil;
import java.util.ArrayList;
@@ -57,13 +60,20 @@ class VisualVoicemailUpdateTask implements Worker<VisualVoicemailUpdateTask.Inpu
CallLogNotificationsQueryHelper queryHelper,
FilteredNumberAsyncQueryHandler queryHandler) {
Assert.isWorkerThread();
+ LogUtil.enterBlock("VisualVoicemailUpdateTask.updateNotification");
- List<NewCall> newCalls = queryHelper.getNewVoicemails();
- if (newCalls == null) {
+ List<NewCall> voicemailsToNotify = queryHelper.getNewVoicemails();
+ if (voicemailsToNotify == null) {
+ // Query failed, just return
return;
}
- newCalls = filterBlockedNumbers(context, queryHandler, newCalls);
- if (newCalls.isEmpty()) {
+
+ voicemailsToNotify.addAll(getAndUpdateVoicemailsWithExistingNotification(context, queryHelper));
+ voicemailsToNotify = filterBlockedNumbers(context, queryHandler, voicemailsToNotify);
+ if (voicemailsToNotify.isEmpty()) {
+ LogUtil.i("VisualVoicemailUpdateTask.updateNotification", "no voicemails to notify about");
+ VisualVoicemailNotifier.cancelAllVoicemailNotifications(context);
+ VoicemailNotificationJobService.cancelJob(context);
return;
}
@@ -73,7 +83,7 @@ class VisualVoicemailUpdateTask implements Worker<VisualVoicemailUpdateTask.Inpu
// Maps each number into a name: if a number is in the map, it has already left a more
// recent voicemail.
Map<String, ContactInfo> contactInfos = new ArrayMap<>();
- for (NewCall newCall : newCalls) {
+ for (NewCall newCall : voicemailsToNotify) {
if (!contactInfos.containsKey(newCall.number)) {
ContactInfo contactInfo =
queryHelper.getContactInfo(
@@ -90,7 +100,43 @@ class VisualVoicemailUpdateTask implements Worker<VisualVoicemailUpdateTask.Inpu
}
}
}
- VisualVoicemailNotifier.showNotifications(context, newCalls, contactInfos, callers);
+ VisualVoicemailNotifier.showNotifications(context, voicemailsToNotify, contactInfos, callers);
+
+ // Set trigger to update notifications when database changes.
+ VoicemailNotificationJobService.scheduleJob(context);
+ }
+
+ /**
+ * Cancel notification for voicemail that is already deleted. Returns a list of voicemails that
+ * already has notifications posted and should be updated.
+ */
+ @WorkerThread
+ @NonNull
+ private static List<NewCall> getAndUpdateVoicemailsWithExistingNotification(
+ Context context, CallLogNotificationsQueryHelper queryHelper) {
+ Assert.isWorkerThread();
+ List<NewCall> result = new ArrayList<>();
+ for (StatusBarNotification notification :
+ DialerNotificationManager.getActiveNotifications(context)) {
+ if (notification.getId() != VisualVoicemailNotifier.NOTIFICATION_ID) {
+ continue;
+ }
+ if (TextUtils.equals(
+ notification.getTag(), VisualVoicemailNotifier.GROUP_SUMMARY_NOTIFICATION_TAG)) {
+ // Group header
+ continue;
+ }
+ NewCall existingCall = queryHelper.getNewCallsQuery().query(Uri.parse(notification.getTag()));
+ if (existingCall != null) {
+ result.add(existingCall);
+ } else {
+ LogUtil.i(
+ "VisualVoicemailUpdateTask.getVoicemailsWithExistingNotification",
+ "voicemail deleted, removing notification");
+ DialerNotificationManager.cancel(context, notification.getTag(), notification.getId());
+ }
+ }
+ return result;
}
@WorkerThread
diff --git a/java/com/android/dialer/app/calllog/VoicemailNotificationJobService.java b/java/com/android/dialer/app/calllog/VoicemailNotificationJobService.java
new file mode 100644
index 000000000..ba61601ae
--- /dev/null
+++ b/java/com/android/dialer/app/calllog/VoicemailNotificationJobService.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.app.calllog;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Build;
+import android.provider.VoicemailContract;
+import com.android.dialer.common.LogUtil;
+import com.android.dialer.constants.ScheduledJobIds;
+
+/** Monitors voicemail provider changes to update active notifications. */
+public class VoicemailNotificationJobService extends JobService {
+
+ private static JobInfo jobInfo;
+
+ /**
+ * Start monitoring the provider. The provider should be monitored whenever a visual voicemail
+ * notification is visible.
+ */
+ public static void scheduleJob(Context context) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
+ LogUtil.i("VoicemailNotificationJobService.scheduleJob", "not supported");
+ } else {
+ context.getSystemService(JobScheduler.class).schedule(getJobInfo(context));
+ LogUtil.i("VoicemailNotificationJobService.scheduleJob", "job scheduled");
+ }
+ }
+
+ /**
+ * Stop monitoring the provider. The provider should not be monitored when visual voicemail
+ * notification is cleared.
+ */
+ public static void cancelJob(Context context) {
+ context.getSystemService(JobScheduler.class).cancel(ScheduledJobIds.VVM_NOTIFICATION_JOB);
+ LogUtil.i("VoicemailNotificationJobService.scheduleJob", "job canceled");
+ }
+
+ @Override
+ public boolean onStartJob(JobParameters params) {
+ LogUtil.i("VoicemailNotificationJobService.onStartJob", "updating notification");
+ VisualVoicemailUpdateTask.scheduleTask(
+ this,
+ () -> {
+ jobFinished(params, false);
+ });
+ return true; // Running in background
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters params) {
+ return false;
+ }
+
+ private static JobInfo getJobInfo(Context context) {
+ if (jobInfo == null) {
+ jobInfo =
+ new JobInfo.Builder(
+ ScheduledJobIds.VVM_NOTIFICATION_JOB,
+ new ComponentName(context, VoicemailNotificationJobService.class))
+ .addTriggerContentUri(
+ new JobInfo.TriggerContentUri(
+ VoicemailContract.Voicemails.CONTENT_URI,
+ JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS))
+ .setTriggerContentMaxDelay(0)
+ .build();
+ }
+
+ return jobInfo;
+ }
+}
diff --git a/java/com/android/dialer/app/calllog/VoicemailQueryHandler.java b/java/com/android/dialer/app/calllog/VoicemailQueryHandler.java
index 2fbebdd30..169d0fd35 100644
--- a/java/com/android/dialer/app/calllog/VoicemailQueryHandler.java
+++ b/java/com/android/dialer/app/calllog/VoicemailQueryHandler.java
@@ -45,7 +45,8 @@ public class VoicemailQueryHandler extends AsyncQueryHandler {
public static void markAllNewVoicemailsAsRead(final @NonNull Context context) {
ThreadUtil.postOnUiThread(
() -> {
- new VoicemailQueryHandler(context.getContentResolver()).markNewVoicemailsAsOld(null);
+ new VoicemailQueryHandler(context.getContentResolver())
+ .markNewVoicemailsAsOld(context, null);
});
}
@@ -59,12 +60,12 @@ public class VoicemailQueryHandler extends AsyncQueryHandler {
ThreadUtil.postOnUiThread(
() -> {
new VoicemailQueryHandler(context.getContentResolver())
- .markNewVoicemailsAsOld(voicemailUri);
+ .markNewVoicemailsAsOld(context, voicemailUri);
});
}
/** Updates all new voicemails to mark them as old. */
- private void markNewVoicemailsAsOld(@Nullable Uri voicemailUri) {
+ private void markNewVoicemailsAsOld(Context context, @Nullable Uri voicemailUri) {
// Mark all "new" voicemails as not new anymore.
StringBuilder where = new StringBuilder();
where.append(Calls.NEW);
@@ -88,5 +89,8 @@ public class VoicemailQueryHandler extends AsyncQueryHandler {
voicemailUri == null
? new String[] {Integer.toString(Calls.VOICEMAIL_TYPE)}
: new String[] {Integer.toString(Calls.VOICEMAIL_TYPE), voicemailUri.toString()});
+
+ // No more notifications, stop monitoring the voicemail provider
+ VoicemailNotificationJobService.cancelJob(context);
}
}
diff --git a/java/com/android/dialer/app/widget/ActionBarController.java b/java/com/android/dialer/app/widget/ActionBarController.java
index c1b4cc2b4..3daa0e2d4 100644
--- a/java/com/android/dialer/app/widget/ActionBarController.java
+++ b/java/com/android/dialer/app/widget/ActionBarController.java
@@ -49,18 +49,6 @@ public class ActionBarController {
}
};
- private final AnimationCallback mFadeInCallback =
- new AnimationCallback() {
- @Override
- public void onAnimationEnd() {
- slideActionBar(false /* slideUp */, false /* animate */);
- }
-
- @Override
- public void onAnimationCancel() {
- slideActionBar(false /* slideUp */, false /* animate */);
- }
- };
private ValueAnimator mAnimator;
public ActionBarController(ActivityUi activityUi, SearchEditTextLayout searchBox) {
@@ -112,17 +100,13 @@ public class ActionBarController {
mSearchBox.isFadedOut(),
mSearchBox.isExpanded());
if (mActivityUi.isInSearchUi()) {
- if (mActivityUi.hasSearchQuery()) {
- if (mSearchBox.isFadedOut()) {
- mSearchBox.setVisible(true);
- }
- if (!mSearchBox.isExpanded()) {
- mSearchBox.expand(false /* animate */, false /* requestFocus */);
- }
- slideActionBar(false /* slideUp */, true /* animate */);
- } else {
- mSearchBox.fadeIn(mFadeInCallback);
+ if (mSearchBox.isFadedOut()) {
+ mSearchBox.setVisible(true);
+ }
+ if (!mSearchBox.isExpanded()) {
+ mSearchBox.expand(false /* animate */, false /* requestFocus */);
}
+ slideActionBar(false /* slideUp */, true /* animate */);
}
}
diff --git a/java/com/android/dialer/constants/ScheduledJobIds.java b/java/com/android/dialer/constants/ScheduledJobIds.java
index cf93a464a..3fcbb0c2e 100644
--- a/java/com/android/dialer/constants/ScheduledJobIds.java
+++ b/java/com/android/dialer/constants/ScheduledJobIds.java
@@ -34,6 +34,7 @@ public final class ScheduledJobIds {
public static final int VVM_DEVICE_PROVISIONED_JOB = 202;
public static final int VVM_TRANSCRIPTION_JOB = 203;
public static final int VVM_TRANSCRIPTION_BACKFILL_JOB = 204;
+ public static final int VVM_NOTIFICATION_JOB = 205;
public static final int VOIP_REGISTRATION = 300;
diff --git a/java/com/android/dialer/dialpadview/DialpadFragment.java b/java/com/android/dialer/dialpadview/DialpadFragment.java
index 86a83796e..837c3af90 100644
--- a/java/com/android/dialer/dialpadview/DialpadFragment.java
+++ b/java/com/android/dialer/dialpadview/DialpadFragment.java
@@ -1001,12 +1001,12 @@ public class DialpadFragment extends Fragment
DialerUtils.startActivityWithErrorToast(
getActivity(),
new CallIntentBuilder(CallUtil.getVoicemailUri(), CallInitiationType.Type.DIALPAD).build());
- hideAndClearDialpad(false);
+ hideAndClearDialpad();
}
- private void hideAndClearDialpad(boolean animate) {
+ private void hideAndClearDialpad() {
LogUtil.enterBlock("DialpadFragment.hideAndClearDialpad");
- FragmentUtils.getParentUnsafe(this, DialpadListener.class).hideDialpadFragment(animate, true);
+ FragmentUtils.getParentUnsafe(this, DialpadListener.class).onCallPlacedFromDialpad();
}
/**
@@ -1053,7 +1053,7 @@ public class DialpadFragment extends Fragment
final Intent intent =
new CallIntentBuilder(number, CallInitiationType.Type.DIALPAD).build();
DialerUtils.startActivityWithErrorToast(getActivity(), intent);
- hideAndClearDialpad(false);
+ hideAndClearDialpad();
}
}
}
@@ -1297,7 +1297,7 @@ public class DialpadFragment extends Fragment
return true;
} else if (resId == R.id.menu_call_with_note) {
CallSubjectDialog.start(getActivity(), mDigits.getText().toString());
- hideAndClearDialpad(false);
+ hideAndClearDialpad();
return true;
} else {
return false;
@@ -1710,7 +1710,7 @@ public class DialpadFragment extends Fragment
void onDialpadShown();
- void hideDialpadFragment(boolean animate, boolean value);
+ void onCallPlacedFromDialpad();
}
/** Callback for async lookup of the last number dialed. */
diff --git a/java/com/android/dialer/logging/dialer_impression.proto b/java/com/android/dialer/logging/dialer_impression.proto
index 94af6c3fd..154460ccb 100644
--- a/java/com/android/dialer/logging/dialer_impression.proto
+++ b/java/com/android/dialer/logging/dialer_impression.proto
@@ -532,7 +532,10 @@ message DialerImpression {
IN_CALL_DIALPAD_CLOSE_BUTTON_PRESSED = 1267;
// More voicemail transcription impressions
- VVM_TRANSCRIPTION_JOB_STOPPED = 1268;
- VVM_TRANSCRIPTION_TASK_CANCELLED = 1269;
+ VVM_NOTIFICATION_CREATED_WITH_IN_PROGRESS = 1268;
+ VVM_NOTIFICATION_CREATED_WITH_TRANSCRIPTION_FAILURE = 1269;
+ VVM_NOTIFICATION_CREATED_WITH_NO_TRANSCRIPTION = 1270;
+ VVM_TRANSCRIPTION_JOB_STOPPED = 1271;
+ VVM_TRANSCRIPTION_TASK_CANCELLED = 1272;
}
}