From b2b77b3b4154c37b5caf39990332d00c9e9122c7 Mon Sep 17 00:00:00 2001 From: mdooley Date: Thu, 7 Sep 2017 16:28:09 -0700 Subject: Updating voicemail notifications for transcription, part 2 Changing voicemail notifications to match the latest mocks, (replacing the 'Voicemail' title with what was the notification content, and putting the voicemail status or transcription in the notification content). The notifications will be updated in a following cl. screen shot: https://drive.google.com/open?id=0B9o_KvtLkcuIbDdjaTNHTFFZLW9YZEo1SG5scDR6SzloaWc4 Bug: 37340510 Test: manual PiperOrigin-RevId: 167928866 Change-Id: I81492f7fbf1cc398401a948e036854d6a8ff878b --- .../calllog/CallLogNotificationsQueryHelper.java | 30 ++++++++++-- .../dialer/app/calllog/MissedCallNotifier.java | 4 +- .../app/calllog/VisualVoicemailNotifier.java | 55 +++++++++++++++++----- .../android/dialer/logging/dialer_impression.proto | 7 ++- 4 files changed, 75 insertions(+), 21 deletions(-) (limited to 'java/com') diff --git a/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java b/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java index c749b65ba..649a6639d 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; @@ -230,6 +233,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 +244,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 +255,7 @@ public class CallLogNotificationsQueryHelper { this.transcription = transcription; this.countryIso = countryIso; this.dateMs = dateMs; + this.transcriptionState = transcriptionState; } } @@ -270,6 +276,16 @@ public class CallLogNotificationsQueryHelper { Calls.COUNTRY_ISO, Calls.DATE }; + + private static final String[] PROJECTION_O; + + static { + List 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 +295,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 +307,7 @@ public class CallLogNotificationsQueryHelper { @Override @Nullable - @TargetApi(VERSION_CODES.M) + @TargetApi(Build.VERSION_CODES.M) public List query(int type) { if (!PermissionsUtil.hasPermission(mContext, Manifest.permission.READ_CALL_LOG)) { LogUtil.w( @@ -309,7 +326,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)) { @@ -345,7 +362,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, 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..27963491d 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; @@ -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 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/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; } } -- cgit v1.2.3 From c18ca0fba4375134107c6e71dab9bd0f85a2c968 Mon Sep 17 00:00:00 2001 From: mdooley Date: Thu, 7 Sep 2017 17:15:59 -0700 Subject: Updating voicemail notifications This is mostly just a revived version of cl/158901400. It adds a job service that is triggered by changes to the voicemail database. The job updates voicemail notifications, as necessary. video of notification update: https://drive.google.com/open?id=0B9o_KvtLkcuId1ptNk1EbGotWFU Bug: 37340510,27535759 Test: manual and unit test PiperOrigin-RevId: 167934550 Change-Id: I36f03c0769645f7a0cb478172171f1079eca2108 --- java/com/android/dialer/app/AndroidManifest.xml | 5 ++ .../calllog/CallLogNotificationsQueryHelper.java | 28 +++++++ .../app/calllog/VisualVoicemailNotifier.java | 4 +- .../app/calllog/VisualVoicemailUpdateTask.java | 58 ++++++++++++-- .../calllog/VoicemailNotificationJobService.java | 89 ++++++++++++++++++++++ .../dialer/app/calllog/VoicemailQueryHandler.java | 10 ++- .../android/dialer/constants/ScheduledJobIds.java | 1 + 7 files changed, 184 insertions(+), 11 deletions(-) create mode 100644 java/com/android/dialer/app/calllog/VoicemailNotificationJobService.java (limited to 'java/com') 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" /> + + diff --git a/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java b/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java index 649a6639d..2f8b1f476 100644 --- a/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java +++ b/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java @@ -136,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. * @@ -219,6 +223,10 @@ public class CallLogNotificationsQueryHelper { /** Returns the new calls of a certain type for which a notification should be generated. */ @Nullable List query(int type); + + /** Returns a {@link NewCall} pointed by the {@code callsUri} */ + @Nullable + NewCall query(Uri callsUri); } /** Information about a new voicemail. */ @@ -346,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); diff --git a/java/com/android/dialer/app/calllog/VisualVoicemailNotifier.java b/java/com/android/dialer/app/calllog/VisualVoicemailNotifier.java index 27963491d..ceae3d38e 100644 --- a/java/com/android/dialer/app/calllog/VisualVoicemailNotifier.java +++ b/java/com/android/dialer/app/calllog/VisualVoicemailNotifier.java @@ -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. 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 newCalls = queryHelper.getNewVoicemails(); - if (newCalls == null) { + List 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 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 getAndUpdateVoicemailsWithExistingNotification( + Context context, CallLogNotificationsQueryHelper queryHelper) { + Assert.isWorkerThread(); + List 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/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; -- cgit v1.2.3 From 50715261119b30e6e23aaf58fcf3e28f16430f3d Mon Sep 17 00:00:00 2001 From: calderwoodra Date: Fri, 8 Sep 2017 09:20:08 -0700 Subject: This is a rollforward of cl/167332236 Improved behavior of back button in search ui. Pressing the back button in the search UI now functions as follows: - If the keyboard is opened, the keyboard is minimized - If the dialpad is opened, the dialpad is closed - If the keyboard and dialpad is closed, the search ui is closed Our existing behavior was dependent on whether a query had been built yet. basically, if the user pressed back with no query selected, the search ui was closed. From the bugbash: 7. No scroll bar in the search results if the results do not fill the entire view. The keyboard overlaps the results and there is no way to get to the enter list without dismissing the keyboard. 10. Dismiss the keyboard on tapping the down arrow on the keyboard. Arrow points down but works like back button Bug: 62685859,63691995,63939331,64137632,64902476 Test: manual PiperOrigin-RevId: 168004913 Change-Id: Ia566fce6d90454a3eae6ecccfa81ce7e909e878f --- java/com/android/dialer/app/DialtactsActivity.java | 113 ++++++++------------- .../dialer/app/widget/ActionBarController.java | 28 ++--- .../dialer/dialpadview/DialpadFragment.java | 12 +-- 3 files changed, 53 insertions(+), 100 deletions(-) (limited to 'java/com') 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/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/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. */ -- cgit v1.2.3