From 10b34a5ebf12e97ecba0caf3c8e30b476b038a96 Mon Sep 17 00:00:00 2001 From: Eric Erfanian Date: Thu, 4 May 2017 08:23:17 -0700 Subject: Update Dialer to V10 RC16 This release was created following the instructions at: go/dialer-aosp-release Subsequent dialer releases will follow as O bugs are fixed, until we reach our final RC. Version: 10 Candidate: RC16 Branch: dialer-android_release_branch/153304843.1 dialer-android/dialer-android_20170416.00/dialer-android_20170416.00_RC16 This release contains the following bug fixes since RC00: Bug: 37324705 35304403 36067503 35304446 33203808 37280992 37346084 35766990 37481880 37424493 36470282 37347691 37519015 37168472 35805360 37545472 27704934 36515614 35766990 37577470 34739750 35801628 36788693 35264204 36708536 37628370 36904650 37314436 37642171 37530847 37637799 37666625 37548549 37648036 37636412 37323529 37630507 35919141 37198343 37548572 36178218 37640315 37663896 37720467 37275944 37710497 31634477 37744796 37348506 37744796 37568534 37672424 34872683 34873026 37681461 34873295 37748373 37526812 37618638 37663896 37536088 37727455 37165687 36651204 36900708 37323529 36902926 37256480 37328353 37432034 37436952 34093562 37720889 37321935 37780300 37781115 37755902 36588206 34258266 37290464 37698062 37618638 37473004 37432034 37918676 37870494 37722091 Test: make, on device Change-Id: I99e1a484ccd578c1f8a13e7a6a4b4952f0791297 --- .../com/android/voicemail/impl/ActivationTask.java | 43 +- .../com/android/voicemail/impl/AndroidManifest.xml | 29 +- java/com/android/voicemail/impl/OmtpService.java | 153 +++++++ .../voicemail/impl/OmtpVvmCarrierConfigHelper.java | 10 +- .../voicemail/impl/PreOMigrationHandler.java | 102 +++++ .../android/voicemail/impl/StatusCheckTask.java | 2 +- .../voicemail/impl/TelephonyMangerCompat.java | 82 +++- .../voicemail/impl/VoicemailClientImpl.java | 8 +- .../voicemail/impl/VvmPackageInstallHandler.java | 167 ++++++++ .../android/voicemail/impl/imap/ImapHelper.java | 63 ++- .../voicemail/impl/protocol/Vvm3Subscriber.java | 56 ++- .../voicemail/impl/res/values-af/strings.xml | 5 +- .../voicemail/impl/res/values-am/strings.xml | 5 +- .../voicemail/impl/res/values-ar/strings.xml | 5 +- .../voicemail/impl/res/values-az/strings.xml | 5 +- .../impl/res/values-b+sr+Latn/strings.xml | 5 +- .../voicemail/impl/res/values-be/strings.xml | 5 +- .../voicemail/impl/res/values-bg/strings.xml | 5 +- .../voicemail/impl/res/values-bn/strings.xml | 5 +- .../voicemail/impl/res/values-bs/strings.xml | 5 +- .../voicemail/impl/res/values-ca/strings.xml | 5 +- .../voicemail/impl/res/values-cs/strings.xml | 5 +- .../voicemail/impl/res/values-da/strings.xml | 5 +- .../voicemail/impl/res/values-de/strings.xml | 5 +- .../voicemail/impl/res/values-el/strings.xml | 5 +- .../voicemail/impl/res/values-en-rAU/strings.xml | 5 +- .../voicemail/impl/res/values-en-rGB/strings.xml | 5 +- .../voicemail/impl/res/values-en-rIN/strings.xml | 5 +- .../voicemail/impl/res/values-es-rUS/strings.xml | 5 +- .../voicemail/impl/res/values-es/strings.xml | 5 +- .../voicemail/impl/res/values-et/strings.xml | 5 +- .../voicemail/impl/res/values-eu/strings.xml | 5 +- .../voicemail/impl/res/values-fa/strings.xml | 5 +- .../voicemail/impl/res/values-fi/strings.xml | 5 +- .../voicemail/impl/res/values-fr-rCA/strings.xml | 5 +- .../voicemail/impl/res/values-fr/strings.xml | 5 +- .../voicemail/impl/res/values-gl/strings.xml | 5 +- .../voicemail/impl/res/values-gu/strings.xml | 5 +- .../voicemail/impl/res/values-hi/strings.xml | 5 +- .../voicemail/impl/res/values-hr/strings.xml | 5 +- .../voicemail/impl/res/values-hu/strings.xml | 5 +- .../voicemail/impl/res/values-hy/strings.xml | 5 +- .../voicemail/impl/res/values-in/strings.xml | 5 +- .../voicemail/impl/res/values-is/strings.xml | 5 +- .../voicemail/impl/res/values-it/strings.xml | 5 +- .../voicemail/impl/res/values-iw/strings.xml | 5 +- .../voicemail/impl/res/values-ja/strings.xml | 5 +- .../voicemail/impl/res/values-ka/strings.xml | 5 +- .../voicemail/impl/res/values-kk/strings.xml | 5 +- .../voicemail/impl/res/values-km/strings.xml | 5 +- .../voicemail/impl/res/values-kn/strings.xml | 5 +- .../voicemail/impl/res/values-ko/strings.xml | 5 +- .../voicemail/impl/res/values-ky/strings.xml | 5 +- .../voicemail/impl/res/values-lo/strings.xml | 5 +- .../voicemail/impl/res/values-lt/strings.xml | 5 +- .../voicemail/impl/res/values-lv/strings.xml | 5 +- .../voicemail/impl/res/values-mk/strings.xml | 5 +- .../voicemail/impl/res/values-ml/strings.xml | 5 +- .../voicemail/impl/res/values-mn/strings.xml | 5 +- .../voicemail/impl/res/values-mr/strings.xml | 5 +- .../voicemail/impl/res/values-ms/strings.xml | 5 +- .../voicemail/impl/res/values-my/strings.xml | 5 +- .../voicemail/impl/res/values-nb/strings.xml | 5 +- .../voicemail/impl/res/values-ne/strings.xml | 5 +- .../voicemail/impl/res/values-nl/strings.xml | 5 +- .../voicemail/impl/res/values-no/strings.xml | 5 +- .../voicemail/impl/res/values-pa/strings.xml | 5 +- .../voicemail/impl/res/values-pl/strings.xml | 5 +- .../voicemail/impl/res/values-pt-rBR/strings.xml | 5 +- .../voicemail/impl/res/values-pt-rPT/strings.xml | 5 +- .../voicemail/impl/res/values-pt/strings.xml | 5 +- .../voicemail/impl/res/values-ro/strings.xml | 5 +- .../voicemail/impl/res/values-ru/strings.xml | 5 +- .../voicemail/impl/res/values-si/strings.xml | 5 +- .../voicemail/impl/res/values-sk/strings.xml | 5 +- .../voicemail/impl/res/values-sl/strings.xml | 5 +- .../voicemail/impl/res/values-sq/strings.xml | 5 +- .../voicemail/impl/res/values-sr/strings.xml | 5 +- .../voicemail/impl/res/values-sv/strings.xml | 5 +- .../voicemail/impl/res/values-sw/strings.xml | 5 +- .../voicemail/impl/res/values-ta/strings.xml | 5 +- .../voicemail/impl/res/values-te/strings.xml | 5 +- .../voicemail/impl/res/values-th/strings.xml | 5 +- .../voicemail/impl/res/values-tl/strings.xml | 5 +- .../voicemail/impl/res/values-tr/strings.xml | 5 +- .../voicemail/impl/res/values-uk/strings.xml | 5 +- .../voicemail/impl/res/values-ur/strings.xml | 5 +- .../voicemail/impl/res/values-uz/strings.xml | 5 +- .../voicemail/impl/res/values-vi/strings.xml | 5 +- .../voicemail/impl/res/values-zh-rCN/strings.xml | 5 +- .../voicemail/impl/res/values-zh-rHK/strings.xml | 5 +- .../voicemail/impl/res/values-zh-rTW/strings.xml | 5 +- .../voicemail/impl/res/values-zu/strings.xml | 5 +- .../android/voicemail/impl/res/values/strings.xml | 15 +- .../voicemail/impl/res/xml/voicemail_settings.xml | 13 +- .../voicemail/impl/scheduling/BaseTask.java | 2 +- .../impl/scheduling/MinimalIntervalPolicy.java | 2 +- .../voicemail/impl/scheduling/RetryPolicy.java | 2 +- .../android/voicemail/impl/scheduling/Task.java | 8 +- .../voicemail/impl/scheduling/TaskExecutor.java | 455 +++++++++++++++++++++ .../voicemail/impl/scheduling/TaskReceiver.java | 80 ++++ .../impl/scheduling/TaskSchedulerJobService.java | 60 ++- .../android/voicemail/impl/scheduling/Tasks.java | 5 +- .../impl/settings/VoicemailSettingsFragment.java | 50 +-- .../voicemail/impl/sms/OmtpMessageReceiver.java | 4 +- .../voicemail/impl/sms/OmtpMessageSender.java | 6 +- .../voicemail/impl/sms/StatusSmsFetcher.java | 6 +- .../voicemail/impl/sync/OmtpVvmSyncService.java | 39 +- .../android/voicemail/impl/sync/SyncOneTask.java | 2 +- java/com/android/voicemail/impl/sync/SyncTask.java | 2 +- .../android/voicemail/impl/sync/UploadTask.java | 2 +- .../voicemail/impl/sync/VoicemailsQueryHelper.java | 24 +- java/com/android/voicemail/permissions.xml | 2 +- 113 files changed, 1413 insertions(+), 491 deletions(-) create mode 100644 java/com/android/voicemail/impl/OmtpService.java create mode 100644 java/com/android/voicemail/impl/PreOMigrationHandler.java create mode 100644 java/com/android/voicemail/impl/VvmPackageInstallHandler.java create mode 100644 java/com/android/voicemail/impl/scheduling/TaskExecutor.java create mode 100644 java/com/android/voicemail/impl/scheduling/TaskReceiver.java (limited to 'java/com/android/voicemail') diff --git a/java/com/android/voicemail/impl/ActivationTask.java b/java/com/android/voicemail/impl/ActivationTask.java index b0ad3bafc..91e369531 100644 --- a/java/com/android/voicemail/impl/ActivationTask.java +++ b/java/com/android/voicemail/impl/ActivationTask.java @@ -31,6 +31,7 @@ import android.telephony.ServiceState; import android.telephony.TelephonyManager; import com.android.dialer.logging.DialerImpression; import com.android.dialer.proguard.UsedByReflection; +import com.android.voicemail.VoicemailClient; import com.android.voicemail.impl.protocol.VisualVoicemailProtocol; import com.android.voicemail.impl.scheduling.BaseTask; import com.android.voicemail.impl.scheduling.RetryPolicy; @@ -105,7 +106,7 @@ public class ActivationTask extends BaseTask { if (messageData != null) { intent.putExtra(EXTRA_MESSAGE_DATA_BUNDLE, messageData); } - context.startService(intent); + context.sendBroadcast(intent); } @Override @@ -136,6 +137,8 @@ public class ActivationTask extends BaseTask { return; } + PreOMigrationHandler.migrate(getContext(), phoneAccountHandle); + if (!VisualVoicemailSettingsUtil.isEnabled(getContext(), phoneAccountHandle)) { VvmLog.i(TAG, "VVM is disabled"); return; @@ -163,6 +166,7 @@ public class ActivationTask extends BaseTask { if (VvmAccountManager.isAccountActivated(getContext(), phoneAccountHandle)) { VvmLog.i(TAG, "Account is already activated"); + onSuccess(getContext(), phoneAccountHandle); return; } helper.handleEvent( @@ -222,7 +226,7 @@ public class ActivationTask extends BaseTask { + message.getReturnCode()); if (message.getProvisioningStatus().equals(OmtpConstants.SUBSCRIBER_READY)) { VvmLog.d(TAG, "subscriber ready, no activation required"); - updateSource(getContext(), phoneAccountHandle, status, message); + updateSource(getContext(), phoneAccountHandle, message); } else { if (helper.supportsProvisioning()) { VvmLog.i(TAG, "Subscriber not ready, start provisioning"); @@ -232,7 +236,7 @@ public class ActivationTask extends BaseTask { VvmLog.i(TAG, "Subscriber new but provisioning is not supported"); // Ignore the non-ready state and attempt to use the provided info as is. // This is probably caused by not completing the new user tutorial. - updateSource(getContext(), phoneAccountHandle, status, message); + updateSource(getContext(), phoneAccountHandle, message); } else { VvmLog.i(TAG, "Subscriber not ready but provisioning is not supported"); helper.handleEvent(status, OmtpEvents.CONFIG_SERVICE_NOT_AVAILABLE); @@ -242,25 +246,38 @@ public class ActivationTask extends BaseTask { getContext(), DialerImpression.Type.VVM_ACTIVATION_COMPLETED); } - public static void updateSource( - Context context, - PhoneAccountHandle phone, - VoicemailStatus.Editor status, - StatusMessage message) { + private static void updateSource( + Context context, PhoneAccountHandle phone, StatusMessage message) { if (OmtpConstants.SUCCESS.equals(message.getReturnCode())) { - OmtpVvmCarrierConfigHelper helper = new OmtpVvmCarrierConfigHelper(context, phone); - helper.handleEvent(status, OmtpEvents.CONFIG_REQUEST_STATUS_SUCCESS); - // Save the IMAP credentials in preferences so they are persistent and can be retrieved. VvmAccountManager.addAccount(context, phone, message); - - SyncTask.start(context, phone, OmtpVvmSyncService.SYNC_FULL_SYNC); + onSuccess(context, phone); } else { VvmLog.e(TAG, "Visual voicemail not available for subscriber."); } } + private static void onSuccess(Context context, PhoneAccountHandle phoneAccountHandle) { + OmtpVvmCarrierConfigHelper helper = new OmtpVvmCarrierConfigHelper(context, phoneAccountHandle); + helper.handleEvent( + VoicemailStatus.edit(context, phoneAccountHandle), + OmtpEvents.CONFIG_REQUEST_STATUS_SUCCESS); + clearLegacyVoicemailNotification(context, phoneAccountHandle); + SyncTask.start(context, phoneAccountHandle, OmtpVvmSyncService.SYNC_FULL_SYNC); + } + + /** Sends a broadcast to the dialer UI to clear legacy voicemail notifications if any. */ + private static void clearLegacyVoicemailNotification( + Context context, PhoneAccountHandle phoneAccountHandle) { + Intent intent = new Intent(VoicemailClient.ACTION_SHOW_LEGACY_VOICEMAIL); + intent.setPackage(context.getPackageName()); + intent.putExtra(TelephonyManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle); + // Setting voicemail message count to zero will clear the notification. + intent.putExtra(TelephonyManager.EXTRA_NOTIFICATION_COUNT, 0); + context.sendBroadcast(intent); + } + private static boolean hasSignal(Context context, PhoneAccountHandle phoneAccountHandle) { TelephonyManager telephonyManager = context diff --git a/java/com/android/voicemail/impl/AndroidManifest.xml b/java/com/android/voicemail/impl/AndroidManifest.xml index 47a4b2dd3..8c0d67f6b 100644 --- a/java/com/android/voicemail/impl/AndroidManifest.xml +++ b/java/com/android/voicemail/impl/AndroidManifest.xml @@ -31,7 +31,8 @@ + android:exported="false" + android:directBootAware="true"> @@ -40,7 +41,7 @@ - + @@ -76,8 +77,8 @@ - - + - + - + - - - - - - - - diff --git a/java/com/android/voicemail/impl/OmtpService.java b/java/com/android/voicemail/impl/OmtpService.java new file mode 100644 index 000000000..ad24e1243 --- /dev/null +++ b/java/com/android/voicemail/impl/OmtpService.java @@ -0,0 +1,153 @@ +/* + * 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.voicemail.impl; + +import android.annotation.TargetApi; +import android.content.Intent; +import android.os.Build.VERSION_CODES; +import android.os.UserManager; +import android.telecom.PhoneAccountHandle; +import android.telephony.VisualVoicemailService; +import android.telephony.VisualVoicemailSms; +import com.android.dialer.logging.DialerImpression; +import com.android.dialer.logging.Logger; +import com.android.voicemail.VoicemailComponent; +import com.android.voicemail.impl.settings.VisualVoicemailSettingsUtil; +import com.android.voicemail.impl.sync.VvmAccountManager; + +/** Implements {@link VisualVoicemailService} to receive visual voicemail events */ +@TargetApi(VERSION_CODES.O) +public class OmtpService extends VisualVoicemailService { + + private static final String TAG = "VvmOmtpService"; + + public static final String ACTION_SMS_RECEIVED = "com.android.vociemailomtp.sms.sms_received"; + + public static final String EXTRA_VOICEMAIL_SMS = "extra_voicemail_sms"; + + @Override + public void onCellServiceConnected( + VisualVoicemailTask task, final PhoneAccountHandle phoneAccountHandle) { + VvmLog.i(TAG, "onCellServiceConnected"); + if (!isModuleEnabled()) { + VvmLog.e(TAG, "onCellServiceConnected received when module is disabled"); + task.finish(); + return; + } + + if (!isUserUnlocked()) { + VvmLog.i(TAG, "onCellServiceConnected: user locked"); + task.finish(); + return; + } + + if (!isServiceEnabled(phoneAccountHandle)) { + task.finish(); + return; + } + + Logger.get(this).logImpression(DialerImpression.Type.VVM_UNBUNDLED_EVENT_RECEIVED); + ActivationTask.start(OmtpService.this, phoneAccountHandle, null); + task.finish(); + } + + @Override + public void onSmsReceived(VisualVoicemailTask task, final VisualVoicemailSms sms) { + VvmLog.i(TAG, "onSmsReceived"); + if (!isModuleEnabled()) { + VvmLog.e(TAG, "onSmsReceived received when module is disabled"); + task.finish(); + return; + } + + VvmPackageInstallHandler.scanNewPackages(this); + + if (!isServiceEnabled(sms.getPhoneAccountHandle())) { + task.finish(); + return; + } + + // isUserUnlocked() is not checked. OmtpMessageReceiver will handle the locked case. + + Logger.get(this).logImpression(DialerImpression.Type.VVM_UNBUNDLED_EVENT_RECEIVED); + Intent intent = new Intent(ACTION_SMS_RECEIVED); + intent.setPackage(getPackageName()); + intent.putExtra(EXTRA_VOICEMAIL_SMS, sms); + sendBroadcast(intent); + task.finish(); + } + + @Override + public void onSimRemoved( + final VisualVoicemailTask task, final PhoneAccountHandle phoneAccountHandle) { + VvmLog.i(TAG, "onSimRemoved"); + if (!isModuleEnabled()) { + VvmLog.e(TAG, "onSimRemoved called when module is disabled"); + task.finish(); + return; + } + + if (!isUserUnlocked()) { + VvmLog.i(TAG, "onSimRemoved: user locked"); + task.finish(); + return; + } + + Logger.get(this).logImpression(DialerImpression.Type.VVM_UNBUNDLED_EVENT_RECEIVED); + VvmAccountManager.removeAccount(this, phoneAccountHandle); + task.finish(); + } + + @Override + public void onStopped(VisualVoicemailTask task) { + VvmLog.i(TAG, "onStopped"); + if (!isModuleEnabled()) { + VvmLog.e(TAG, "onStopped called when module is disabled"); + task.finish(); + return; + } + if (!isUserUnlocked()) { + VvmLog.i(TAG, "onStopped: user locked"); + task.finish(); + return; + } + Logger.get(this).logImpression(DialerImpression.Type.VVM_UNBUNDLED_EVENT_RECEIVED); + } + + private boolean isModuleEnabled() { + return VoicemailComponent.get(this).getVoicemailClient().isVoicemailModuleEnabled(); + } + + private boolean isServiceEnabled(PhoneAccountHandle phoneAccountHandle) { + OmtpVvmCarrierConfigHelper config = new OmtpVvmCarrierConfigHelper(this, phoneAccountHandle); + if (!config.isValid()) { + VvmLog.i(TAG, "VVM not supported on " + phoneAccountHandle); + return false; + } + if (!VisualVoicemailSettingsUtil.isEnabled(this, phoneAccountHandle) + && !config.isLegacyModeEnabled()) { + VvmLog.i(TAG, "VVM is disabled"); + return false; + } + return true; + } + + private boolean isUserUnlocked() { + UserManager userManager = getSystemService(UserManager.class); + return userManager.isUserUnlocked(); + } +} diff --git a/java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java b/java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java index 2f1df09dd..04b3e73da 100644 --- a/java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java +++ b/java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java @@ -26,7 +26,6 @@ import android.support.annotation.VisibleForTesting; import android.telecom.PhoneAccountHandle; import android.telephony.CarrierConfigManager; import android.telephony.TelephonyManager; -import android.telephony.VisualVoicemailService; import android.telephony.VisualVoicemailSmsFilterSettings; import android.text.TextUtils; import android.util.ArraySet; @@ -234,9 +233,7 @@ public class OmtpVvmCarrierConfigHelper { return (String) getValue(KEY_VVM_DESTINATION_NUMBER_STRING); } - /** - * @return Port to start a SSL IMAP connection directly. - */ + /** @return Port to start a SSL IMAP connection directly. */ public int getSslPort() { Assert.checkArgument(isValid()); return (int) getValue(KEY_VVM_SSL_PORT_NUMBER_INT, 0); @@ -328,7 +325,7 @@ public class OmtpVvmCarrierConfigHelper { public void activateSmsFilter() { Assert.checkArgument(isValid()); - VisualVoicemailService.setSmsFilterSettings( + TelephonyMangerCompat.setVisualVoicemailSmsFilterSettings( mContext, getPhoneAccountHandle(), new VisualVoicemailSmsFilterSettings.Builder().setClientPrefix(getClientPrefix()).build()); @@ -339,7 +336,8 @@ public class OmtpVvmCarrierConfigHelper { VvmLog.i(TAG, "startDeactivation"); if (!isLegacyModeEnabled()) { // SMS should still be filtered in legacy mode - VisualVoicemailService.setSmsFilterSettings(mContext, getPhoneAccountHandle(), null); + TelephonyMangerCompat.setVisualVoicemailSmsFilterSettings( + mContext, getPhoneAccountHandle(), null); VvmLog.i(TAG, "filter disabled"); } if (mProtocol != null) { diff --git a/java/com/android/voicemail/impl/PreOMigrationHandler.java b/java/com/android/voicemail/impl/PreOMigrationHandler.java new file mode 100644 index 000000000..6dc2dee90 --- /dev/null +++ b/java/com/android/voicemail/impl/PreOMigrationHandler.java @@ -0,0 +1,102 @@ +/* + * 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.voicemail.impl; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.WorkerThread; +import android.telecom.PhoneAccountHandle; +import android.telephony.TelephonyManager; +import android.text.TextUtils; +import com.android.voicemail.impl.settings.VisualVoicemailSettingsUtil; +import com.android.voicemail.impl.settings.VoicemailChangePinActivity; +import java.lang.reflect.Method; + +/** Handles migration of data from the visual voicemail client in telephony before O. */ +public final class PreOMigrationHandler { + + // Hidden system APIs to access pre O VVM data + // Bundle getVisualVoicemailSettings() + private static final String METHOD_GET_VISUAL_VOICEMAIL_SETTINGS = "getVisualVoicemailSettings"; + + /** + * Key in bundle returned by {@link #METHOD_GET_VISUAL_VOICEMAIL_SETTINGS}, indicating whether + * visual voicemail was enabled or disabled by the user. If the user never explicitly changed this + * setting, this key will not exist. + */ + private static final String EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL = + "android.telephony.extra.VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL"; + + /** + * Key in bundle returned by {@link #METHOD_GET_VISUAL_VOICEMAIL_SETTINGS}, indicating the + * voicemail access PIN scrambled during the auto provisioning process. The user is expected to + * reset their PIN if this value is not {@code null}. + */ + private static final String EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING = + "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING"; + + private static final String PRE_O_MIGRATION_FINISHED = "pre_o_migration_finished"; + + @WorkerThread + public static void migrate(Context context, PhoneAccountHandle phoneAccountHandle) { + Assert.isNotMainThread(); + VisualVoicemailPreferences preferences = + new VisualVoicemailPreferences(context, phoneAccountHandle); + if (preferences.getBoolean(PRE_O_MIGRATION_FINISHED, false)) { + VvmLog.i("PreOMigrationHandler", phoneAccountHandle + " already migrated"); + return; + } + VvmLog.i("PreOMigrationHandler", "migrating " + phoneAccountHandle); + migrateSettings(context, phoneAccountHandle); + + preferences.edit().putBoolean(PRE_O_MIGRATION_FINISHED, true).apply(); + } + + private static void migrateSettings(Context context, PhoneAccountHandle phoneAccountHandle) { + VvmLog.i("PreOMigrationHandler.migrateSettings", "migrating settings"); + TelephonyManager telephonyManager = + context + .getSystemService(TelephonyManager.class) + .createForPhoneAccountHandle(phoneAccountHandle); + if (telephonyManager == null) { + VvmLog.e("PreOMigrationHandler.migrateSettings", "invalid PhoneAccountHandle"); + return; + } + Bundle legacySettings; + try { + Method method = TelephonyManager.class.getMethod(METHOD_GET_VISUAL_VOICEMAIL_SETTINGS); + legacySettings = (Bundle) method.invoke(telephonyManager); + } catch (ReflectiveOperationException | ClassCastException e) { + VvmLog.i("PreOMigrationHandler.migrateSettings", "unable to retrieve settings from system"); + return; + } + + if (legacySettings.containsKey(EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL)) { + boolean enabled = legacySettings.getBoolean(EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL); + VvmLog.i("PreOMigrationHandler.migrateSettings", "setting VVM enabled to " + enabled); + VisualVoicemailSettingsUtil.setEnabled(context, phoneAccountHandle, enabled); + } + + if (legacySettings.containsKey(EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING)) { + String scrambledPin = legacySettings.getString(EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING); + if (!TextUtils.isEmpty(scrambledPin)) { + VvmLog.i("PreOMigrationHandler.migrateSettings", "migrating scrambled PIN"); + VoicemailChangePinActivity.setDefaultOldPIN(context, phoneAccountHandle, scrambledPin); + } + } + } +} diff --git a/java/com/android/voicemail/impl/StatusCheckTask.java b/java/com/android/voicemail/impl/StatusCheckTask.java index 7699e9848..e59eb3b37 100644 --- a/java/com/android/voicemail/impl/StatusCheckTask.java +++ b/java/com/android/voicemail/impl/StatusCheckTask.java @@ -51,7 +51,7 @@ public class StatusCheckTask extends BaseTask { public static void start(Context context, PhoneAccountHandle phoneAccountHandle) { Intent intent = BaseTask.createIntent(context, StatusCheckTask.class, phoneAccountHandle); - context.startService(intent); + context.sendBroadcast(intent); } @Override diff --git a/java/com/android/voicemail/impl/TelephonyMangerCompat.java b/java/com/android/voicemail/impl/TelephonyMangerCompat.java index 353cd69e3..404b4d6ca 100644 --- a/java/com/android/voicemail/impl/TelephonyMangerCompat.java +++ b/java/com/android/voicemail/impl/TelephonyMangerCompat.java @@ -16,24 +16,36 @@ package com.android.voicemail.impl; +import android.app.PendingIntent; +import android.content.Context; import android.telecom.PhoneAccountHandle; import android.telephony.TelephonyManager; +import android.telephony.VisualVoicemailService; +import android.telephony.VisualVoicemailSmsFilterSettings; +import com.android.dialer.common.LogUtil; import java.lang.reflect.Method; /** Handles {@link TelephonyManager} API changes in experimental SDK */ public class TelephonyMangerCompat { - - private static final String GET_VISUAL_VOICEMAIL_PACKGE_NAME = "getVisualVoicemailPackageName"; - - /** - * Changed from getVisualVoicemailPackageName(PhoneAccountHandle) to - * getVisualVoicemailPackageName() - */ - public static String getVisualVoicemailPackageName(TelephonyManager telephonyManager) { + /** Moved from VisualVoicemailService to TelephonyManager */ + public static String sendVisualVoicemailSms( + Context context, + PhoneAccountHandle phoneAccountHandle, + String number, + int port, + String text, + PendingIntent sentIntent) { try { - Method method = TelephonyManager.class.getMethod(GET_VISUAL_VOICEMAIL_PACKGE_NAME); + Method method = + TelephonyManager.class.getMethod( + "sendVisualVoicemailSms", String.class, int.class, String.class, PendingIntent.class); try { - return (String) method.invoke(telephonyManager); + LogUtil.i("TelephonyMangerCompat.sendVisualVoicemailSms", "using TelephonyManager"); + TelephonyManager telephonyManager = + context + .getSystemService(TelephonyManager.class) + .createForPhoneAccountHandle(phoneAccountHandle); + return (String) method.invoke(telephonyManager, number, port, text, sentIntent); } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } @@ -41,16 +53,62 @@ public class TelephonyMangerCompat { // Do nothing, try the next version. } + try { + LogUtil.i("TelephonyMangerCompat.sendVisualVoicemailSms", "using VisualVoicemailService"); + Method method = + VisualVoicemailService.class.getMethod( + "sendVisualVoicemailSms", + Context.class, + PhoneAccountHandle.class, + String.class, + short.class, + String.class, + PendingIntent.class); + return (String) + method.invoke(null, context, phoneAccountHandle, number, (short) port, text, sentIntent); + + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + /** Moved from VisualVoicemailService to TelephonyManager */ + public static String setVisualVoicemailSmsFilterSettings( + Context context, + PhoneAccountHandle phoneAccountHandle, + VisualVoicemailSmsFilterSettings settings) { try { Method method = TelephonyManager.class.getMethod( - GET_VISUAL_VOICEMAIL_PACKGE_NAME, PhoneAccountHandle.class); + "setVisualVoicemailSmsFilterSettings", VisualVoicemailSmsFilterSettings.class); try { - return (String) method.invoke(telephonyManager, (Object) null); + LogUtil.i( + "TelephonyMangerCompat.setVisualVoicemailSmsFilterSettings", "using TelephonyManager"); + TelephonyManager telephonyManager = + context + .getSystemService(TelephonyManager.class) + .createForPhoneAccountHandle(phoneAccountHandle); + return (String) method.invoke(telephonyManager, settings); } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } } catch (NoSuchMethodException e) { + // Do nothing, try the next version. + } + + try { + LogUtil.i( + "TelephonyMangerCompat.setVisualVoicemailSmsFilterSettings", + "using VisualVoicemailService"); + Method method = + VisualVoicemailService.class.getMethod( + "setSmsFilterSettings", + Context.class, + PhoneAccountHandle.class, + VisualVoicemailSmsFilterSettings.class); + return (String) method.invoke(null, context, phoneAccountHandle, settings); + + } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } } diff --git a/java/com/android/voicemail/impl/VoicemailClientImpl.java b/java/com/android/voicemail/impl/VoicemailClientImpl.java index 7747b2486..83c0523bf 100644 --- a/java/com/android/voicemail/impl/VoicemailClientImpl.java +++ b/java/com/android/voicemail/impl/VoicemailClientImpl.java @@ -130,8 +130,8 @@ public class VoicemailClientImpl implements VoicemailClient { @Override public void appendOmtpVoicemailSelectionClause( Context context, StringBuilder where, List selectionArgs) { - TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class); - String omtpSource = TelephonyMangerCompat.getVisualVoicemailPackageName(telephonyManager); + String omtpSource = + context.getSystemService(TelephonyManager.class).getVisualVoicemailPackageName(); if (where.length() != 0) { where.append(" AND "); } @@ -162,8 +162,8 @@ public class VoicemailClientImpl implements VoicemailClient { @Override public void appendOmtpVoicemailStatusSelectionClause( Context context, StringBuilder where, List selectionArgs) { - TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class); - String omtpSource = TelephonyMangerCompat.getVisualVoicemailPackageName(telephonyManager); + String omtpSource = + context.getSystemService(TelephonyManager.class).getVisualVoicemailPackageName(); if (where.length() != 0) { where.append(" AND "); } diff --git a/java/com/android/voicemail/impl/VvmPackageInstallHandler.java b/java/com/android/voicemail/impl/VvmPackageInstallHandler.java new file mode 100644 index 000000000..8d1fb2289 --- /dev/null +++ b/java/com/android/voicemail/impl/VvmPackageInstallHandler.java @@ -0,0 +1,167 @@ +/* + * 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.voicemail.impl; + +import android.annotation.SuppressLint; +import android.annotation.TargetApi; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.pm.ChangedPackages; +import android.os.Build.VERSION_CODES; +import android.preference.PreferenceManager; +import android.provider.Settings.Global; +import android.telecom.PhoneAccountHandle; +import android.telecom.TelecomManager; +import android.util.ArraySet; +import com.android.dialer.common.PackageUtils; +import com.android.voicemail.impl.settings.VisualVoicemailSettingsUtil; +import java.util.Set; + +/** + * When a new package is installed, check if it matches any of the vvm carrier apps of the currently + * enabled dialer VVM sources. The dialer VVM client will be disabled upon carrier VVM app + * installation, unless it was explicitly enabled by the user. + * + *

The ACTION_PACKAGE_ADDED broadcast can no longer be received. (see + * https://developer.android.com/preview/features/background.html#broadcasts) New apps are scanned + * when a VVM SMS is received instead, as it can be a result of the carrier VVM app trying to run + * activation. + */ +@SuppressLint("AndroidApiChecker") // forEach +@TargetApi(VERSION_CODES.O) +public final class VvmPackageInstallHandler { + + private static final String LAST_BOOT_COUNT = + "com.android.voicemail.impl.VvmPackageInstallHandler.LAST_BOOT_COUNT"; + + private static final String CHANGED_PACKAGES_SEQUENCE_NUMBER = + "com.android.voicemail.impl.VvmPackageInstallHandler.CHANGED_PACKAGES_SEQUENCE_NUMBER"; + + private static final String INSTALLED_CARRIER_PACKAGES = + "com.android.voicemail.impl.VvmPackageInstallHandler.INSTALLED_CARRIER_PACKAGES"; + + /** + * Perform a scan of all changed apps since the last invocation to see if the carrier VVM app is + * installed. + */ + public static void scanNewPackages(Context context) { + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); + int sequenceNumber = sharedPreferences.getInt(CHANGED_PACKAGES_SEQUENCE_NUMBER, 0); + int lastBootCount = sharedPreferences.getInt(LAST_BOOT_COUNT, 0); + int bootCount = Global.getInt(context.getContentResolver(), Global.BOOT_COUNT, 0); + if (lastBootCount != bootCount) { + VvmLog.i( + "VvmPackageInstallHandler.scanNewPackages", "reboot detected, resetting sequence number"); + sequenceNumber = 0; + sharedPreferences.edit().putInt(LAST_BOOT_COUNT, bootCount).apply(); + } + + ChangedPackages changedPackages = + context.getPackageManager().getChangedPackages(sequenceNumber); + if (changedPackages == null) { + VvmLog.i("VvmPackageInstallHandler.scanNewPackages", "no package has changed"); + return; + } + sharedPreferences + .edit() + .putInt(CHANGED_PACKAGES_SEQUENCE_NUMBER, changedPackages.getSequenceNumber()) + .apply(); + + Set installedPackages = + sharedPreferences.getStringSet(INSTALLED_CARRIER_PACKAGES, new ArraySet<>()); + + Set monitoredPackage = getMonitoredPackages(context); + installedPackages.removeIf((packageName) -> !monitoredPackage.contains(packageName)); + + for (String packageName : changedPackages.getPackageNames()) { + if (!monitoredPackage.contains(packageName)) { + continue; + } + if (PackageUtils.isPackageEnabled(packageName, context)) { + if (!installedPackages.contains(packageName)) { + VvmLog.i("VvmPackageInstallHandler.scanNewPackages", "new package found: " + packageName); + installedPackages.add(packageName); + handlePackageInstalled(context, packageName); + } + } else { + installedPackages.remove(packageName); + } + } + sharedPreferences.edit().putStringSet(INSTALLED_CARRIER_PACKAGES, installedPackages).apply(); + } + + private static Set getMonitoredPackages(Context context) { + Set result = new ArraySet<>(); + context + .getSystemService(TelecomManager.class) + .getCallCapablePhoneAccounts() + .forEach( + (phoneAccountHandle -> { + OmtpVvmCarrierConfigHelper carrierConfigHelper = + new OmtpVvmCarrierConfigHelper(context, phoneAccountHandle); + if (!carrierConfigHelper.isValid()) { + return; + } + if (carrierConfigHelper.getCarrierVvmPackageNames() == null) { + return; + } + result.addAll(carrierConfigHelper.getCarrierVvmPackageNames()); + })); + + return result; + }; + + /** + * Iterates through all phone account and disable VVM on a account if {@code packageName} is + * listed as a carrier VVM package. + */ + private static void handlePackageInstalled(Context context, String packageName) { + // This get called every time an app is installed and will be noisy. Don't log until the app + // is identified as a carrier VVM app. + for (PhoneAccountHandle phoneAccount : + context.getSystemService(TelecomManager.class).getCallCapablePhoneAccounts()) { + OmtpVvmCarrierConfigHelper carrierConfigHelper = + new OmtpVvmCarrierConfigHelper(context, phoneAccount); + if (!carrierConfigHelper.isValid()) { + continue; + } + if (carrierConfigHelper.getCarrierVvmPackageNames() == null) { + continue; + } + if (!carrierConfigHelper.getCarrierVvmPackageNames().contains(packageName)) { + continue; + } + + VvmLog.i("VvmPackageInstallHandler.handlePackageInstalled", "Carrier app installed"); + if (VisualVoicemailSettingsUtil.isEnabledUserSet(context, phoneAccount)) { + // Skip the check if this voicemail source's setting is overridden by the user. + VvmLog.i( + "VvmPackageInstallHandler.handlePackageInstalled", + "VVM enabled by user, not disabling"); + continue; + } + + // Force deactivate the client. The user can re-enable it in the settings. + // There is no need to update the settings for deactivation. At this point, if the + // default value is used it should be false because a carrier package is present. + VvmLog.i( + "VvmPackageInstallHandler.handlePackageInstalled", + "Carrier VVM package installed, disabling system VVM client"); + VisualVoicemailSettingsUtil.setEnabled(context, phoneAccount, false); + } + } +} diff --git a/java/com/android/voicemail/impl/imap/ImapHelper.java b/java/com/android/voicemail/impl/imap/ImapHelper.java index 6aa415811..f1bc8b221 100644 --- a/java/com/android/voicemail/impl/imap/ImapHelper.java +++ b/java/com/android/voicemail/impl/imap/ImapHelper.java @@ -19,7 +19,7 @@ import android.content.Context; import android.net.ConnectivityManager; import android.net.Network; import android.net.NetworkInfo; -import android.provider.VoicemailContract; +import android.support.annotation.Nullable; import android.telecom.PhoneAccountHandle; import android.util.Base64; import com.android.voicemail.impl.OmtpConstants; @@ -44,6 +44,7 @@ import com.android.voicemail.impl.mail.TempDirectory; import com.android.voicemail.impl.mail.internet.MimeMessage; import com.android.voicemail.impl.mail.store.ImapConnection; import com.android.voicemail.impl.mail.store.ImapFolder; +import com.android.voicemail.impl.mail.store.ImapFolder.Quota; import com.android.voicemail.impl.mail.store.ImapStore; import com.android.voicemail.impl.mail.store.imap.ImapConstants; import com.android.voicemail.impl.mail.store.imap.ImapResponse; @@ -73,11 +74,6 @@ public class ImapHelper implements Closeable { private final Editor mStatus; VisualVoicemailPreferences mPrefs; - private static final String PREF_KEY_QUOTA_OCCUPIED = "quota_occupied_"; - private static final String PREF_KEY_QUOTA_TOTAL = "quota_total_"; - - private int mQuotaOccupied; - private int mQuotaTotal; private final OmtpVvmCarrierConfigHelper mConfig; @@ -90,10 +86,7 @@ public class ImapHelper implements Closeable { } public ImapHelper( - Context context, - PhoneAccountHandle phoneAccount, - Network network, - Editor status) + Context context, PhoneAccountHandle phoneAccount, Network network, Editor status) throws InitializingException { this( context, @@ -139,10 +132,6 @@ public class ImapHelper implements Closeable { LogUtils.w(TAG, "Could not parse port number"); throw new InitializingException("cannot initialize ImapHelper:" + e.toString()); } - - mQuotaOccupied = - mPrefs.getInt(PREF_KEY_QUOTA_OCCUPIED, VoicemailContract.Status.QUOTA_UNAVAILABLE); - mQuotaTotal = mPrefs.getInt(PREF_KEY_QUOTA_TOTAL, VoicemailContract.Status.QUOTA_UNAVAILABLE); } @Override @@ -475,12 +464,22 @@ public class ImapHelper implements Closeable { } } - public int getOccuupiedQuota() { - return mQuotaOccupied; - } - - public int getTotalQuota() { - return mQuotaTotal; + @Nullable + public Quota getQuota() { + try { + mFolder = openImapFolder(ImapFolder.MODE_READ_ONLY); + if (mFolder == null) { + // This means we were unable to successfully open the folder. + LogUtils.e(TAG, "Unable to open folder"); + return null; + } + return mFolder.getQuota(); + } catch (MessagingException e) { + LogUtils.e(TAG, e, "Messaging Exception"); + return null; + } finally { + closeImapFolder(); + } } private void updateQuota(ImapFolder folder) throws MessagingException { @@ -489,21 +488,19 @@ public class ImapHelper implements Closeable { private void setQuota(ImapFolder.Quota quota) { if (quota == null) { + LogUtils.i(TAG, "quota was null"); return; } - if (quota.occupied == mQuotaOccupied && quota.total == mQuotaTotal) { - VvmLog.v(TAG, "Quota hasn't changed"); - return; - } - mQuotaOccupied = quota.occupied; - mQuotaTotal = quota.total; - VoicemailStatus.edit(mContext, mPhoneAccount).setQuota(mQuotaOccupied, mQuotaTotal).apply(); - mPrefs - .edit() - .putInt(PREF_KEY_QUOTA_OCCUPIED, mQuotaOccupied) - .putInt(PREF_KEY_QUOTA_TOTAL, mQuotaTotal) - .apply(); - VvmLog.v(TAG, "Quota changed to " + mQuotaOccupied + "/" + mQuotaTotal); + + LogUtils.i( + TAG, + "Updating Voicemail status table with" + + " quota occupied: " + + quota.occupied + + " new quota total:" + + quota.total); + VoicemailStatus.edit(mContext, mPhoneAccount).setQuota(quota.occupied, quota.total).apply(); + LogUtils.i(TAG, "Updated quota occupied and total"); } /** diff --git a/java/com/android/voicemail/impl/protocol/Vvm3Subscriber.java b/java/com/android/voicemail/impl/protocol/Vvm3Subscriber.java index c8a74c8d5..1cdbbfbca 100644 --- a/java/com/android/voicemail/impl/protocol/Vvm3Subscriber.java +++ b/java/com/android/voicemail/impl/protocol/Vvm3Subscriber.java @@ -17,10 +17,13 @@ package com.android.voicemail.impl.protocol; import android.annotation.TargetApi; +import android.content.Context; import android.net.Network; import android.os.Build; import android.os.Build.VERSION_CODES; import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.VisibleForTesting; import android.support.annotation.WorkerThread; import android.telecom.PhoneAccountHandle; import android.telephony.TelephonyManager; @@ -28,6 +31,7 @@ import android.text.Html; import android.text.Spanned; import android.text.style.URLSpan; import android.util.ArrayMap; +import com.android.dialer.common.ConfigProviderBindings; import com.android.voicemail.impl.ActivationTask; import com.android.voicemail.impl.Assert; import com.android.voicemail.impl.OmtpEvents; @@ -49,6 +53,8 @@ import java.net.CookieHandler; import java.net.CookieManager; import java.net.HttpURLConnection; import java.net.URL; +import java.util.ArrayList; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Random; @@ -57,6 +63,8 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.json.JSONArray; +import org.json.JSONException; /** * Class to subscribe to basic VVM3 visual voicemail, for example, Verizon. Subscription is required @@ -111,7 +119,15 @@ public class Vvm3Subscriber { private static final String SPG_LANGUAGE_PARAM = "SPG_LANGUAGE_PARAM"; private static final String SPG_LANGUAGE_EN = "ENGLISH"; - private static final String BASIC_SUBSCRIBE_LINK_TEXT = "Subscribe to Basic Visual Voice Mail"; + @VisibleForTesting + static final String VVM3_SUBSCRIBE_LINK_PATTERNS_JSON_ARRAY = + "vvm3_subscribe_link_pattern_json_array"; + + private static final String VVM3_SUBSCRIBE_LINK_DEFAULT_PATTERNS = + "[" + + "\"(?i)Subscribe to Basic Visual Voice Mail\"," + + "\"(?i)Subscribe to Basic Visual Voicemail\"" + + "]"; private static final int REQUEST_TIMEOUT_SECONDS = 30; @@ -125,7 +141,8 @@ public class Vvm3Subscriber { private RequestQueue mRequestQueue; - private static class ProvisioningException extends Exception { + @VisibleForTesting + static class ProvisioningException extends Exception { public ProvisioningException(String message) { super(message); @@ -188,7 +205,8 @@ public class Vvm3Subscriber { try { String gatewayUrl = getSelfProvisioningGateway(); String selfProvisionResponse = getSelfProvisionResponse(gatewayUrl); - String subscribeLink = findSubscribeLink(selfProvisionResponse); + String subscribeLink = + findSubscribeLink(getSubscribeLinkPatterns(mHelper.getContext()), selfProvisionResponse); clickSubscribeLink(subscribeLink); } catch (ProvisioningException e) { VvmLog.e(TAG, e.toString()); @@ -291,14 +309,40 @@ public class Vvm3Subscriber { } } - private String findSubscribeLink(String response) throws ProvisioningException { + @VisibleForTesting + static List getSubscribeLinkPatterns(Context context) { + String patternsJsonString = + ConfigProviderBindings.get(context) + .getString( + VVM3_SUBSCRIBE_LINK_PATTERNS_JSON_ARRAY, VVM3_SUBSCRIBE_LINK_DEFAULT_PATTERNS); + List patterns = new ArrayList<>(); + try { + JSONArray patternsArray = new JSONArray(patternsJsonString); + for (int i = 0; i < patternsArray.length(); i++) { + patterns.add(Pattern.compile(patternsArray.getString(i))); + } + } catch (JSONException e) { + throw new IllegalArgumentException("Unable to parse patterns" + e); + } + return patterns; + } + + @VisibleForTesting + static String findSubscribeLink(@NonNull List patterns, String response) + throws ProvisioningException { + if (patterns.isEmpty()) { + throw new IllegalArgumentException("empty patterns"); + } Spanned doc = Html.fromHtml(response, Html.FROM_HTML_MODE_LEGACY); URLSpan[] spans = doc.getSpans(0, doc.length(), URLSpan.class); StringBuilder fulltext = new StringBuilder(); + for (URLSpan span : spans) { String text = doc.subSequence(doc.getSpanStart(span), doc.getSpanEnd(span)).toString(); - if (BASIC_SUBSCRIBE_LINK_TEXT.equals(text)) { - return span.getURL(); + for (Pattern pattern : patterns) { + if (pattern.matcher(text).matches()) { + return span.getURL(); + } } fulltext.append(text); } diff --git a/java/com/android/voicemail/impl/res/values-af/strings.xml b/java/com/android/voicemail/impl/res/values-af/strings.xml index 71263217f..a84553480 100644 --- a/java/com/android/voicemail/impl/res/values-af/strings.xml +++ b/java/com/android/voicemail/impl/res/values-af/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Stemboodskap (%s)" "Stemboodskap" - "Vibreer" - "Vibreer" - "Klank" + + "Gevorderde instellings" "Visuele stemboodskap" "Ekstra rugsteun en berging" diff --git a/java/com/android/voicemail/impl/res/values-am/strings.xml b/java/com/android/voicemail/impl/res/values-am/strings.xml index d350bbd94..2f0719a0b 100644 --- a/java/com/android/voicemail/impl/res/values-am/strings.xml +++ b/java/com/android/voicemail/impl/res/values-am/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "የድምፅ መልዕክት (%s)" "የድምፅ መልዕክት" - "ንዘር" - "ንዘር" - "ድምፅ" + + "የላቁ ቅንብሮች" "ምስላዊ የድምፅ መልዕክት" "ተጨማሪ ምትኬ እና ማከማቻ" diff --git a/java/com/android/voicemail/impl/res/values-ar/strings.xml b/java/com/android/voicemail/impl/res/values-ar/strings.xml index 679dcce9c..f46ebe1be 100644 --- a/java/com/android/voicemail/impl/res/values-ar/strings.xml +++ b/java/com/android/voicemail/impl/res/values-ar/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "البريد الصوتي (%s)" "البريد الصوتي" - "اهتزاز" - "اهتزاز" - "صوت" + + "الإعدادات المتقدمة" "بريد صوتي مرئي" "نسخة احتياطية وسعة تخزين إضافية" diff --git a/java/com/android/voicemail/impl/res/values-az/strings.xml b/java/com/android/voicemail/impl/res/values-az/strings.xml index 87b4c0692..ebb85dce8 100644 --- a/java/com/android/voicemail/impl/res/values-az/strings.xml +++ b/java/com/android/voicemail/impl/res/values-az/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Səsli e-poçt (%s)" "Səsli e-poçt" - "Vibrasiya" - "Vibrasiya" - "Səs" + + "Qabaqcıl Ayarlar" "Görünən Səsli e-poçt" "Əlavə yedəkləmə və yaddaş" diff --git a/java/com/android/voicemail/impl/res/values-b+sr+Latn/strings.xml b/java/com/android/voicemail/impl/res/values-b+sr+Latn/strings.xml index 193913081..41294300b 100644 --- a/java/com/android/voicemail/impl/res/values-b+sr+Latn/strings.xml +++ b/java/com/android/voicemail/impl/res/values-b+sr+Latn/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Govorna pošta (%s)" "Govorna pošta" - "Vibracija" - "Vibracija" - "Zvuk" + + "Napredna podešavanja" "Vizuelna govorna pošta" "Dodatne rezervne kopije i prostor" diff --git a/java/com/android/voicemail/impl/res/values-be/strings.xml b/java/com/android/voicemail/impl/res/values-be/strings.xml index 874b4791a..ffb7caba0 100644 --- a/java/com/android/voicemail/impl/res/values-be/strings.xml +++ b/java/com/android/voicemail/impl/res/values-be/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Галасавая пошта (%s)" "Галасавая пошта" - "Вібрацыя" - "Вібрацыя" - "Гук" + + "Пашыраныя налады" "Візуальная галасавая пошта" "Дадатковае рэзервовае капір. і сховішча" diff --git a/java/com/android/voicemail/impl/res/values-bg/strings.xml b/java/com/android/voicemail/impl/res/values-bg/strings.xml index f987015e9..d3a66a41c 100644 --- a/java/com/android/voicemail/impl/res/values-bg/strings.xml +++ b/java/com/android/voicemail/impl/res/values-bg/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Гласова поща (%s)" "Гласова поща" - "Вибриране" - "Вибриране" - "Звук" + + "Разширени настройки" "Визуална гласова поща" "Допълнителни резервни копия и хранилище" diff --git a/java/com/android/voicemail/impl/res/values-bn/strings.xml b/java/com/android/voicemail/impl/res/values-bn/strings.xml index 699576d41..636f332cb 100644 --- a/java/com/android/voicemail/impl/res/values-bn/strings.xml +++ b/java/com/android/voicemail/impl/res/values-bn/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ভয়েসমেল (%s)" "ভয়েসমেল" - "কম্পন" - "কম্পন" - "শব্দ" + + "উন্নত সেটিংস" "ভিজ্যুয়াল ভয়েসমেল" "অতিরিক্ত ব্যাক আপ এবং সঞ্চয়স্থান" diff --git a/java/com/android/voicemail/impl/res/values-bs/strings.xml b/java/com/android/voicemail/impl/res/values-bs/strings.xml index 2c8cc7682..09b9ab6d1 100644 --- a/java/com/android/voicemail/impl/res/values-bs/strings.xml +++ b/java/com/android/voicemail/impl/res/values-bs/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Govorna pošta (%s)" "Govorna pošta" - "Vibracija" - "Vibracija" - "Zvuk" + + "Napredne postavke" "Vizuelna govorna pošta" "Dodatna sigurnosna kopija i pohrana" diff --git a/java/com/android/voicemail/impl/res/values-ca/strings.xml b/java/com/android/voicemail/impl/res/values-ca/strings.xml index b6525d02b..e6c3bc730 100644 --- a/java/com/android/voicemail/impl/res/values-ca/strings.xml +++ b/java/com/android/voicemail/impl/res/values-ca/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Bústia de veu (%s)" "Bústia de veu" - "Vibra" - "Vibra" - "So" + + "Configuració avançada" "Bústia de veu visual" "Còpia de seguretat addicional i emmagatz." diff --git a/java/com/android/voicemail/impl/res/values-cs/strings.xml b/java/com/android/voicemail/impl/res/values-cs/strings.xml index 987f9de01..621c4a8b1 100644 --- a/java/com/android/voicemail/impl/res/values-cs/strings.xml +++ b/java/com/android/voicemail/impl/res/values-cs/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Hlasová schránka (%s)" "Hlasová schránka" - "Vibrace" - "Vibrace" - "Zvuk" + + "Pokročilá nastavení" "Vizuální hlasová schránka" "Další zálohování a úložiště" diff --git a/java/com/android/voicemail/impl/res/values-da/strings.xml b/java/com/android/voicemail/impl/res/values-da/strings.xml index 70ecb3699..e9f0404d2 100644 --- a/java/com/android/voicemail/impl/res/values-da/strings.xml +++ b/java/com/android/voicemail/impl/res/values-da/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Telefonsvarer (%s)" "Telefonsvarer" - "Vibrer" - "Vibrer" - "Lyd" + + "Avancerede indstillinger" "Visuel telefonsvarer" "Ekstra sikkerhedskopiering og lagerplads" diff --git a/java/com/android/voicemail/impl/res/values-de/strings.xml b/java/com/android/voicemail/impl/res/values-de/strings.xml index 2746629e9..c4cc75b37 100644 --- a/java/com/android/voicemail/impl/res/values-de/strings.xml +++ b/java/com/android/voicemail/impl/res/values-de/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Mailbox (%s)" "Mailbox" - "Vibrieren" - "Vibrieren" - "Ton" + + "Erweiterte Einstellungen" "Visuelle Mailbox" "Zusätzliche Sicherung und mehr Speicher" diff --git a/java/com/android/voicemail/impl/res/values-el/strings.xml b/java/com/android/voicemail/impl/res/values-el/strings.xml index e9f9835c6..5456c4875 100644 --- a/java/com/android/voicemail/impl/res/values-el/strings.xml +++ b/java/com/android/voicemail/impl/res/values-el/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Αυτόματος τηλεφωνητής (%s)" "Αυτόματος τηλεφωνητής" - "Δόνηση" - "Δόνηση" - "Ήχος" + + "Σύνθετες ρυθμίσεις" "Οπτικός αυτόματος τηλεφωνητής" "Επιπλέον αντίγραφα ασφ. και αποθήκευση" diff --git a/java/com/android/voicemail/impl/res/values-en-rAU/strings.xml b/java/com/android/voicemail/impl/res/values-en-rAU/strings.xml index ec08faf22..dba1f1624 100644 --- a/java/com/android/voicemail/impl/res/values-en-rAU/strings.xml +++ b/java/com/android/voicemail/impl/res/values-en-rAU/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Voicemail (%s)" "Voicemail" - "Vibrate" - "Vibrate" - "Sound" + + "Advanced settings" "Visual voicemail" "Extra backup and storage" diff --git a/java/com/android/voicemail/impl/res/values-en-rGB/strings.xml b/java/com/android/voicemail/impl/res/values-en-rGB/strings.xml index ec08faf22..dba1f1624 100644 --- a/java/com/android/voicemail/impl/res/values-en-rGB/strings.xml +++ b/java/com/android/voicemail/impl/res/values-en-rGB/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Voicemail (%s)" "Voicemail" - "Vibrate" - "Vibrate" - "Sound" + + "Advanced settings" "Visual voicemail" "Extra backup and storage" diff --git a/java/com/android/voicemail/impl/res/values-en-rIN/strings.xml b/java/com/android/voicemail/impl/res/values-en-rIN/strings.xml index ec08faf22..dba1f1624 100644 --- a/java/com/android/voicemail/impl/res/values-en-rIN/strings.xml +++ b/java/com/android/voicemail/impl/res/values-en-rIN/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Voicemail (%s)" "Voicemail" - "Vibrate" - "Vibrate" - "Sound" + + "Advanced settings" "Visual voicemail" "Extra backup and storage" diff --git a/java/com/android/voicemail/impl/res/values-es-rUS/strings.xml b/java/com/android/voicemail/impl/res/values-es-rUS/strings.xml index fcd9cc7c3..86cb7e934 100644 --- a/java/com/android/voicemail/impl/res/values-es-rUS/strings.xml +++ b/java/com/android/voicemail/impl/res/values-es-rUS/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Buzón de voz (%s)" "Buzón de voz" - "Vibrar" - "Vibrar" - "Sonido" + + "Configuración avanzada" "Buzón de voz visual" "Copia de seguridad y almacenamiento adicional" diff --git a/java/com/android/voicemail/impl/res/values-es/strings.xml b/java/com/android/voicemail/impl/res/values-es/strings.xml index f20ebc5cf..29863d177 100644 --- a/java/com/android/voicemail/impl/res/values-es/strings.xml +++ b/java/com/android/voicemail/impl/res/values-es/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Buzón de voz (%s)" "Buzón de voz" - "Vibración" - "Vibrar" - "Sonido" + + "Configuración avanzada" "Buzón de voz visual" "Copias de seguridad y almacenamiento extra" diff --git a/java/com/android/voicemail/impl/res/values-et/strings.xml b/java/com/android/voicemail/impl/res/values-et/strings.xml index dc7f685ba..6fcf23392 100644 --- a/java/com/android/voicemail/impl/res/values-et/strings.xml +++ b/java/com/android/voicemail/impl/res/values-et/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Kõnepost (%s)" "Kõnepost" - "Vibreerimine" - "Vibreerimine" - "Heli" + + "Täpsemad seaded" "Visuaalne kõnepost" "Lisavarundus ja -salvestusruum" diff --git a/java/com/android/voicemail/impl/res/values-eu/strings.xml b/java/com/android/voicemail/impl/res/values-eu/strings.xml index 8a3bd640a..293dd1c45 100644 --- a/java/com/android/voicemail/impl/res/values-eu/strings.xml +++ b/java/com/android/voicemail/impl/res/values-eu/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Erantzungailua (%s)" "Erantzungailua" - "Dardara" - "Dardara" - "Soinua" + + "Ezarpen aurreratuak" "Erantzungailu bisuala" "Babeskopiak eta edukia gordetzeko tokia" diff --git a/java/com/android/voicemail/impl/res/values-fa/strings.xml b/java/com/android/voicemail/impl/res/values-fa/strings.xml index 0b5d51333..cc04d98f2 100644 --- a/java/com/android/voicemail/impl/res/values-fa/strings.xml +++ b/java/com/android/voicemail/impl/res/values-fa/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "پست صوتی (%s)" "پست صوتی" - "لرزش" - "لرزش" - "صدا" + + "تنظیمات پیشرفته" "پست صوتی تصویری" "پشتیبان‌گیری و فضای ذخیره‌سازی اضافی" diff --git a/java/com/android/voicemail/impl/res/values-fi/strings.xml b/java/com/android/voicemail/impl/res/values-fi/strings.xml index c20d3e481..0e1cda523 100644 --- a/java/com/android/voicemail/impl/res/values-fi/strings.xml +++ b/java/com/android/voicemail/impl/res/values-fi/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Vastaaja (%s)" "Vastaaja" - "Värinä" - "Värinä" - "Ääni" + + "Lisäasetukset" "Visuaalinen vastaaja" "Lisävarmuuskopiointi ja ‑tallennustila" diff --git a/java/com/android/voicemail/impl/res/values-fr-rCA/strings.xml b/java/com/android/voicemail/impl/res/values-fr-rCA/strings.xml index 6bbd1341f..f570fa415 100644 --- a/java/com/android/voicemail/impl/res/values-fr-rCA/strings.xml +++ b/java/com/android/voicemail/impl/res/values-fr-rCA/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Messagerie vocale (%s)" "Messagerie vocale" - "Vibreur" - "Vibreur" - "Son" + + "Paramètres avancés" "Messagerie vocale visuelle" "Espace suppl. de sauvegarde et stockage" diff --git a/java/com/android/voicemail/impl/res/values-fr/strings.xml b/java/com/android/voicemail/impl/res/values-fr/strings.xml index dc21c76d3..323decf84 100644 --- a/java/com/android/voicemail/impl/res/values-fr/strings.xml +++ b/java/com/android/voicemail/impl/res/values-fr/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Messagerie vocale (%s)" "Messagerie vocale" - "Vibreur" - "Vibreur" - "Sonnerie" + + "Paramètres avancés" "Messagerie vocale visuelle" "Espace suppl. de sauvegarde et stockage" diff --git a/java/com/android/voicemail/impl/res/values-gl/strings.xml b/java/com/android/voicemail/impl/res/values-gl/strings.xml index 81f6e679a..b6ff512d2 100644 --- a/java/com/android/voicemail/impl/res/values-gl/strings.xml +++ b/java/com/android/voicemail/impl/res/values-gl/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Correo de voz (%s)" "Correo de voz" - "Vibración" - "Vibración" - "Son" + + "Configuración avanzada" "Correo de voz visual" "Copia de seguranza e almacenamento extra" diff --git a/java/com/android/voicemail/impl/res/values-gu/strings.xml b/java/com/android/voicemail/impl/res/values-gu/strings.xml index 3e8948d19..684bd40fc 100644 --- a/java/com/android/voicemail/impl/res/values-gu/strings.xml +++ b/java/com/android/voicemail/impl/res/values-gu/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "વૉઇસમેઇલ (%s)" "વૉઇસમેઇલ" - "વાઇબ્રેટ" - "વાઇબ્રેટ" - "ધ્વનિ" + + "વિગતવાર સેટિંગ્સ" "વિઝ્યુઅલ વૉઇસમેઇલ" "અતિરિક્ત બેકઅપ અને સ્ટોરેજ" diff --git a/java/com/android/voicemail/impl/res/values-hi/strings.xml b/java/com/android/voicemail/impl/res/values-hi/strings.xml index 8daa3e3d7..3cb394f46 100644 --- a/java/com/android/voicemail/impl/res/values-hi/strings.xml +++ b/java/com/android/voicemail/impl/res/values-hi/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "वॉइसमेल (%s)" "वॉइसमेल" - "कंपन" - "कंपन" - "ध्वनि" + + "उन्नत सेटिंग" "विज़ुअल वॉइसमेल" "अतिरिक्त बैकअप और जगह" diff --git a/java/com/android/voicemail/impl/res/values-hr/strings.xml b/java/com/android/voicemail/impl/res/values-hr/strings.xml index 960909571..6eb0bbc40 100644 --- a/java/com/android/voicemail/impl/res/values-hr/strings.xml +++ b/java/com/android/voicemail/impl/res/values-hr/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Govorna pošta (%s)" "Govorna pošta" - "Vibriranje" - "Vibriranje" - "Zvuk" + + "Napredne postavke" "Vizualna govorna pošta" "Dodatno sigurnosno kopiranje i pohrana" diff --git a/java/com/android/voicemail/impl/res/values-hu/strings.xml b/java/com/android/voicemail/impl/res/values-hu/strings.xml index ce18af799..b76412275 100644 --- a/java/com/android/voicemail/impl/res/values-hu/strings.xml +++ b/java/com/android/voicemail/impl/res/values-hu/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Hangposta (%s)" "Hangposta" - "Rezgés" - "Rezgés" - "Hang" + + "Speciális beállítások" "Vizuális hangpostaüzenet" "Extra tárhely és biztonsági mentés" diff --git a/java/com/android/voicemail/impl/res/values-hy/strings.xml b/java/com/android/voicemail/impl/res/values-hy/strings.xml index eaa987aa4..23544bad8 100644 --- a/java/com/android/voicemail/impl/res/values-hy/strings.xml +++ b/java/com/android/voicemail/impl/res/values-hy/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Ձայնային փոստ (%s)" "Ձայնային փոստ" - "Թրթռոց" - "Թրթռոց" - "Ձայն" + + "Ընդլայնված կարգավորումներ" "Տեսողական ձայնային փոստ" "Լրացուցիչ տարածք և պահուստավորում" diff --git a/java/com/android/voicemail/impl/res/values-in/strings.xml b/java/com/android/voicemail/impl/res/values-in/strings.xml index 6f7e6377e..76ad47944 100644 --- a/java/com/android/voicemail/impl/res/values-in/strings.xml +++ b/java/com/android/voicemail/impl/res/values-in/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Pesan Suara (%s)" "Pesan Suara" - "Getar" - "Getar" - "Suara" + + "Setelan Lanjutan" "Pesan Suara Visual" "Penyimpanan dan backup ekstra" diff --git a/java/com/android/voicemail/impl/res/values-is/strings.xml b/java/com/android/voicemail/impl/res/values-is/strings.xml index 5e00487af..26ee45a75 100644 --- a/java/com/android/voicemail/impl/res/values-is/strings.xml +++ b/java/com/android/voicemail/impl/res/values-is/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Talhólf (%s)" "Talhólf" - "Titringur" - "Titringur" - "Hljóð" + + "Ítarlegar stillingar" "Myndrænt talhólf" "Viðbótaröryggisafritun og samstilling" diff --git a/java/com/android/voicemail/impl/res/values-it/strings.xml b/java/com/android/voicemail/impl/res/values-it/strings.xml index 2c37ba281..3f28d4563 100644 --- a/java/com/android/voicemail/impl/res/values-it/strings.xml +++ b/java/com/android/voicemail/impl/res/values-it/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Segreteria (%s)" "Segreteria" - "Vibrazione" - "Vibrazione" - "Suono" + + "Impostazioni avanzate" "Leggi la segreteria" "Archiviazione supplementare e backup" diff --git a/java/com/android/voicemail/impl/res/values-iw/strings.xml b/java/com/android/voicemail/impl/res/values-iw/strings.xml index cdf58dd64..f808e9853 100644 --- a/java/com/android/voicemail/impl/res/values-iw/strings.xml +++ b/java/com/android/voicemail/impl/res/values-iw/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "דואר קולי (%s)" "דואר קולי" - "רטט" - "רטט" - "צליל" + + "הגדרות מתקדמות" "דואר קולי ויזואלי" "גיבוי ופינוי מקום" diff --git a/java/com/android/voicemail/impl/res/values-ja/strings.xml b/java/com/android/voicemail/impl/res/values-ja/strings.xml index e35359f01..75dcd5e08 100644 --- a/java/com/android/voicemail/impl/res/values-ja/strings.xml +++ b/java/com/android/voicemail/impl/res/values-ja/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ボイスメール(%s)" "ボイスメール" - "バイブレーション" - "バイブレーション" - "通知音" + + "詳細設定" "ビジュアル ボイスメール" "追加のバックアップと保存容量" diff --git a/java/com/android/voicemail/impl/res/values-ka/strings.xml b/java/com/android/voicemail/impl/res/values-ka/strings.xml index 7eb792fd0..8c46747ff 100644 --- a/java/com/android/voicemail/impl/res/values-ka/strings.xml +++ b/java/com/android/voicemail/impl/res/values-ka/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ხმოვანი ფოსტა (%s)" "ხმოვანი ფოსტა" - "ვიბრაცია" - "ვიბრაცია" - "ხმა" + + "გაფართოებული პარამეტრები" "ვიზუალური ხმოვანი ფოსტა" "დამატებითი სარეზ. ასლები და მეხსიერება" diff --git a/java/com/android/voicemail/impl/res/values-kk/strings.xml b/java/com/android/voicemail/impl/res/values-kk/strings.xml index a03171d01..1badcfd92 100644 --- a/java/com/android/voicemail/impl/res/values-kk/strings.xml +++ b/java/com/android/voicemail/impl/res/values-kk/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Дауыстық хабар (%s)" "Дауыстық хабар" - "Діріл" - "Діріл" - "Дыбыс" + + "Қосымша параметрлер" "Визуалды дауыстық пошта" "Қосымша сақтық көшірме жасау және сақтау" diff --git a/java/com/android/voicemail/impl/res/values-km/strings.xml b/java/com/android/voicemail/impl/res/values-km/strings.xml index 3d55d00bb..35fdb490a 100644 --- a/java/com/android/voicemail/impl/res/values-km/strings.xml +++ b/java/com/android/voicemail/impl/res/values-km/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "សារ​ជា​សំឡេង (%s)" "សារ​ជា​សំឡេង" - "ញ័រ" - "ញ័រ" - "សំឡេង" + + "ការ​កំណត់​កម្រិត​ខ្ពស់" "សារជាសំឡេងអាចមើលឃើញ" "ទំហំ​ផ្ទុក និង​ការ​បម្រុងទុក​បន្ថែម" diff --git a/java/com/android/voicemail/impl/res/values-kn/strings.xml b/java/com/android/voicemail/impl/res/values-kn/strings.xml index 379e656ce..5ab3a2e75 100644 --- a/java/com/android/voicemail/impl/res/values-kn/strings.xml +++ b/java/com/android/voicemail/impl/res/values-kn/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ಧ್ವನಿಮೇಲ್ (%s)" "ಧ್ವನಿಮೇಲ್" - "ವೈಬ್ರೇಟ್‌" - "ವೈಬ್ರೇಟ್‌" - "ಶಬ್ದ" + + "ಸುಧಾರಿತ ಸೆಟ್ಟಿಂಗ್‌ಗಳು" "ದೃಶ್ಯ ಧ್ವನಿಮೇಲ್" "ಹೆಚ್ಚುವರಿ ಬ್ಯಾಕಪ್ ಮತ್ತು ಸಂಗ್ರಹಣೆ" diff --git a/java/com/android/voicemail/impl/res/values-ko/strings.xml b/java/com/android/voicemail/impl/res/values-ko/strings.xml index 513a67546..98195e04f 100644 --- a/java/com/android/voicemail/impl/res/values-ko/strings.xml +++ b/java/com/android/voicemail/impl/res/values-ko/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "음성사서함(%s)" "음성사서함" - "진동" - "진동" - "소리" + + "고급 설정" "시각적 음성사서함" "추가 백업 및 저장용량" diff --git a/java/com/android/voicemail/impl/res/values-ky/strings.xml b/java/com/android/voicemail/impl/res/values-ky/strings.xml index 12b7f18c5..5ba4ddeba 100644 --- a/java/com/android/voicemail/impl/res/values-ky/strings.xml +++ b/java/com/android/voicemail/impl/res/values-ky/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Үн почтасы (%s)" "Үн почтасы" - "Дирилдөө" - "Дирилдөө" - "Үн" + + "Өркүндөтүлгөн жөндөөлөр" "Визуалдык үн почтасы" "Кошумча камдык көчүрмөнү сактоо жана сактагыч" diff --git a/java/com/android/voicemail/impl/res/values-lo/strings.xml b/java/com/android/voicemail/impl/res/values-lo/strings.xml index f4f45e592..ef9cecc8d 100644 --- a/java/com/android/voicemail/impl/res/values-lo/strings.xml +++ b/java/com/android/voicemail/impl/res/values-lo/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ຂໍ້​ຄວາມ​ສຽງ (%s)" "ຂໍ້ຄວາມສຽງ" - "ສັ່ນເຕືອນ" - "ສັ່ນເຕືອນ" - "ສຽງ" + + "ການຕັ້ງຄ່າຂັ້ນສູງ" "ຂໍ້​ຄວາມ​ສຽງສະເໝືອນ" "ການສຳຮອງ ແລະ ບ່ອນຈັດເກັບຂໍ້ມູນພິເສດ" diff --git a/java/com/android/voicemail/impl/res/values-lt/strings.xml b/java/com/android/voicemail/impl/res/values-lt/strings.xml index 59a15f452..31dba2e5f 100644 --- a/java/com/android/voicemail/impl/res/values-lt/strings.xml +++ b/java/com/android/voicemail/impl/res/values-lt/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Balso paštas (%s)" "Balso paštas" - "Vibruoti" - "Vibravimas" - "Garsas" + + "Išplėstiniai nustatymai" "Vaizdinis balso paštas" "Papild. saug. vt. ir ats. kop. kūr. f." diff --git a/java/com/android/voicemail/impl/res/values-lv/strings.xml b/java/com/android/voicemail/impl/res/values-lv/strings.xml index 0b8b2f92a..d8230d9ec 100644 --- a/java/com/android/voicemail/impl/res/values-lv/strings.xml +++ b/java/com/android/voicemail/impl/res/values-lv/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Balss pasts (%s)" "Balss pasts" - "Vibrācija" - "Vibrācija" - "Signāls" + + "Papildu iestatījumi" "Vizuālais balss pasts" "Papildu dublēšana un krātuve" diff --git a/java/com/android/voicemail/impl/res/values-mk/strings.xml b/java/com/android/voicemail/impl/res/values-mk/strings.xml index 90c2f6cb2..375b79a7f 100644 --- a/java/com/android/voicemail/impl/res/values-mk/strings.xml +++ b/java/com/android/voicemail/impl/res/values-mk/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Говорна пошта (%s)" "Говорна пошта" - "Вибрации" - "Вибрации" - "Звук" + + "Напредни поставки" "Визуелна говорна пошта" "Дополнителен бекап и склад" diff --git a/java/com/android/voicemail/impl/res/values-ml/strings.xml b/java/com/android/voicemail/impl/res/values-ml/strings.xml index d7fd31f1e..d21d8bed9 100644 --- a/java/com/android/voicemail/impl/res/values-ml/strings.xml +++ b/java/com/android/voicemail/impl/res/values-ml/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "വോയ്‌സ്‌മെയിൽ (%s)" "വോയ്‌സ്‌മെയിൽ" - "വൈബ്രേറ്റുചെയ്യുക" - "വൈബ്രേറ്റുചെയ്യുക" - "ശബ്‌ദം" + + "വിപുലമായ ക്രമീകരണം" "വിഷ്വൽ വോയ്‌സ്‌മെയിൽ" "അധിക ബായ്‌ക്കപ്പും സ്‌റ്റോറേജും" diff --git a/java/com/android/voicemail/impl/res/values-mn/strings.xml b/java/com/android/voicemail/impl/res/values-mn/strings.xml index 5f726342f..56cffa9e0 100644 --- a/java/com/android/voicemail/impl/res/values-mn/strings.xml +++ b/java/com/android/voicemail/impl/res/values-mn/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Дуут шуудан (%s)" "Дуут шуудан" - "Чичиргээ" - "Чичиргээ" - "Дуу" + + "Нарийвчилсан тохиргоо" "Уншиж болохуйц дуут шуудан" "Нэмэлт нөөцлөлт болон хадгалах сан" diff --git a/java/com/android/voicemail/impl/res/values-mr/strings.xml b/java/com/android/voicemail/impl/res/values-mr/strings.xml index e8c546ce6..407909876 100644 --- a/java/com/android/voicemail/impl/res/values-mr/strings.xml +++ b/java/com/android/voicemail/impl/res/values-mr/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "व्हॉइसमेल (%s)" "व्हॉइसमेल" - "कंपन करा" - "कंपन करा" - "ध्वनी" + + "प्रगत सेटिंग्ज" "दृश्‍यमान व्हॉइसमेल" "अतिरिक्त बॅक अप आणि संचय" diff --git a/java/com/android/voicemail/impl/res/values-ms/strings.xml b/java/com/android/voicemail/impl/res/values-ms/strings.xml index 4468d49d7..91fa3051e 100644 --- a/java/com/android/voicemail/impl/res/values-ms/strings.xml +++ b/java/com/android/voicemail/impl/res/values-ms/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Mel suara (%s)" "Mel suara" - "Bergetar" - "Bergetar" - "Bunyi" + + "Tetapan Terperinci" "Mel Suara Visual" "Sandaran dan storan tambahan" diff --git a/java/com/android/voicemail/impl/res/values-my/strings.xml b/java/com/android/voicemail/impl/res/values-my/strings.xml index 41e88351d..8144c1f49 100644 --- a/java/com/android/voicemail/impl/res/values-my/strings.xml +++ b/java/com/android/voicemail/impl/res/values-my/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "အသံမေးလ် (%s)" "အသံမေးလ်" - "တုန်ခါမှု" - "တုန်ခါမှု" - "အသံ" + + "အဆင့်မြင့် ဆက်တင်များ" "စာသားမှတ်တမ်းပါ အသံမေးလ်" "အပိုဆောင်း မိတ္တူနှင့် သိုလှောင်မှု" diff --git a/java/com/android/voicemail/impl/res/values-nb/strings.xml b/java/com/android/voicemail/impl/res/values-nb/strings.xml index afbdd3bb8..b13be25c4 100644 --- a/java/com/android/voicemail/impl/res/values-nb/strings.xml +++ b/java/com/android/voicemail/impl/res/values-nb/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Talepostkasse (%s)" "Talepost" - "Vibrering" - "Vibrering" - "Lyd" + + "Avanserte innstillinger" "Visuell talepostkasse" "Ekstra sikkerhetskopi og lagring" diff --git a/java/com/android/voicemail/impl/res/values-ne/strings.xml b/java/com/android/voicemail/impl/res/values-ne/strings.xml index a186535b5..360164eb5 100644 --- a/java/com/android/voicemail/impl/res/values-ne/strings.xml +++ b/java/com/android/voicemail/impl/res/values-ne/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "भ्वाइस मेल (%s)" "भ्वाइस मेल" - "कम्पन" - "कम्पन" - "आवाज" + + "उन्नत सेटिङहरू" "भिजुअल भ्वाइस मेल" "अतिरिक्त ब्याकअप र भण्डारण" diff --git a/java/com/android/voicemail/impl/res/values-nl/strings.xml b/java/com/android/voicemail/impl/res/values-nl/strings.xml index ed66ab303..88fc0f63f 100644 --- a/java/com/android/voicemail/impl/res/values-nl/strings.xml +++ b/java/com/android/voicemail/impl/res/values-nl/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Voicemail (%s)" "Voicemail" - "Trillen" - "Trillen" - "Geluid" + + "Geavanceerde instellingen" "Visuele voicemail" "Extra back-up en opslag" diff --git a/java/com/android/voicemail/impl/res/values-no/strings.xml b/java/com/android/voicemail/impl/res/values-no/strings.xml index afbdd3bb8..b13be25c4 100644 --- a/java/com/android/voicemail/impl/res/values-no/strings.xml +++ b/java/com/android/voicemail/impl/res/values-no/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Talepostkasse (%s)" "Talepost" - "Vibrering" - "Vibrering" - "Lyd" + + "Avanserte innstillinger" "Visuell talepostkasse" "Ekstra sikkerhetskopi og lagring" diff --git a/java/com/android/voicemail/impl/res/values-pa/strings.xml b/java/com/android/voicemail/impl/res/values-pa/strings.xml index ec68867c6..b7711b903 100644 --- a/java/com/android/voicemail/impl/res/values-pa/strings.xml +++ b/java/com/android/voicemail/impl/res/values-pa/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ਵੌਇਸਮੇਲ (%s)" "ਵੌਇਸਮੇਲ" - "ਵਾਈਬ੍ਰੇਟ ਕਰੋ" - "ਵਾਈਬ੍ਰੇਟ ਕਰੋ" - "ਧੁਨੀ" + + "ਉੱਨਤ ਸੈਟਿੰਗਾਂ" "ਦ੍ਰਿਸ਼ਟਾਂਤਕ ਵੌਇਸਮੇਲ" "ਵਾਧੂ ਬੈਕਅੱਪ ਅਤੇ ਸਟੋਰੇਜ" diff --git a/java/com/android/voicemail/impl/res/values-pl/strings.xml b/java/com/android/voicemail/impl/res/values-pl/strings.xml index 25b891475..d240f7dbc 100644 --- a/java/com/android/voicemail/impl/res/values-pl/strings.xml +++ b/java/com/android/voicemail/impl/res/values-pl/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Poczta głosowa (%s)" "Poczta głosowa" - "Wibracje" - "Wibracje" - "Dźwięk" + + "Ustawienia zaawansowane" "Wizualna poczta głosowa" "Dodatkowe miejsce i kopia zapasowa" diff --git a/java/com/android/voicemail/impl/res/values-pt-rBR/strings.xml b/java/com/android/voicemail/impl/res/values-pt-rBR/strings.xml index c93402e36..501924a35 100644 --- a/java/com/android/voicemail/impl/res/values-pt-rBR/strings.xml +++ b/java/com/android/voicemail/impl/res/values-pt-rBR/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Correio de voz (%s)" "Correio de voz" - "Vibração" - "Vibração" - "Som" + + "Configurações avançadas" "Correio de voz visual" "Armazenamento extra e backup" diff --git a/java/com/android/voicemail/impl/res/values-pt-rPT/strings.xml b/java/com/android/voicemail/impl/res/values-pt-rPT/strings.xml index 00ed0331b..d443329bb 100644 --- a/java/com/android/voicemail/impl/res/values-pt-rPT/strings.xml +++ b/java/com/android/voicemail/impl/res/values-pt-rPT/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Correio de voz (%s)" "Correio de voz" - "Vibrar" - "Vibrar" - "Som" + + "Definições avançadas" "Mensagem de correio de voz visual" "Cópia de segurança e armazenamento extra" diff --git a/java/com/android/voicemail/impl/res/values-pt/strings.xml b/java/com/android/voicemail/impl/res/values-pt/strings.xml index c93402e36..501924a35 100644 --- a/java/com/android/voicemail/impl/res/values-pt/strings.xml +++ b/java/com/android/voicemail/impl/res/values-pt/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Correio de voz (%s)" "Correio de voz" - "Vibração" - "Vibração" - "Som" + + "Configurações avançadas" "Correio de voz visual" "Armazenamento extra e backup" diff --git a/java/com/android/voicemail/impl/res/values-ro/strings.xml b/java/com/android/voicemail/impl/res/values-ro/strings.xml index 9099065c1..44bfd0d81 100644 --- a/java/com/android/voicemail/impl/res/values-ro/strings.xml +++ b/java/com/android/voicemail/impl/res/values-ro/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Mesagerie vocală (%s)" "Mesagerie vocală" - "Vibrații" - "Vibrații" - "Sunet" + + "Setări avansate" "Mesagerie vocală vizuală" "Backup și spațiu de stocare suplimentare" diff --git a/java/com/android/voicemail/impl/res/values-ru/strings.xml b/java/com/android/voicemail/impl/res/values-ru/strings.xml index 322b41bfb..b0512f842 100644 --- a/java/com/android/voicemail/impl/res/values-ru/strings.xml +++ b/java/com/android/voicemail/impl/res/values-ru/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Голосовая почта (%s)" "Голосовая почта" - "Вибросигнал" - "Вибросигнал" - "Звук" + + "Расширенные настройки" "Визуальная голосовая почта" "Дополнительное место для хранения и резервного копирования" diff --git a/java/com/android/voicemail/impl/res/values-si/strings.xml b/java/com/android/voicemail/impl/res/values-si/strings.xml index 8ad6f87e6..ff16e6173 100644 --- a/java/com/android/voicemail/impl/res/values-si/strings.xml +++ b/java/com/android/voicemail/impl/res/values-si/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "හඬ තැපෑල (%s)" "හඬ තැපෑල" - "කම්පනය" - "කම්පනය කරන්න" - "හඬ" + + "උසස් සැකසීම්" "දෘශ්‍ය හඬ තැපෑල" "අතිරේක උපස්ථය සහ ගබඩාව" diff --git a/java/com/android/voicemail/impl/res/values-sk/strings.xml b/java/com/android/voicemail/impl/res/values-sk/strings.xml index 80252d454..a824ca83f 100644 --- a/java/com/android/voicemail/impl/res/values-sk/strings.xml +++ b/java/com/android/voicemail/impl/res/values-sk/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Hlasová schránka %s" "Hlasová schránka" - "Vibrovať" - "Vibrovať" - "Zvuk" + + "Rozšírené nastavenia" "Vizuálna hlasová schránka" "Ďalšie zálohovanie a úložisko" diff --git a/java/com/android/voicemail/impl/res/values-sl/strings.xml b/java/com/android/voicemail/impl/res/values-sl/strings.xml index b634d156a..6ad9569e7 100644 --- a/java/com/android/voicemail/impl/res/values-sl/strings.xml +++ b/java/com/android/voicemail/impl/res/values-sl/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Sporočilo v odzivniku (%s)" "Sporočilo v odzivniku" - "Vibriranje" - "Vibriranje" - "Zvok" + + "Dodatne nastavitve" "Vizualno sporočilo v odzivniku" "Dodatno varnostno kopiranje in shramba" diff --git a/java/com/android/voicemail/impl/res/values-sq/strings.xml b/java/com/android/voicemail/impl/res/values-sq/strings.xml index 59db0fd74..b9dfad9a4 100644 --- a/java/com/android/voicemail/impl/res/values-sq/strings.xml +++ b/java/com/android/voicemail/impl/res/values-sq/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Posta zanore (%s)" "Posta zanore" - "Dridhje" - "Dridhje" - "Tingulli" + + "Cilësimet e përparuara" "Posta zanore vizuale" "Rezervimi dhe hapësira ruajtëse shtesë" diff --git a/java/com/android/voicemail/impl/res/values-sr/strings.xml b/java/com/android/voicemail/impl/res/values-sr/strings.xml index d4998ed2e..3608263e2 100644 --- a/java/com/android/voicemail/impl/res/values-sr/strings.xml +++ b/java/com/android/voicemail/impl/res/values-sr/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Говорна пошта (%s)" "Говорна пошта" - "Вибрација" - "Вибрација" - "Звук" + + "Напредна подешавања" "Визуелна говорна пошта" "Додатне резервне копије и простор" diff --git a/java/com/android/voicemail/impl/res/values-sv/strings.xml b/java/com/android/voicemail/impl/res/values-sv/strings.xml index c69a2df5f..6818b3977 100644 --- a/java/com/android/voicemail/impl/res/values-sv/strings.xml +++ b/java/com/android/voicemail/impl/res/values-sv/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Röstbrevlåda (%s)" "Röstbrevlåda" - "Vibrera" - "Vibrera" - "Ljud" + + "Avancerade inställningar" "Visuell röstbrevlåda" "Extra säkerhetskopiering och lagring" diff --git a/java/com/android/voicemail/impl/res/values-sw/strings.xml b/java/com/android/voicemail/impl/res/values-sw/strings.xml index d1cccc78c..b08db9a41 100644 --- a/java/com/android/voicemail/impl/res/values-sw/strings.xml +++ b/java/com/android/voicemail/impl/res/values-sw/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Ujumbe wa sauti (%s)" "Ujumbe wa sauti" - "Mtetemo" - "Tetema" - "Mlio" + + "Mipangilio ya Kina" "Ujumbe wa Sauti Unaoonekana" "Nafasi ya ziada na hifadhi rudufu" diff --git a/java/com/android/voicemail/impl/res/values-ta/strings.xml b/java/com/android/voicemail/impl/res/values-ta/strings.xml index 0c3c454e1..f240cdd14 100644 --- a/java/com/android/voicemail/impl/res/values-ta/strings.xml +++ b/java/com/android/voicemail/impl/res/values-ta/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "குரலஞ்சல் (%s)" "குரலஞ்சல்" - "அதிர்வுறுதல்" - "அதிர்வுறு" - "ஒலி" + + "மேம்பட்ட அமைப்புகள்" "விஷூவல் குரலஞ்சல்" "கூடுதல் காப்புப் பிரதியும் சேமிப்பகமும்" diff --git a/java/com/android/voicemail/impl/res/values-te/strings.xml b/java/com/android/voicemail/impl/res/values-te/strings.xml index 7a865f43f..038ed98f1 100644 --- a/java/com/android/voicemail/impl/res/values-te/strings.xml +++ b/java/com/android/voicemail/impl/res/values-te/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "వాయిస్ మెయిల్ (%s)" "వాయిస్ మెయిల్" - "వైబ్రేషన్" - "వైబ్రేషన్" - "ధ్వని" + + "అధునాతన సెట్టింగ్‌లు" "దృశ్యమాన వాయిస్ మెయిల్" "అదనపు బ్యాకప్ మరియు నిల్వ" diff --git a/java/com/android/voicemail/impl/res/values-th/strings.xml b/java/com/android/voicemail/impl/res/values-th/strings.xml index 68b32fb45..d4f527020 100644 --- a/java/com/android/voicemail/impl/res/values-th/strings.xml +++ b/java/com/android/voicemail/impl/res/values-th/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ข้อความเสียง (%s)" "ข้อความเสียง" - "สั่น" - "สั่น" - "เสียง" + + "การตั้งค่าขั้นสูง" "ภาพแสดงข้อความเสียง" "การสำรองข้อมูลและพื้นที่เก็บข้อมูลเพิ่มเติม" diff --git a/java/com/android/voicemail/impl/res/values-tl/strings.xml b/java/com/android/voicemail/impl/res/values-tl/strings.xml index c14919c03..184f27edb 100644 --- a/java/com/android/voicemail/impl/res/values-tl/strings.xml +++ b/java/com/android/voicemail/impl/res/values-tl/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Voicemail (%s)" "Voicemail" - "I-vibrate" - "I-vibrate" - "Tunog" + + "Mga Advanced na Setting" "Visual na Voicemail" "Karagdagang backup at storage" diff --git a/java/com/android/voicemail/impl/res/values-tr/strings.xml b/java/com/android/voicemail/impl/res/values-tr/strings.xml index e8f9336f3..2b36fba34 100644 --- a/java/com/android/voicemail/impl/res/values-tr/strings.xml +++ b/java/com/android/voicemail/impl/res/values-tr/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Sesli mesaj (%s)" "Sesli mesaj" - "Titreşim" - "Titreşim" - "Ses" + + "Gelişmiş Ayarlar" "Görsel Sesli Mesaj" "Ekstra yedekleme ve depolama alanı" diff --git a/java/com/android/voicemail/impl/res/values-uk/strings.xml b/java/com/android/voicemail/impl/res/values-uk/strings.xml index 760177ca4..5e4ab77c0 100644 --- a/java/com/android/voicemail/impl/res/values-uk/strings.xml +++ b/java/com/android/voicemail/impl/res/values-uk/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Голосова пошта (%s)" "Голосова пошта" - "Вібросигнал" - "Вібросигнал" - "Звук" + + "Розширені налаштування" "Візуальна голосова пошта" "Додаткова пам’ять і резервне копіювання" diff --git a/java/com/android/voicemail/impl/res/values-ur/strings.xml b/java/com/android/voicemail/impl/res/values-ur/strings.xml index 2105fae08..ae6e98def 100644 --- a/java/com/android/voicemail/impl/res/values-ur/strings.xml +++ b/java/com/android/voicemail/impl/res/values-ur/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "صوتی میل (%s)" "صوتی میل" - "ارتعاش" - "ارتعاش" - "آواز" + + "اعلی ترتیبات" "بصری صوتی میل" "اضافی بیک اپ اور اسٹوریج" diff --git a/java/com/android/voicemail/impl/res/values-uz/strings.xml b/java/com/android/voicemail/impl/res/values-uz/strings.xml index fad79164d..f458aee7b 100644 --- a/java/com/android/voicemail/impl/res/values-uz/strings.xml +++ b/java/com/android/voicemail/impl/res/values-uz/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Ovozli pochta (%s)" "Ovozli pochta" - "Tebranish" - "Tebranish" - "Ovoz" + + "Kengaytirilgan sozlamalar" "Vizual ovozli pochta" "Zaxira. va saqlash u-n qo‘shimcha xotira" diff --git a/java/com/android/voicemail/impl/res/values-vi/strings.xml b/java/com/android/voicemail/impl/res/values-vi/strings.xml index 1d029ea12..c0bfa8183 100644 --- a/java/com/android/voicemail/impl/res/values-vi/strings.xml +++ b/java/com/android/voicemail/impl/res/values-vi/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Thư thoại %s" "Thư thoại" - "Rung" - "Rung" - "Âm báo" + + "Cài đặt nâng cao" "Thư thoại kèm theo hình ảnh" "Bộ nhớ và bản sao lưu bổ sung" diff --git a/java/com/android/voicemail/impl/res/values-zh-rCN/strings.xml b/java/com/android/voicemail/impl/res/values-zh-rCN/strings.xml index d70f1fa51..66b058b1f 100644 --- a/java/com/android/voicemail/impl/res/values-zh-rCN/strings.xml +++ b/java/com/android/voicemail/impl/res/values-zh-rCN/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "语音邮件(%s)" "语音邮件" - "振动" - "振动" - "提示音" + + "高级设置" "可视语音信箱" "额外存储空间和备份功能" diff --git a/java/com/android/voicemail/impl/res/values-zh-rHK/strings.xml b/java/com/android/voicemail/impl/res/values-zh-rHK/strings.xml index 4adc3fd97..d76068790 100644 --- a/java/com/android/voicemail/impl/res/values-zh-rHK/strings.xml +++ b/java/com/android/voicemail/impl/res/values-zh-rHK/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "留言 (%s)" "留言" - "震動" - "震動" - "音效" + + "進階設定" "視像留言" "額外備份功能和儲存空間" diff --git a/java/com/android/voicemail/impl/res/values-zh-rTW/strings.xml b/java/com/android/voicemail/impl/res/values-zh-rTW/strings.xml index 6ff084f60..2b4de45d9 100644 --- a/java/com/android/voicemail/impl/res/values-zh-rTW/strings.xml +++ b/java/com/android/voicemail/impl/res/values-zh-rTW/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "語音信箱 (%s)" "語音信箱" - "震動" - "震動" - "音效" + + "進階設定" "視覺化語音信箱" "額外的備份功能和儲存空間" diff --git a/java/com/android/voicemail/impl/res/values-zu/strings.xml b/java/com/android/voicemail/impl/res/values-zu/strings.xml index 5adf300e5..1debac61b 100644 --- a/java/com/android/voicemail/impl/res/values-zu/strings.xml +++ b/java/com/android/voicemail/impl/res/values-zu/strings.xml @@ -18,9 +18,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Ivoyisimeyili (%s)" "Ivoyisimeyili" - "Dlidlizela" - "Dlidlizela" - "Umsindo" + + "Izilungiselelo ezithuthukisiwe" "Ivoyisimeyili ebonakalayo" "Isipele esingeziwe nesitoreji" diff --git a/java/com/android/voicemail/impl/res/values/strings.xml b/java/com/android/voicemail/impl/res/values/strings.xml index bb754d18b..375a1e9ba 100644 --- a/java/com/android/voicemail/impl/res/values/strings.xml +++ b/java/com/android/voicemail/impl/res/values/strings.xml @@ -23,19 +23,12 @@ Voicemail - voicemail_notification_ringtone_key - - voicemail_notification_vibrate_key - - - Vibrate - - Vibrate + voicemail_notification_key - - Sound + Notifications voicemail_advanced_settings_key diff --git a/java/com/android/voicemail/impl/res/xml/voicemail_settings.xml b/java/com/android/voicemail/impl/res/xml/voicemail_settings.xml index 53fd57f7e..50510905c 100644 --- a/java/com/android/voicemail/impl/res/xml/voicemail_settings.xml +++ b/java/com/android/voicemail/impl/res/xml/voicemail_settings.xml @@ -17,16 +17,9 @@ - - - + The executor will only exist when {@link TaskSchedulerJobService} is running. + * + *

All tasks are ran in the background with a wakelock being held by the {@link + * android.app.job.JobScheduler}, which is between {@link #onStartJob(Job, List)} and {@link + * #finishJobAsync()}. The {@link TaskSchedulerJobService} also has a {@link TaskQueue}, but the + * data is stored in the {@link android.app.job.JobScheduler} instead of the process memory, so if + * the process is killed the queued tasks will be restored. If a new task is added, a new {@link + * TaskSchedulerJobService} will be scheduled to run the task. If the job is already scheduled, the + * new task will be pushed into the queue of the scheduled job. If the job is already running, the + * job will be queued in process memory. + * + *

Only one task will be ran at a time, and same task cannot exist in the queue at the same time. + * Refer to {@link TaskQueue} for queuing and execution order. + * + *

If there are still tasks in the queue but none are executable immediately, the service will + * enter a "sleep", pushing all remaining task into a new job and end the current job. + * + *

The executor will be started when {@link TaskSchedulerJobService} is running, and stopped when + * there are no more tasks in the queue or when the executor is put to sleep. + * + *

{@link android.app.job.JobScheduler} is not used directly due to: + * + *

    + *
  • The {@link android.telecom.PhoneAccountHandle} used to differentiate task can not be easily + * mapped into an integer for job id + *
  • A job cannot be mutated to store information such as retry count. + *
+ */ +@TargetApi(VERSION_CODES.O) +final class TaskExecutor { + + /** + * An entity that holds execution resources for the {@link TaskExecutor} to run, usually a {@link + * android.app.job.JobService}. + */ + interface Job { + + /** + * Signals to Job to end and release its' resources. This is an asynchronous call and may not + * take effect immediately. + */ + @MainThread + void finishAsync(); + + /** Whether the call to {@link #finishAsync()} has actually taken effect. */ + @MainThread + boolean isFinished(); + } + + private static final String TAG = "VvmTaskExecutor"; + + private static final int READY_TOLERANCE_MILLISECONDS = 100; + + /** + * Threshold to determine whether to do a short or long sleep when a task is scheduled in the + * future. + * + *

A short sleep will continue the job and use {@link Handler#postDelayed(Runnable, long)} to + * wait for the next task. + * + *

A long sleep will finish the job and schedule a new one. The exact execution time is + * subjected to {@link android.app.job.JobScheduler} battery optimization, and is not exact. + */ + private static final int SHORT_SLEEP_THRESHOLD_MILLISECONDS = 10_000; + /** + * When there are no more tasks to be run the service should be stopped. But when all tasks has + * finished there might still be more tasks in the message queue waiting to be processed, + * especially the ones submitted in {@link Task#onCompleted()}. Wait for a while before stopping + * the service to make sure there are no pending messages. + */ + private static final int STOP_DELAY_MILLISECONDS = 5_000; + + /** Interval between polling of whether the job is finished. */ + private static final int TERMINATE_POLLING_INTERVAL_MILLISECONDS = 1_000; + + // The thread to run tasks on + private final WorkerThreadHandler workerThreadHandler; + + private static TaskExecutor instance; + + /** + * Used by tests to turn task handling into a single threaded process by calling {@link + * Handler#handleMessage(Message)} directly + */ + private MessageSender messageSender = new MessageSender(); + + private final MainThreadHandler mainThreadHandler; + + private final Context context; + + /** Main thread only, access through {@link #getTasks()} */ + private final TaskQueue tasks = new TaskQueue(); + + private boolean isWorkerThreadBusy = false; + + private boolean isTerminating = false; + + private Job job; + + private final Runnable stopServiceWithDelay = + new Runnable() { + @MainThread + @Override + public void run() { + VvmLog.i(TAG, "Stopping service"); + if (!isJobRunning() || isTerminating()) { + VvmLog.e(TAG, "Service already stopped"); + return; + } + scheduleJobAndTerminate(0, true); + } + }; + + /** + * Reschedule the {@link TaskSchedulerJobService} and terminate the executor when the {@link Job} + * is truly finished. If the job is still not finished, this runnable will requeue itself on the + * main thread. The requeue is only expected to happen a few times. + */ + private class JobFinishedPoller implements Runnable { + + private final long delayMillis; + private final boolean isNewJob; + private int invocationCounter = 0; + + JobFinishedPoller(long delayMillis, boolean isNewJob) { + this.delayMillis = delayMillis; + this.isNewJob = isNewJob; + } + + @Override + public void run() { + // The job should be finished relatively quickly. Assert to make sure this assumption is true. + Assert.isTrue(invocationCounter < 10); + invocationCounter++; + if (job.isFinished()) { + VvmLog.i("JobFinishedPoller.run", "Job finished"); + if (!getTasks().isEmpty()) { + TaskSchedulerJobService.scheduleJob( + context, serializePendingTasks(), delayMillis, isNewJob); + tasks.clear(); + } + terminate(); + return; + } + VvmLog.w("JobFinishedPoller.run", "Job still running"); + mainThreadHandler.postDelayed(this, TERMINATE_POLLING_INTERVAL_MILLISECONDS); + } + }; + + /** Should attempt to run the next task when a task has finished or been added. */ + private boolean taskAutoRunDisabledForTesting = false; + + @VisibleForTesting + final class WorkerThreadHandler extends Handler { + + public WorkerThreadHandler(Looper looper) { + super(looper); + } + + @Override + @WorkerThread + public void handleMessage(Message msg) { + Assert.isNotMainThread(); + Task task = (Task) msg.obj; + try { + VvmLog.i(TAG, "executing task " + task); + task.onExecuteInBackgroundThread(); + } catch (Throwable throwable) { + VvmLog.e(TAG, "Exception while executing task " + task + ":", throwable); + } + + Message schedulerMessage = mainThreadHandler.obtainMessage(); + schedulerMessage.obj = task; + messageSender.send(schedulerMessage); + } + } + + @VisibleForTesting + final class MainThreadHandler extends Handler { + + public MainThreadHandler(Looper looper) { + super(looper); + } + + @Override + @MainThread + public void handleMessage(Message msg) { + Assert.isMainThread(); + Task task = (Task) msg.obj; + getTasks().remove(task); + task.onCompleted(); + isWorkerThreadBusy = false; + maybeRunNextTask(); + } + } + + /** Starts a new TaskExecutor. May only be called by {@link TaskSchedulerJobService}. */ + @MainThread + static void createRunningInstance(Context context) { + Assert.isMainThread(); + Assert.isTrue(instance == null); + instance = new TaskExecutor(context); + } + + /** @return the currently running instance, or {@code null} if the executor is not running. */ + @MainThread + @Nullable + static TaskExecutor getRunningInstance() { + return instance; + } + + private TaskExecutor(Context context) { + this.context = context; + HandlerThread thread = new HandlerThread("VvmTaskExecutor"); + thread.start(); + + workerThreadHandler = new WorkerThreadHandler(thread.getLooper()); + mainThreadHandler = new MainThreadHandler(Looper.getMainLooper()); + } + + @VisibleForTesting + void terminate() { + VvmLog.i(TAG, "terminated"); + Assert.isMainThread(); + job = null; + workerThreadHandler.getLooper().quit(); + instance = null; + TaskReceiver.resendDeferredBroadcasts(context); + } + + @MainThread + void addTask(Task task) { + Assert.isMainThread(); + getTasks().add(task); + VvmLog.i(TAG, task + " added"); + mainThreadHandler.removeCallbacks(stopServiceWithDelay); + maybeRunNextTask(); + } + + @MainThread + @VisibleForTesting + TaskQueue getTasks() { + Assert.isMainThread(); + return tasks; + } + + @MainThread + private void maybeRunNextTask() { + Assert.isMainThread(); + if (isWorkerThreadBusy) { + return; + } + if (taskAutoRunDisabledForTesting) { + // If taskAutoRunDisabledForTesting is true, runNextTask() must be explicitly called + // to run the next task. + return; + } + + runNextTask(); + } + + @VisibleForTesting + @MainThread + void runNextTask() { + Assert.isMainThread(); + if (getTasks().isEmpty()) { + prepareStop(); + return; + } + NextTask nextTask = getTasks().getNextTask(READY_TOLERANCE_MILLISECONDS); + + if (nextTask.task != null) { + nextTask.task.onBeforeExecute(); + Message message = workerThreadHandler.obtainMessage(); + message.obj = nextTask.task; + isWorkerThreadBusy = true; + messageSender.send(message); + return; + } + VvmLog.i(TAG, "minimal wait time:" + nextTask.minimalWaitTimeMillis); + if (!taskAutoRunDisabledForTesting && nextTask.minimalWaitTimeMillis != null) { + // No tasks are currently ready. Sleep until the next one should be. + // If a new task is added during the sleep the service will wake immediately. + sleep(nextTask.minimalWaitTimeMillis); + } + } + + @MainThread + private void sleep(long timeMillis) { + VvmLog.i(TAG, "sleep for " + timeMillis + " millis"); + if (timeMillis < SHORT_SLEEP_THRESHOLD_MILLISECONDS) { + mainThreadHandler.postDelayed( + new Runnable() { + @Override + public void run() { + maybeRunNextTask(); + } + }, + timeMillis); + return; + } + scheduleJobAndTerminate(timeMillis, false); + } + + private List serializePendingTasks() { + return getTasks().toBundles(); + } + + private void prepareStop() { + VvmLog.i( + TAG, + "no more tasks, stopping service if no task are added in " + + STOP_DELAY_MILLISECONDS + + " millis"); + mainThreadHandler.postDelayed(stopServiceWithDelay, STOP_DELAY_MILLISECONDS); + } + + @NeededForTesting + static class MessageSender { + + public void send(Message message) { + message.sendToTarget(); + } + } + + @NeededForTesting + void setTaskAutoRunDisabledForTest(boolean value) { + taskAutoRunDisabledForTesting = value; + } + + @NeededForTesting + void setMessageSenderForTest(MessageSender sender) { + messageSender = sender; + } + + /** + * The {@link TaskSchedulerJobService} has started and all queued task should be executed in the + * worker thread. + */ + @MainThread + public void onStartJob(Job job, List pendingTasks) { + VvmLog.i(TAG, "onStartJob"); + this.job = job; + tasks.fromBundles(context, pendingTasks); + maybeRunNextTask(); + } + + /** + * The {@link TaskSchedulerJobService} is being terminated by the system (timeout or network + * lost). A new job will be queued to resume all pending tasks. The current unfinished job may be + * ran again. + */ + @MainThread + public void onStopJob() { + VvmLog.e(TAG, "onStopJob"); + if (isJobRunning() && !isTerminating()) { + scheduleJobAndTerminate(0, true); + } + } + + /** + * Send all pending tasks and schedule a new {@link TaskSchedulerJobService}. The current executor + * will start the termination process, but restarted when the scheduled job runs in the future. + * + * @param delayMillis the delay before stating the job, see {@link + * android.app.job.JobInfo.Builder#setMinimumLatency(long)}. This must be 0 if {@code + * isNewJob} is true. + * @param isNewJob a new job will be requested to run immediately, bypassing all requirements. + */ + @MainThread + @VisibleForTesting + void scheduleJobAndTerminate(long delayMillis, boolean isNewJob) { + Assert.isMainThread(); + finishJobAsync(); + mainThreadHandler.post(new JobFinishedPoller(delayMillis, isNewJob)); + } + + /** + * Whether the TaskExecutor is still terminating. {@link TaskReceiver} should defer all new task + * until {@link #getRunningInstance()} returns {@code null} so a new job can be started. {@link + * #scheduleJobAndTerminate(long, boolean)} does not run immediately because the job can only be + * scheduled after the main thread has returned. The TaskExecutor will be in a intermediate state + * between scheduleJobAndTerminate() and terminate(). In this state, {@link #getRunningInstance()} + * returns non-null because it has not been fully stopped yet, but the TaskExecutor cannot do + * anything. A new job should not be scheduled either because the current job might still be + * running. + */ + @MainThread + public boolean isTerminating() { + return isTerminating; + } + + /** + * Signals {@link TaskSchedulerJobService} the current session of tasks has finished, and the wake + * lock can be released. Note: this only takes effect after the main thread has been returned. If + * a new job need to be scheduled, it should be posted on the main thread handler instead of + * calling directly. + */ + @MainThread + private void finishJobAsync() { + Assert.isTrue(!isTerminating()); + Assert.isMainThread(); + VvmLog.i(TAG, "finishing Job"); + job.finishAsync(); + isTerminating = true; + mainThreadHandler.removeCallbacks(stopServiceWithDelay); + } + + private boolean isJobRunning() { + return job != null; + } +} diff --git a/java/com/android/voicemail/impl/scheduling/TaskReceiver.java b/java/com/android/voicemail/impl/scheduling/TaskReceiver.java new file mode 100644 index 000000000..00d36d00f --- /dev/null +++ b/java/com/android/voicemail/impl/scheduling/TaskReceiver.java @@ -0,0 +1,80 @@ +/* + * 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.voicemail.impl.scheduling; + +import android.annotation.TargetApi; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.os.Build.VERSION_CODES; +import android.os.Bundle; +import com.android.voicemail.impl.VvmLog; +import java.util.ArrayList; +import java.util.List; + +/** + * BroadcastReceiver to queue and run {@link Task} with the {@link android.app.job.JobScheduler}. A + * task is queued using a explicit broadcast to this receiver. The intent should contain enough + * information in {@link Intent#getExtras()} to construct the task (see {@link + * Tasks#createIntent(Context, Class)}). The task will be queued directly in {@link TaskExecutor} if + * it is already running, or in {@link TaskSchedulerJobService} if not. + */ +@TargetApi(VERSION_CODES.O) +public class TaskReceiver extends BroadcastReceiver { + + private static final String TAG = "VvmTaskReceiver"; + + private static final List deferredBroadcasts = new ArrayList<>(); + + /** + * When {@link TaskExecutor#isTerminating()} is {@code true}, newly added tasks will be deferred + * to allow the TaskExecutor to terminate properly. After termination is completed this should be + * called to add the tasks again. + */ + public static void resendDeferredBroadcasts(Context context) { + for (Intent intent : deferredBroadcasts) { + context.sendBroadcast(intent); + } + } + + @Override + public void onReceive(Context context, Intent intent) { + if (intent == null) { + VvmLog.w(TAG, "null intent received"); + return; + } + VvmLog.i(TAG, "task received"); + TaskExecutor taskExecutor = TaskExecutor.getRunningInstance(); + if (taskExecutor != null) { + VvmLog.i(TAG, "TaskExecutor already running"); + if (taskExecutor.isTerminating()) { + // The current taskExecutor and cannot do anything and a new job cannot be scheduled. Defer + // the task until a new job can be scheduled. + VvmLog.w(TAG, "TaskExecutor is terminating, bouncing task"); + deferredBroadcasts.add(intent); + return; + } + Task task = Tasks.createTask(context, intent.getExtras()); + taskExecutor.addTask(task); + } else { + VvmLog.i(TAG, "scheduling new job"); + List taskList = new ArrayList<>(); + taskList.add(intent.getExtras()); + TaskSchedulerJobService.scheduleJob(context, taskList, 0, true); + } + } +} diff --git a/java/com/android/voicemail/impl/scheduling/TaskSchedulerJobService.java b/java/com/android/voicemail/impl/scheduling/TaskSchedulerJobService.java index eab410eb0..9bfce0052 100644 --- a/java/com/android/voicemail/impl/scheduling/TaskSchedulerJobService.java +++ b/java/com/android/voicemail/impl/scheduling/TaskSchedulerJobService.java @@ -23,11 +23,8 @@ import android.app.job.JobScheduler; import android.app.job.JobService; import android.content.ComponentName; import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; import android.os.Build.VERSION_CODES; import android.os.Bundle; -import android.os.IBinder; import android.os.Parcelable; import android.support.annotation.MainThread; import com.android.dialer.constants.ScheduledJobIds; @@ -36,59 +33,42 @@ import com.android.voicemail.impl.VvmLog; import java.util.ArrayList; import java.util.List; -/** - * A {@link JobService} that will trigger the background execution of {@link TaskSchedulerService}. - */ +/** A {@link JobService} that will trigger the background execution of {@link TaskExecutor}. */ @TargetApi(VERSION_CODES.O) -public class TaskSchedulerJobService extends JobService implements TaskSchedulerService.Job { +public class TaskSchedulerJobService extends JobService implements TaskExecutor.Job { private static final String TAG = "TaskSchedulerJobService"; private static final String EXTRA_TASK_EXTRAS_ARRAY = "extra_task_extras_array"; private JobParameters jobParameters; - private TaskSchedulerService scheduler; - - private final ServiceConnection mConnection = - new ServiceConnection() { - - @Override - public void onServiceConnected(ComponentName className, IBinder binder) { - VvmLog.i(TAG, "TaskSchedulerService connected"); - scheduler = ((TaskSchedulerService.LocalBinder) binder).getService(); - scheduler.onStartJob( - TaskSchedulerJobService.this, - getBundleList( - jobParameters.getTransientExtras().getParcelableArray(EXTRA_TASK_EXTRAS_ARRAY))); - } - - @Override - public void onServiceDisconnected(ComponentName unused) { - // local service, process should always be killed together. - Assert.fail(); - } - }; @Override @MainThread public boolean onStartJob(JobParameters params) { jobParameters = params; - bindService( - new Intent(this, TaskSchedulerService.class), mConnection, Context.BIND_AUTO_CREATE); + TaskExecutor.createRunningInstance(this); + TaskExecutor.getRunningInstance() + .onStartJob( + this, + getBundleList( + jobParameters.getTransientExtras().getParcelableArray(EXTRA_TASK_EXTRAS_ARRAY))); return true /* job still running in background */; } @Override @MainThread public boolean onStopJob(JobParameters params) { - scheduler.onStopJob(); + TaskExecutor.getRunningInstance().onStopJob(); jobParameters = null; - return false /* don't reschedule. TaskScheduler service will post a new job */; + return false /* don't reschedule. TaskExecutor service will post a new job */; } /** * Schedule a job to run the {@code pendingTasks}. If a job is already scheduled it will be - * appended to the back of the queue and the job will be rescheduled. + * appended to the back of the queue and the job will be rescheduled. A job may only be scheduled + * when the {@link TaskExecutor} is not running ({@link TaskExecutor#getRunningInstance()} + * returning {@code null}) * * @param delayMillis delay before running the job. Must be 0 if{@code isNewJob} is true. * @param isNewJob a new job will be forced to run immediately. @@ -141,11 +121,19 @@ public class TaskSchedulerJobService extends JobService implements TaskScheduler * the wakelock */ @Override - public void finish() { - VvmLog.i(TAG, "finishing job and unbinding TaskSchedulerService"); + public void finishAsync() { + VvmLog.i(TAG, "finishing job"); jobFinished(jobParameters, false); jobParameters = null; - unbindService(mConnection); + } + + @MainThread + @Override + public boolean isFinished() { + Assert.isMainThread(); + return getSystemService(JobScheduler.class) + .getPendingJob(ScheduledJobIds.VVM_TASK_SCHEDULER_JOB) + == null; } private static List getBundleList(Parcelable[] parcelables) { diff --git a/java/com/android/voicemail/impl/scheduling/Tasks.java b/java/com/android/voicemail/impl/scheduling/Tasks.java index 34debaf29..76da3d7f6 100644 --- a/java/com/android/voicemail/impl/scheduling/Tasks.java +++ b/java/com/android/voicemail/impl/scheduling/Tasks.java @@ -19,6 +19,7 @@ package com.android.voicemail.impl.scheduling; import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.support.annotation.NonNull; import com.android.voicemail.impl.VvmLog; /** Common operations on {@link Task} */ @@ -32,6 +33,7 @@ final class Tasks { * Create a task from a bundle. The bundle is created either with {@link #toBundle(Task)} or * {@link #createIntent(Context, Class)} from the target {@link Task} */ + @NonNull public static Task createTask(Context context, Bundle extras) { // The extra contains custom parcelables which cannot be unmarshalled by the framework class // loader. @@ -66,7 +68,8 @@ final class Tasks { * necessary information. */ public static Intent createIntent(Context context, Class task) { - Intent intent = new Intent(context, TaskSchedulerService.class); + Intent intent = new Intent(context, TaskReceiver.class); + intent.setPackage(context.getPackageName()); intent.putExtra(EXTRA_CLASS_NAME, task.getName()); return intent; } diff --git a/java/com/android/voicemail/impl/settings/VoicemailSettingsFragment.java b/java/com/android/voicemail/impl/settings/VoicemailSettingsFragment.java index 423fd11b4..ac5f3cac9 100644 --- a/java/com/android/voicemail/impl/settings/VoicemailSettingsFragment.java +++ b/java/com/android/voicemail/impl/settings/VoicemailSettingsFragment.java @@ -17,7 +17,6 @@ import android.annotation.TargetApi; import android.content.Intent; import android.os.Build.VERSION_CODES; import android.os.Bundle; -import android.preference.CheckBoxPreference; import android.preference.Preference; import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceFragment; @@ -29,6 +28,8 @@ import android.telephony.TelephonyManager; import com.android.dialer.common.Assert; import com.android.dialer.logging.DialerImpression; import com.android.dialer.logging.Logger; +import com.android.dialer.notification.NotificationChannelManager; +import com.android.dialer.notification.NotificationChannelManager.Channel; import com.android.voicemail.VoicemailClient; import com.android.voicemail.VoicemailComponent; import com.android.voicemail.impl.OmtpVvmCarrierConfigHelper; @@ -43,7 +44,6 @@ import com.android.voicemail.impl.sync.VvmAccountManager; @TargetApi(VERSION_CODES.O) public class VoicemailSettingsFragment extends PreferenceFragment implements Preference.OnPreferenceChangeListener, - VoicemailRingtonePreference.VoicemailRingtoneNameChangeListener, VvmAccountManager.Listener { private static final String TAG = "VmSettingsActivity"; @@ -51,17 +51,12 @@ public class VoicemailSettingsFragment extends PreferenceFragment @Nullable private PhoneAccountHandle phoneAccountHandle; private OmtpVvmCarrierConfigHelper omtpVvmCarrierConfigHelper; - private VoicemailRingtonePreference voicemailRingtonePreference; - private CheckBoxPreference voicemailVibration; + private Preference voicemailNotificationPreference; private SwitchPreference voicemailVisualVoicemail; private SwitchPreference autoArchiveSwitchPreference; private Preference voicemailChangePinPreference; private PreferenceScreen advancedSettings; - // The ringtone name is retrieved with an async call. Cache the old name so there will be no jank - // during transition. - private CharSequence oldRingtoneName = ""; - @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); @@ -86,12 +81,12 @@ public class VoicemailSettingsFragment extends PreferenceFragment PreferenceScreen prefSet = getPreferenceScreen(); - voicemailRingtonePreference = - (VoicemailRingtonePreference) - findPreference(getString(R.string.voicemail_notification_ringtone_key)); - voicemailRingtonePreference.setVoicemailRingtoneNameChangeListener(this); - voicemailRingtonePreference.init(phoneAccountHandle, oldRingtoneName); - voicemailRingtonePreference.setOnPreferenceClickListener( + voicemailNotificationPreference = + findPreference(getString(R.string.voicemail_notifications_key)); + voicemailNotificationPreference.setIntent( + NotificationChannelManager.getInstance() + .getSettingsIntentForChannel(getContext(), Channel.VOICEMAIL, phoneAccountHandle)); + voicemailNotificationPreference.setOnPreferenceClickListener( new OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { @@ -102,24 +97,6 @@ public class VoicemailSettingsFragment extends PreferenceFragment } }); - voicemailVibration = - (CheckBoxPreference) findPreference(getString(R.string.voicemail_notification_vibrate_key)); - voicemailVibration.setOnPreferenceChangeListener(this); - voicemailVibration.setChecked( - getContext() - .getSystemService(TelephonyManager.class) - .isVoicemailVibrationEnabled(phoneAccountHandle)); - voicemailVibration.setOnPreferenceClickListener( - new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - Logger.get(getContext()) - .logImpression(DialerImpression.Type.VVM_CHANGE_VIBRATION_CLICKED); - // Let the preference handle the click. - return false; - } - }); - voicemailVisualVoicemail = (SwitchPreference) findPreference(getString(R.string.voicemail_visual_voicemail_key)); @@ -219,10 +196,6 @@ public class VoicemailSettingsFragment extends PreferenceFragment logArchiveToggle((boolean) objValue); VisualVoicemailSettingsUtil.setArchiveEnabled( getContext(), phoneAccountHandle, (boolean) objValue); - } else if (preference.getKey().equals(voicemailVibration.getKey())) { - getContext() - .getSystemService(TelephonyManager.class) - .setVoicemailVibrationEnabled(phoneAccountHandle, (boolean) objValue); } // Always let the preference setting proceed. @@ -254,11 +227,6 @@ public class VoicemailSettingsFragment extends PreferenceFragment } } - @Override - public void onVoicemailRingtoneNameChanged(CharSequence name) { - oldRingtoneName = name; - } - @Override public void onActivationStateChanged(PhoneAccountHandle phoneAccountHandle, boolean isActivated) { if (this.phoneAccountHandle.equals(phoneAccountHandle)) { diff --git a/java/com/android/voicemail/impl/sms/OmtpMessageReceiver.java b/java/com/android/voicemail/impl/sms/OmtpMessageReceiver.java index 43e2b85bd..ef0bf10e9 100644 --- a/java/com/android/voicemail/impl/sms/OmtpMessageReceiver.java +++ b/java/com/android/voicemail/impl/sms/OmtpMessageReceiver.java @@ -28,7 +28,7 @@ import android.telecom.PhoneAccountHandle; import android.telephony.VisualVoicemailSms; import com.android.voicemail.impl.ActivationTask; import com.android.voicemail.impl.OmtpConstants; -import com.android.voicemail.impl.OmtpReceiver; +import com.android.voicemail.impl.OmtpService; import com.android.voicemail.impl.OmtpVvmCarrierConfigHelper; import com.android.voicemail.impl.Voicemail; import com.android.voicemail.impl.Voicemail.Builder; @@ -52,7 +52,7 @@ public class OmtpMessageReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { mContext = context; - VisualVoicemailSms sms = intent.getExtras().getParcelable(OmtpReceiver.EXTRA_VOICEMAIL_SMS); + VisualVoicemailSms sms = intent.getExtras().getParcelable(OmtpService.EXTRA_VOICEMAIL_SMS); PhoneAccountHandle phone = sms.getPhoneAccountHandle(); if (phone == null) { diff --git a/java/com/android/voicemail/impl/sms/OmtpMessageSender.java b/java/com/android/voicemail/impl/sms/OmtpMessageSender.java index 6c9333fb3..e9d145cde 100644 --- a/java/com/android/voicemail/impl/sms/OmtpMessageSender.java +++ b/java/com/android/voicemail/impl/sms/OmtpMessageSender.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Google Inc. All Rights Reserved. + * 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. @@ -20,8 +20,8 @@ import android.content.Context; import android.support.annotation.Nullable; import android.telecom.PhoneAccountHandle; import android.telephony.SmsManager; -import android.telephony.VisualVoicemailService; import com.android.voicemail.impl.OmtpConstants; +import com.android.voicemail.impl.TelephonyMangerCompat; /** * Send client originated OMTP messages to the OMTP server. @@ -75,7 +75,7 @@ public abstract class OmtpMessageSender { public void requestVvmStatus(@Nullable PendingIntent sentIntent) {} protected void sendSms(String text, PendingIntent sentIntent) { - VisualVoicemailService.sendVisualVoicemailSms( + TelephonyMangerCompat.sendVisualVoicemailSms( mContext, mPhoneAccountHandle, mDestinationNumber, mApplicationPort, text, sentIntent); } diff --git a/java/com/android/voicemail/impl/sms/StatusSmsFetcher.java b/java/com/android/voicemail/impl/sms/StatusSmsFetcher.java index dd9204d3e..d178628c6 100644 --- a/java/com/android/voicemail/impl/sms/StatusSmsFetcher.java +++ b/java/com/android/voicemail/impl/sms/StatusSmsFetcher.java @@ -33,7 +33,7 @@ import android.telephony.SmsManager; import android.telephony.VisualVoicemailSms; import com.android.voicemail.impl.Assert; import com.android.voicemail.impl.OmtpConstants; -import com.android.voicemail.impl.OmtpReceiver; +import com.android.voicemail.impl.OmtpService; import com.android.voicemail.impl.OmtpVvmCarrierConfigHelper; import com.android.voicemail.impl.VvmLog; import com.android.voicemail.impl.protocol.VisualVoicemailProtocol; @@ -67,7 +67,7 @@ public class StatusSmsFetcher extends BroadcastReceiver implements Closeable { mContext = context; mPhoneAccountHandle = phoneAccountHandle; IntentFilter filter = new IntentFilter(ACTION_REQUEST_SENT_INTENT); - filter.addAction(OmtpReceiver.ACTION_SMS_RECEIVED); + filter.addAction(OmtpService.ACTION_SMS_RECEIVED); context.registerReceiver(this, filter); } @@ -110,7 +110,7 @@ public class StatusSmsFetcher extends BroadcastReceiver implements Closeable { return; } - VisualVoicemailSms sms = intent.getExtras().getParcelable(OmtpReceiver.EXTRA_VOICEMAIL_SMS); + VisualVoicemailSms sms = intent.getExtras().getParcelable(OmtpService.EXTRA_VOICEMAIL_SMS); if (!mPhoneAccountHandle.equals(sms.getPhoneAccountHandle())) { return; diff --git a/java/com/android/voicemail/impl/sync/OmtpVvmSyncService.java b/java/com/android/voicemail/impl/sync/OmtpVvmSyncService.java index af934dd3c..3443737cd 100644 --- a/java/com/android/voicemail/impl/sync/OmtpVvmSyncService.java +++ b/java/com/android/voicemail/impl/sync/OmtpVvmSyncService.java @@ -36,6 +36,7 @@ import com.android.voicemail.impl.VvmLog; import com.android.voicemail.impl.fetch.VoicemailFetchedCallback; import com.android.voicemail.impl.imap.ImapHelper; import com.android.voicemail.impl.imap.ImapHelper.InitializingException; +import com.android.voicemail.impl.mail.store.ImapFolder.Quota; import com.android.voicemail.impl.scheduling.BaseTask; import com.android.voicemail.impl.settings.VisualVoicemailSettingsUtil; import com.android.voicemail.impl.sync.VvmNetworkRequest.NetworkWrapper; @@ -152,21 +153,28 @@ public class OmtpVvmSyncService { */ private void autoDeleteAndArchiveVM( ImapHelper imapHelper, PhoneAccountHandle phoneAccountHandle) { - - if (isArchiveAllowedAndEnabled(mContext, phoneAccountHandle)) { - if ((float) imapHelper.getOccuupiedQuota() / (float) imapHelper.getTotalQuota() - > AUTO_DELETE_ARCHIVE_VM_THRESHOLD) { - deleteAndArchiveVM(imapHelper); - imapHelper.updateQuota(); - LoggerUtils.logImpressionOnMainThread( - mContext, DialerImpression.Type.VVM_ARCHIVE_AUTO_DELETED_VM_FROM_SERVER); - } else { - VvmLog.i(TAG, "no need to archive and auto delete VM, quota below threshold"); - } - } else { + if (!isArchiveAllowedAndEnabled(mContext, phoneAccountHandle)) { VvmLog.i(TAG, "autoDeleteAndArchiveVM is turned off"); LoggerUtils.logImpressionOnMainThread( mContext, DialerImpression.Type.VVM_ARCHIVE_AUTO_DELETE_TURNED_OFF); + return; + } + Quota quotaOnServer = imapHelper.getQuota(); + if (quotaOnServer == null) { + LoggerUtils.logImpressionOnMainThread( + mContext, DialerImpression.Type.VVM_ARCHIVE_AUTO_DELETE_FAILED_DUE_TO_FAILED_QUOTA_CHECK); + VvmLog.e(TAG, "autoDeleteAndArchiveVM failed - Can't retrieve Imap quota."); + return; + } + + if ((float) quotaOnServer.occupied / (float) quotaOnServer.total + > AUTO_DELETE_ARCHIVE_VM_THRESHOLD) { + deleteAndArchiveVM(imapHelper, quotaOnServer); + imapHelper.updateQuota(); + LoggerUtils.logImpressionOnMainThread( + mContext, DialerImpression.Type.VVM_ARCHIVE_AUTO_DELETED_VM_FROM_SERVER); + } else { + VvmLog.i(TAG, "no need to archive and auto delete VM, quota below threshold"); } } @@ -190,14 +198,15 @@ public class OmtpVvmSyncService { return true; } - private void deleteAndArchiveVM(ImapHelper imapHelper) { + private void deleteAndArchiveVM(ImapHelper imapHelper, Quota quotaOnServer) { // Archive column should only be used for 0 and above Assert.isTrue(BuildCompat.isAtLeastO()); + // The number of voicemails that exceed our threshold and should be deleted from the server int numVoicemails = - imapHelper.getOccuupiedQuota() - - (int) (AUTO_DELETE_ARCHIVE_VM_THRESHOLD * imapHelper.getTotalQuota()); + quotaOnServer.occupied - (int) (AUTO_DELETE_ARCHIVE_VM_THRESHOLD * quotaOnServer.total); List oldestVoicemails = mQueryHelper.oldestVoicemailsOnServer(numVoicemails); + VvmLog.w(TAG, "number of voicemails to delete " + numVoicemails); if (!oldestVoicemails.isEmpty()) { mQueryHelper.markArchivedInDatabase(oldestVoicemails); imapHelper.markMessagesAsDeleted(oldestVoicemails); diff --git a/java/com/android/voicemail/impl/sync/SyncOneTask.java b/java/com/android/voicemail/impl/sync/SyncOneTask.java index 19419ec8a..cd2782abb 100644 --- a/java/com/android/voicemail/impl/sync/SyncOneTask.java +++ b/java/com/android/voicemail/impl/sync/SyncOneTask.java @@ -51,7 +51,7 @@ public class SyncOneTask extends BaseTask { intent.putExtra(EXTRA_PHONE_ACCOUNT_HANDLE, phone); intent.putExtra(EXTRA_SYNC_TYPE, OmtpVvmSyncService.SYNC_DOWNLOAD_ONE_TRANSCRIPTION); intent.putExtra(EXTRA_VOICEMAIL, voicemail); - context.startService(intent); + context.sendBroadcast(intent); } public SyncOneTask() { diff --git a/java/com/android/voicemail/impl/sync/SyncTask.java b/java/com/android/voicemail/impl/sync/SyncTask.java index 27f803401..0b3e090bf 100644 --- a/java/com/android/voicemail/impl/sync/SyncTask.java +++ b/java/com/android/voicemail/impl/sync/SyncTask.java @@ -48,7 +48,7 @@ public class SyncTask extends BaseTask { Intent intent = BaseTask.createIntent(context, SyncTask.class, phone); intent.putExtra(EXTRA_PHONE_ACCOUNT_HANDLE, phone); intent.putExtra(EXTRA_SYNC_TYPE, syncType); - context.startService(intent); + context.sendBroadcast(intent); } public SyncTask() { diff --git a/java/com/android/voicemail/impl/sync/UploadTask.java b/java/com/android/voicemail/impl/sync/UploadTask.java index 403074572..f2b2036b5 100644 --- a/java/com/android/voicemail/impl/sync/UploadTask.java +++ b/java/com/android/voicemail/impl/sync/UploadTask.java @@ -44,7 +44,7 @@ public class UploadTask extends BaseTask { public static void start(Context context, PhoneAccountHandle phoneAccountHandle) { Intent intent = BaseTask.createIntent(context, UploadTask.class, phoneAccountHandle); - context.startService(intent); + context.sendBroadcast(intent); } @Override diff --git a/java/com/android/voicemail/impl/sync/VoicemailsQueryHelper.java b/java/com/android/voicemail/impl/sync/VoicemailsQueryHelper.java index bfc2e5f20..9b295dbb7 100644 --- a/java/com/android/voicemail/impl/sync/VoicemailsQueryHelper.java +++ b/java/com/android/voicemail/impl/sync/VoicemailsQueryHelper.java @@ -27,7 +27,6 @@ import android.provider.VoicemailContract; import android.provider.VoicemailContract.Voicemails; import android.support.annotation.NonNull; import android.telecom.PhoneAccountHandle; -import android.text.TextUtils; import com.android.dialer.common.Assert; import com.android.voicemail.impl.Voicemail; import java.util.ArrayList; @@ -54,12 +53,6 @@ public class VoicemailsQueryHelper { Voicemails.DIRTY + "=1 AND " + Voicemails.DELETED + "!=1 AND " + Voicemails.IS_READ + "=1"; static final String DELETED_SELECTION = Voicemails.DELETED + "=1"; static final String ARCHIVED_SELECTION = Voicemails.ARCHIVED + "=0"; - private static final String PHONE_ACCOUNT_HANDLE_SELECTION = - "(" - + Voicemails.PHONE_ACCOUNT_COMPONENT_NAME - + "=? AND " - + Voicemails.PHONE_ACCOUNT_ID - + "=?)"; private Context mContext; private ContentResolver mContentResolver; @@ -101,23 +94,14 @@ public class VoicemailsQueryHelper { /** * Utility method to make queries to the voicemail database. * + *

TODO(b/36588206) add PhoneAccountHandle filtering back + * * @param selection A filter declaring which rows to return. {@code null} returns all rows. * @return A list of voicemails according to the selection statement. */ private List getLocalVoicemails( - @NonNull PhoneAccountHandle phoneAccountHandle, String selection) { - - String[] selectionArgs = - new String[] { - phoneAccountHandle.getComponentName().flattenToString(), phoneAccountHandle.getId() - }; - if (TextUtils.isEmpty(selection)) { - selection = PHONE_ACCOUNT_HANDLE_SELECTION; - } else { - selection = PHONE_ACCOUNT_HANDLE_SELECTION + " AND (" + selection + ")"; - } - - Cursor cursor = mContentResolver.query(mSourceUri, PROJECTION, selection, selectionArgs, null); + @NonNull PhoneAccountHandle unusedPhoneAccountHandle, String selection) { + Cursor cursor = mContentResolver.query(mSourceUri, PROJECTION, selection, null, null); if (cursor == null) { return null; } diff --git a/java/com/android/voicemail/permissions.xml b/java/com/android/voicemail/permissions.xml index adb4b6f54..bedf06898 100644 --- a/java/com/android/voicemail/permissions.xml +++ b/java/com/android/voicemail/permissions.xml @@ -3,7 +3,7 @@ + android:targetSdkVersion="26"/> -- cgit v1.2.3