From 8369df095a73a77b3715f8ae7ba06089cebca4ce Mon Sep 17 00:00:00 2001 From: Eric Erfanian Date: Wed, 3 May 2017 10:27:13 -0700 Subject: This change reflects the Dialer V10 RC00 branch. RC00 is based on: branch: dialer-android_release_branch/153304843.1 synced to: 153304843 following the instructions at go/dialer-aosp-release. In this release: * Removes final apache sources. * Uses native lite compilation. More drops will follow with subsequent release candidates until we reach our final v10 release, in cadence with our prebuilt drops. Test: TreeHugger, on device Change-Id: Ic9684057230f9b579c777820c746cd21bf45ec0f --- .../com/android/voicemail/impl/ActivationTask.java | 21 +- .../com/android/voicemail/impl/AndroidManifest.xml | 26 ++ java/com/android/voicemail/impl/OmtpReceiver.java | 2 +- .../voicemail/impl/OmtpVvmCarrierConfigHelper.java | 2 + .../voicemail/impl/StatusCheckJobService.java | 71 +++++ .../android/voicemail/impl/StatusCheckTask.java | 128 +++++++++ .../voicemail/impl/VoicemailBootReceiver.java | 31 +++ .../voicemail/impl/VoicemailClientImpl.java | 19 +- .../android/voicemail/impl/VoicemailModule.java | 19 +- .../voicemail/impl/VvmPackageInstallReceiver.java | 34 ++- .../impl/fetch/FetchVoicemailReceiver.java | 10 + java/com/android/voicemail/impl/mail/Address.java | 8 +- .../voicemail/impl/mail/internet/MimeMessage.java | 40 ++- .../voicemail/impl/mail/internet/MimeUtility.java | 9 +- .../voicemail/impl/mail/store/ImapFolder.java | 36 ++- .../voicemail/impl/mail/store/ImapStore.java | 3 +- .../voicemail/impl/protocol/Vvm3Protocol.java | 11 +- .../voicemail/impl/res/values-af/strings.xml | 1 - .../voicemail/impl/res/values-am/strings.xml | 1 - .../voicemail/impl/res/values-ar/strings.xml | 1 - .../voicemail/impl/res/values-az/strings.xml | 1 - .../impl/res/values-b+sr+Latn/strings.xml | 53 ++++ .../voicemail/impl/res/values-be/strings.xml | 1 - .../voicemail/impl/res/values-bg/strings.xml | 1 - .../voicemail/impl/res/values-bn/strings.xml | 1 - .../voicemail/impl/res/values-bs/strings.xml | 1 - .../voicemail/impl/res/values-ca/strings.xml | 1 - .../voicemail/impl/res/values-cs/strings.xml | 1 - .../voicemail/impl/res/values-da/strings.xml | 1 - .../voicemail/impl/res/values-de/strings.xml | 1 - .../voicemail/impl/res/values-el/strings.xml | 1 - .../voicemail/impl/res/values-en-rAU/strings.xml | 1 - .../voicemail/impl/res/values-en-rGB/strings.xml | 1 - .../voicemail/impl/res/values-en-rIN/strings.xml | 1 - .../voicemail/impl/res/values-es-rUS/strings.xml | 1 - .../voicemail/impl/res/values-es/strings.xml | 1 - .../voicemail/impl/res/values-et/strings.xml | 1 - .../voicemail/impl/res/values-eu/strings.xml | 1 - .../voicemail/impl/res/values-fa/strings.xml | 1 - .../voicemail/impl/res/values-fi/strings.xml | 1 - .../voicemail/impl/res/values-fr-rCA/strings.xml | 1 - .../voicemail/impl/res/values-fr/strings.xml | 1 - .../voicemail/impl/res/values-gl/strings.xml | 1 - .../voicemail/impl/res/values-gu/strings.xml | 1 - .../voicemail/impl/res/values-hi/strings.xml | 1 - .../voicemail/impl/res/values-hr/strings.xml | 1 - .../voicemail/impl/res/values-hu/strings.xml | 1 - .../voicemail/impl/res/values-hy/strings.xml | 1 - .../voicemail/impl/res/values-in/strings.xml | 1 - .../voicemail/impl/res/values-is/strings.xml | 1 - .../voicemail/impl/res/values-it/strings.xml | 1 - .../voicemail/impl/res/values-iw/strings.xml | 1 - .../voicemail/impl/res/values-ja/strings.xml | 1 - .../voicemail/impl/res/values-ka/strings.xml | 1 - .../voicemail/impl/res/values-kk/strings.xml | 1 - .../voicemail/impl/res/values-km/strings.xml | 1 - .../voicemail/impl/res/values-kn/strings.xml | 1 - .../voicemail/impl/res/values-ko/strings.xml | 1 - .../voicemail/impl/res/values-ky/strings.xml | 1 - .../voicemail/impl/res/values-lo/strings.xml | 1 - .../voicemail/impl/res/values-lt/strings.xml | 1 - .../voicemail/impl/res/values-lv/strings.xml | 1 - .../voicemail/impl/res/values-mk/strings.xml | 1 - .../voicemail/impl/res/values-ml/strings.xml | 1 - .../voicemail/impl/res/values-mn/strings.xml | 1 - .../voicemail/impl/res/values-mr/strings.xml | 1 - .../voicemail/impl/res/values-ms/strings.xml | 1 - .../voicemail/impl/res/values-my/strings.xml | 1 - .../voicemail/impl/res/values-nb/strings.xml | 1 - .../voicemail/impl/res/values-ne/strings.xml | 1 - .../voicemail/impl/res/values-nl/strings.xml | 1 - .../voicemail/impl/res/values-no/strings.xml | 1 - .../voicemail/impl/res/values-pa/strings.xml | 1 - .../voicemail/impl/res/values-pl/strings.xml | 1 - .../voicemail/impl/res/values-pt-rBR/strings.xml | 1 - .../voicemail/impl/res/values-pt-rPT/strings.xml | 1 - .../voicemail/impl/res/values-pt/strings.xml | 1 - .../voicemail/impl/res/values-ro/strings.xml | 1 - .../voicemail/impl/res/values-ru/strings.xml | 1 - .../voicemail/impl/res/values-si/strings.xml | 1 - .../voicemail/impl/res/values-sk/strings.xml | 1 - .../voicemail/impl/res/values-sl/strings.xml | 1 - .../voicemail/impl/res/values-sq/strings.xml | 1 - .../voicemail/impl/res/values-sr/strings.xml | 1 - .../voicemail/impl/res/values-sv/strings.xml | 1 - .../voicemail/impl/res/values-sw/strings.xml | 1 - .../voicemail/impl/res/values-ta/strings.xml | 1 - .../voicemail/impl/res/values-te/strings.xml | 1 - .../voicemail/impl/res/values-th/strings.xml | 1 - .../voicemail/impl/res/values-tl/strings.xml | 1 - .../voicemail/impl/res/values-tr/strings.xml | 1 - .../voicemail/impl/res/values-uk/strings.xml | 1 - .../voicemail/impl/res/values-ur/strings.xml | 1 - .../voicemail/impl/res/values-uz/strings.xml | 1 - .../voicemail/impl/res/values-vi/strings.xml | 1 - .../voicemail/impl/res/values-zh-rCN/strings.xml | 1 - .../voicemail/impl/res/values-zh-rHK/strings.xml | 1 - .../voicemail/impl/res/values-zh-rTW/strings.xml | 1 - .../voicemail/impl/res/values-zu/strings.xml | 1 - .../android/voicemail/impl/res/values/strings.xml | 5 - .../voicemail/impl/scheduling/BaseTask.java | 36 ++- .../voicemail/impl/scheduling/BlockerTask.java | 14 +- .../impl/scheduling/MinimalIntervalPolicy.java | 5 +- .../android/voicemail/impl/scheduling/Policy.java | 4 +- .../voicemail/impl/scheduling/PostponePolicy.java | 6 +- .../voicemail/impl/scheduling/RetryPolicy.java | 11 +- .../android/voicemail/impl/scheduling/Task.java | 38 ++- .../voicemail/impl/scheduling/TaskQueue.java | 149 +++++++++++ .../impl/scheduling/TaskSchedulerJobService.java | 158 +++++++++++ .../impl/scheduling/TaskSchedulerService.java | 294 +++++++++++---------- .../android/voicemail/impl/scheduling/Tasks.java | 73 +++++ .../impl/settings/VisualVoicemailSettingsUtil.java | 2 + .../impl/settings/VoicemailChangePinActivity.java | 7 +- .../impl/settings/VoicemailSettingsFragment.java | 4 +- .../voicemail/impl/sms/LegacyModeSmsHandler.java | 92 ++++++- .../voicemail/impl/sync/OmtpVvmSyncService.java | 33 +-- .../android/voicemail/impl/sync/SyncOneTask.java | 20 +- java/com/android/voicemail/impl/sync/SyncTask.java | 18 +- .../android/voicemail/impl/sync/UploadTask.java | 7 +- .../voicemail/impl/sync/VoicemailsQueryHelper.java | 36 ++- .../android/voicemail/impl/utils/LoggerUtils.java | 33 +++ 121 files changed, 1247 insertions(+), 402 deletions(-) create mode 100644 java/com/android/voicemail/impl/StatusCheckJobService.java create mode 100644 java/com/android/voicemail/impl/StatusCheckTask.java create mode 100644 java/com/android/voicemail/impl/VoicemailBootReceiver.java create mode 100644 java/com/android/voicemail/impl/res/values-b+sr+Latn/strings.xml create mode 100644 java/com/android/voicemail/impl/scheduling/TaskQueue.java create mode 100644 java/com/android/voicemail/impl/scheduling/TaskSchedulerJobService.java create mode 100644 java/com/android/voicemail/impl/scheduling/Tasks.java create mode 100644 java/com/android/voicemail/impl/utils/LoggerUtils.java (limited to 'java/com/android/voicemail/impl') diff --git a/java/com/android/voicemail/impl/ActivationTask.java b/java/com/android/voicemail/impl/ActivationTask.java index c53d3c722..b0ad3bafc 100644 --- a/java/com/android/voicemail/impl/ActivationTask.java +++ b/java/com/android/voicemail/impl/ActivationTask.java @@ -29,8 +29,8 @@ import android.support.annotation.WorkerThread; import android.telecom.PhoneAccountHandle; import android.telephony.ServiceState; import android.telephony.TelephonyManager; -import com.android.dialer.logging.Logger; -import com.android.dialer.logging.nano.DialerImpression; +import com.android.dialer.logging.DialerImpression; +import com.android.dialer.proguard.UsedByReflection; import com.android.voicemail.impl.protocol.VisualVoicemailProtocol; import com.android.voicemail.impl.scheduling.BaseTask; import com.android.voicemail.impl.scheduling.RetryPolicy; @@ -40,6 +40,7 @@ import com.android.voicemail.impl.sms.StatusSmsFetcher; import com.android.voicemail.impl.sync.OmtpVvmSyncService; import com.android.voicemail.impl.sync.SyncTask; import com.android.voicemail.impl.sync.VvmAccountManager; +import com.android.voicemail.impl.utils.LoggerUtils; import java.io.IOException; import java.util.HashSet; import java.util.Set; @@ -55,6 +56,7 @@ import java.util.concurrent.TimeoutException; * spontaneously sent a STATUS SMS. */ @TargetApi(VERSION_CODES.O) +@UsedByReflection(value = "Tasks.java") public class ActivationTask extends BaseTask { private static final String TAG = "VvmActivationTask"; @@ -107,14 +109,15 @@ public class ActivationTask extends BaseTask { } @Override - public void onCreate(Context context, Intent intent, int flags, int startId) { - super.onCreate(context, intent, flags, startId); - mMessageData = intent.getParcelableExtra(EXTRA_MESSAGE_DATA_BUNDLE); + public void onCreate(Context context, Bundle extras) { + super.onCreate(context, extras); + mMessageData = extras.getParcelable(EXTRA_MESSAGE_DATA_BUNDLE); } @Override public Intent createRestartIntent() { - Logger.get(getContext()).logImpression(DialerImpression.Type.VVM_AUTO_RETRY_ACTIVATION); + LoggerUtils.logImpressionOnMainThread( + getContext(), DialerImpression.Type.VVM_AUTO_RETRY_ACTIVATION); Intent intent = super.createRestartIntent(); // mMessageData is discarded, request a fresh STATUS SMS for retries. return intent; @@ -124,7 +127,8 @@ public class ActivationTask extends BaseTask { @WorkerThread public void onExecuteInBackgroundThread() { Assert.isNotMainThread(); - Logger.get(getContext()).logImpression(DialerImpression.Type.VVM_ACTIVATION_STARTED); + LoggerUtils.logImpressionOnMainThread( + getContext(), DialerImpression.Type.VVM_ACTIVATION_STARTED); PhoneAccountHandle phoneAccountHandle = getPhoneAccountHandle(); if (phoneAccountHandle == null) { // This should never happen @@ -234,7 +238,8 @@ public class ActivationTask extends BaseTask { helper.handleEvent(status, OmtpEvents.CONFIG_SERVICE_NOT_AVAILABLE); } } - Logger.get(getContext()).logImpression(DialerImpression.Type.VVM_ACTIVATION_COMPLETED); + LoggerUtils.logImpressionOnMainThread( + getContext(), DialerImpression.Type.VVM_ACTIVATION_COMPLETED); } public static void updateSource( diff --git a/java/com/android/voicemail/impl/AndroidManifest.xml b/java/com/android/voicemail/impl/AndroidManifest.xml index 97e397385..47a4b2dd3 100644 --- a/java/com/android/voicemail/impl/AndroidManifest.xml +++ b/java/com/android/voicemail/impl/AndroidManifest.xml @@ -80,6 +80,16 @@ android:name="com.android.voicemail.impl.scheduling.TaskSchedulerService" android:exported="false"/> + + + + @@ -92,5 +102,21 @@ android:exported="false" android:windowSoftInputMode="stateVisible|adjustResize"> + + + + + + + + + + + + + + diff --git a/java/com/android/voicemail/impl/OmtpReceiver.java b/java/com/android/voicemail/impl/OmtpReceiver.java index 239a544c4..9baf95415 100644 --- a/java/com/android/voicemail/impl/OmtpReceiver.java +++ b/java/com/android/voicemail/impl/OmtpReceiver.java @@ -24,8 +24,8 @@ import android.os.Build.VERSION_CODES; import android.telecom.PhoneAccountHandle; import android.telephony.VisualVoicemailSms; import com.android.dialer.common.Assert; +import com.android.dialer.logging.DialerImpression; import com.android.dialer.logging.Logger; -import com.android.dialer.logging.nano.DialerImpression; import com.android.voicemail.VoicemailComponent; import com.android.voicemail.impl.settings.VisualVoicemailSettingsUtil; import com.android.voicemail.impl.sync.VvmAccountManager; diff --git a/java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java b/java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java index 095f00bb7..2f1df09dd 100644 --- a/java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java +++ b/java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java @@ -336,9 +336,11 @@ public class OmtpVvmCarrierConfigHelper { public void startDeactivation() { Assert.checkArgument(isValid()); + VvmLog.i(TAG, "startDeactivation"); if (!isLegacyModeEnabled()) { // SMS should still be filtered in legacy mode VisualVoicemailService.setSmsFilterSettings(mContext, getPhoneAccountHandle(), null); + VvmLog.i(TAG, "filter disabled"); } if (mProtocol != null) { mProtocol.startDeactivation(this); diff --git a/java/com/android/voicemail/impl/StatusCheckJobService.java b/java/com/android/voicemail/impl/StatusCheckJobService.java new file mode 100644 index 000000000..870c5b471 --- /dev/null +++ b/java/com/android/voicemail/impl/StatusCheckJobService.java @@ -0,0 +1,71 @@ +/** + * 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.app.job.JobInfo; +import android.app.job.JobParameters; +import android.app.job.JobScheduler; +import android.app.job.JobService; +import android.content.ComponentName; +import android.content.Context; +import android.os.Build.VERSION_CODES; +import android.telecom.PhoneAccountHandle; +import android.telecom.TelecomManager; +import com.android.dialer.constants.ScheduledJobIds; +import com.android.voicemail.impl.sync.VvmAccountManager; +import java.util.concurrent.TimeUnit; + +/** + * A job to perform {@link StatusCheckTask} once per day, performing book keeping to ensure the + * credentials and status for a activated voicemail account is still correct. A task will be + * scheduled for each active voicemail account. The status is expected to be always in sync, the + * check is a failsafe to mimic the previous status check on signal return behavior. + */ +@TargetApi(VERSION_CODES.O) +public class StatusCheckJobService extends JobService { + + public static void schedule(Context context) { + JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); + if (jobScheduler.getPendingJob(ScheduledJobIds.VVM_STATUS_CHECK_JOB) != null) { + VvmLog.i("StatusCheckJobService.schedule", "job already scheduled"); + return; + } + + jobScheduler.schedule( + new JobInfo.Builder( + ScheduledJobIds.VVM_STATUS_CHECK_JOB, + new ComponentName(context, StatusCheckJobService.class)) + .setPeriodic(TimeUnit.DAYS.toMillis(1)) + .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) + .setRequiresCharging(true) + .build()); + } + + @Override + public boolean onStartJob(JobParameters params) { + for (PhoneAccountHandle phoneAccountHandle : + getSystemService(TelecomManager.class).getCallCapablePhoneAccounts()) { + if (VvmAccountManager.isAccountActivated(this, phoneAccountHandle)) { + StatusCheckTask.start(this, phoneAccountHandle); + } + } + return false; // not running in background + } + + @Override + public boolean onStopJob(JobParameters params) { + return false; // don't retry + } +} diff --git a/java/com/android/voicemail/impl/StatusCheckTask.java b/java/com/android/voicemail/impl/StatusCheckTask.java new file mode 100644 index 000000000..7699e9848 --- /dev/null +++ b/java/com/android/voicemail/impl/StatusCheckTask.java @@ -0,0 +1,128 @@ +/** + * 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.Context; +import android.content.Intent; +import android.os.Build.VERSION_CODES; +import android.os.Bundle; +import android.telecom.PhoneAccountHandle; +import android.telephony.ServiceState; +import android.telephony.TelephonyManager; +import com.android.dialer.logging.DialerImpression; +import com.android.dialer.proguard.UsedByReflection; +import com.android.voicemail.impl.scheduling.BaseTask; +import com.android.voicemail.impl.sms.StatusMessage; +import com.android.voicemail.impl.sms.StatusSmsFetcher; +import com.android.voicemail.impl.sync.VvmAccountManager; +import com.android.voicemail.impl.utils.LoggerUtils; +import java.io.IOException; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; + +/** + * Task to verify the account status is still correct. This task is only for book keeping so any + * error is ignored and will not retry. If the provision status sent by the carrier is "ready" the + * access credentials will be updated (although it is not expected to change without the carrier + * actively sending out an STATUS SMS which will be handled by {@link + * com.android.voicemail.impl.sms.OmtpMessageReceiver}). If the provisioning status is not ready an + * {@link ActivationTask} will be launched to attempt to correct it. + */ +@TargetApi(VERSION_CODES.O) +@UsedByReflection(value = "Tasks.java") +public class StatusCheckTask extends BaseTask { + + public StatusCheckTask() { + super(TASK_STATUS_CHECK); + } + + public static void start(Context context, PhoneAccountHandle phoneAccountHandle) { + Intent intent = BaseTask.createIntent(context, StatusCheckTask.class, phoneAccountHandle); + context.startService(intent); + } + + @Override + public void onExecuteInBackgroundThread() { + TelephonyManager telephonyManager = + getContext() + .getSystemService(TelephonyManager.class) + .createForPhoneAccountHandle(getPhoneAccountHandle()); + + if (telephonyManager == null) { + VvmLog.w( + "StatusCheckTask.onExecuteInBackgroundThread", + getPhoneAccountHandle() + " no longer valid"); + return; + } + if (telephonyManager.getServiceState().getState() != ServiceState.STATE_IN_SERVICE) { + VvmLog.i( + "StatusCheckTask.onExecuteInBackgroundThread", + getPhoneAccountHandle() + " not in service"); + return; + } + OmtpVvmCarrierConfigHelper config = + new OmtpVvmCarrierConfigHelper(getContext(), getPhoneAccountHandle()); + if (!config.isValid()) { + VvmLog.e( + "StatusCheckTask.onExecuteInBackgroundThread", + "config no longer valid for " + getPhoneAccountHandle()); + VvmAccountManager.removeAccount(getContext(), getPhoneAccountHandle()); + return; + } + + Bundle data; + try (StatusSmsFetcher fetcher = new StatusSmsFetcher(getContext(), getPhoneAccountHandle())) { + config.getProtocol().requestStatus(config, fetcher.getSentIntent()); + // Both the fetcher and OmtpMessageReceiver will be triggered, but + // OmtpMessageReceiver will just route the SMS back to ActivationTask, which will be + // rejected because the task is still running. + data = fetcher.get(); + } catch (TimeoutException e) { + VvmLog.e("StatusCheckTask.onExecuteInBackgroundThread", "timeout requesting status"); + return; + } catch (CancellationException e) { + VvmLog.e("StatusCheckTask.onExecuteInBackgroundThread", "Unable to send status request SMS"); + return; + } catch (InterruptedException | ExecutionException | IOException e) { + VvmLog.e("StatusCheckTask.onExecuteInBackgroundThread", "can't get future STATUS SMS", e); + return; + } + + StatusMessage message = new StatusMessage(data); + VvmLog.i( + "StatusCheckTask.onExecuteInBackgroundThread", + "STATUS SMS received: st=" + + message.getProvisioningStatus() + + ", rc=" + + message.getReturnCode()); + if (message.getProvisioningStatus().equals(OmtpConstants.SUBSCRIBER_READY)) { + VvmLog.i( + "StatusCheckTask.onExecuteInBackgroundThread", + "subscriber ready, no activation required"); + LoggerUtils.logImpressionOnMainThread( + getContext(), DialerImpression.Type.VVM_STATUS_CHECK_READY); + VvmAccountManager.addAccount(getContext(), getPhoneAccountHandle(), message); + } else { + VvmLog.i( + "StatusCheckTask.onExecuteInBackgroundThread", + "subscriber not ready, attempting reactivation"); + VvmAccountManager.removeAccount(getContext(), getPhoneAccountHandle()); + LoggerUtils.logImpressionOnMainThread( + getContext(), DialerImpression.Type.VVM_STATUS_CHECK_REACTIVATION); + ActivationTask.start(getContext(), getPhoneAccountHandle(), data); + } + } +} diff --git a/java/com/android/voicemail/impl/VoicemailBootReceiver.java b/java/com/android/voicemail/impl/VoicemailBootReceiver.java new file mode 100644 index 000000000..0a3e61a01 --- /dev/null +++ b/java/com/android/voicemail/impl/VoicemailBootReceiver.java @@ -0,0 +1,31 @@ +/** + * 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.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import com.android.voicemail.VoicemailComponent; + +/** Receives {@link Intent#ACTION_BOOT_COMPLETED} for the voicemail module. */ +public class VoicemailBootReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + if (!VoicemailComponent.get(context).getVoicemailClient().isVoicemailModuleEnabled()) { + return; + } + StatusCheckJobService.schedule(context); + } +} diff --git a/java/com/android/voicemail/impl/VoicemailClientImpl.java b/java/com/android/voicemail/impl/VoicemailClientImpl.java index 31a12791c..7747b2486 100644 --- a/java/com/android/voicemail/impl/VoicemailClientImpl.java +++ b/java/com/android/voicemail/impl/VoicemailClientImpl.java @@ -31,6 +31,7 @@ import com.android.voicemail.VoicemailClient; import com.android.voicemail.impl.settings.VisualVoicemailSettingsUtil; import com.android.voicemail.impl.settings.VoicemailChangePinActivity; import com.android.voicemail.impl.settings.VoicemailSettingsFragment; +import com.android.voicemail.impl.sync.VvmAccountManager; import java.util.List; import javax.inject.Inject; @@ -67,6 +68,17 @@ public class VoicemailClientImpl implements VoicemailClient { return true; } + @Override + public boolean isVoicemailEnabled(Context context, PhoneAccountHandle phoneAccountHandle) { + return VisualVoicemailSettingsUtil.isEnabled(context, phoneAccountHandle); + } + + @Override + public void setVoicemailEnabled( + Context context, PhoneAccountHandle phoneAccountHandle, boolean enabled) { + VisualVoicemailSettingsUtil.setEnabled(context, phoneAccountHandle, enabled); + } + @Nullable @Override public String getSettingsFragment() { @@ -85,7 +97,7 @@ public class VoicemailClientImpl implements VoicemailClient { return false; } - if (!ConfigProviderBindings.get(context).getBoolean(ALLOW_VOICEMAIL_ARCHIVE, true)) { + if (!ConfigProviderBindings.get(context).getBoolean(ALLOW_VOICEMAIL_ARCHIVE, false)) { LogUtil.i( "VoicemailClientImpl.isVoicemailArchiveAllowed", "feature disabled by config: %s", @@ -109,6 +121,11 @@ public class VoicemailClientImpl implements VoicemailClient { return intent; } + @Override + public boolean isActivated(Context context, PhoneAccountHandle phoneAccountHandle) { + return VvmAccountManager.isAccountActivated(context, phoneAccountHandle); + } + @TargetApi(VERSION_CODES.O) @Override public void appendOmtpVoicemailSelectionClause( diff --git a/java/com/android/voicemail/impl/VoicemailModule.java b/java/com/android/voicemail/impl/VoicemailModule.java index c3e5714d5..5a4e739f5 100644 --- a/java/com/android/voicemail/impl/VoicemailModule.java +++ b/java/com/android/voicemail/impl/VoicemailModule.java @@ -16,8 +16,10 @@ package com.android.voicemail.impl; +import android.content.Context; import android.support.v4.os.BuildCompat; import com.android.voicemail.VoicemailClient; +import com.android.voicemail.VoicemailPermissionHelper; import com.android.voicemail.stub.StubVoicemailClient; import dagger.Module; import dagger.Provides; @@ -29,12 +31,21 @@ public final class VoicemailModule { @Provides @Singleton - static VoicemailClient provideVoicemailClient() { - if (BuildCompat.isAtLeastO()) { - return new VoicemailClientImpl(); - } else { + static VoicemailClient provideVoicemailClient(Context context) { + if (!BuildCompat.isAtLeastO()) { + VvmLog.i("VoicemailModule.provideVoicemailClient", "SDK below O"); return new StubVoicemailClient(); } + + if (!VoicemailPermissionHelper.hasPermissions(context)) { + VvmLog.i( + "VoicemailModule.provideVoicemailClient", + "missing permissions " + VoicemailPermissionHelper.getMissingPermissions(context)); + return new StubVoicemailClient(); + } + + VvmLog.i("VoicemailModule.provideVoicemailClient", "providing VoicemailClientImpl"); + return new VoicemailClientImpl(); } private VoicemailModule() {} diff --git a/java/com/android/voicemail/impl/VvmPackageInstallReceiver.java b/java/com/android/voicemail/impl/VvmPackageInstallReceiver.java index d92012147..1e2de6070 100644 --- a/java/com/android/voicemail/impl/VvmPackageInstallReceiver.java +++ b/java/com/android/voicemail/impl/VvmPackageInstallReceiver.java @@ -25,7 +25,8 @@ import com.android.voicemail.impl.settings.VisualVoicemailSettingsUtil; /** * When a new package is installed, check if it matches any of the vvm carrier apps of the currently - * enabled dialer vvm sources. + * enabled dialer VVM sources. The dialer VVM client will be disabled upon carrier VVM app + * installation, unless it was explicitly enabled by the user. */ public class VvmPackageInstallReceiver extends BroadcastReceiver { @@ -46,25 +47,34 @@ public class VvmPackageInstallReceiver extends BroadcastReceiver { return; } + // 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()) { - if (VisualVoicemailSettingsUtil.isEnabledUserSet(context, phoneAccount)) { - // Skip the check if this voicemail source's setting is overridden by the user. - continue; - } - OmtpVvmCarrierConfigHelper carrierConfigHelper = new OmtpVvmCarrierConfigHelper(context, phoneAccount); + if (!carrierConfigHelper.isValid()) { + continue; + } if (carrierConfigHelper.getCarrierVvmPackageNames() == null) { continue; } - if (carrierConfigHelper.getCarrierVvmPackageNames().contains(packageName)) { - // 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(TAG, "Carrier VVM package installed, disabling system VVM client"); - VisualVoicemailSettingsUtil.setEnabled(context, phoneAccount, false); + if (!carrierConfigHelper.getCarrierVvmPackageNames().contains(packageName)) { + continue; } + + VvmLog.i(TAG, "Carrier app installed"); + if (VisualVoicemailSettingsUtil.isEnabledUserSet(context, phoneAccount)) { + // Skip the check if this voicemail source's setting is overridden by the user. + VvmLog.i(TAG, "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(TAG, "Carrier VVM package installed, disabling system VVM client"); + VisualVoicemailSettingsUtil.setEnabled(context, phoneAccount, false); } } } diff --git a/java/com/android/voicemail/impl/fetch/FetchVoicemailReceiver.java b/java/com/android/voicemail/impl/fetch/FetchVoicemailReceiver.java index b0285672e..0348a60c5 100644 --- a/java/com/android/voicemail/impl/fetch/FetchVoicemailReceiver.java +++ b/java/com/android/voicemail/impl/fetch/FetchVoicemailReceiver.java @@ -120,6 +120,16 @@ public class FetchVoicemailReceiver extends BroadcastReceiver { new PhoneAccountHandle( ComponentName.unflattenFromString(cursor.getString(PHONE_ACCOUNT_COMPONENT_NAME)), cursor.getString(PHONE_ACCOUNT_ID)); + TelephonyManager telephonyManager = + context + .getSystemService(TelephonyManager.class) + .createForPhoneAccountHandle(mPhoneAccount); + if (telephonyManager == null) { + // can happen when trying to fetch voicemails from a SIM that is no longer on the + // device + VvmLog.e(TAG, "account no longer valid, cannot retrieve message"); + return; + } if (!VvmAccountManager.isAccountActivated(context, mPhoneAccount)) { mPhoneAccount = getAccountFromMarshmallowAccount(context, mPhoneAccount); if (mPhoneAccount == null) { diff --git a/java/com/android/voicemail/impl/mail/Address.java b/java/com/android/voicemail/impl/mail/Address.java index 3a7a86607..ac8e8a294 100644 --- a/java/com/android/voicemail/impl/mail/Address.java +++ b/java/com/android/voicemail/impl/mail/Address.java @@ -25,8 +25,9 @@ import android.text.util.Rfc822Tokenizer; import com.android.voicemail.impl.mail.utils.LogUtils; import java.util.ArrayList; import java.util.regex.Pattern; +import org.apache.james.mime4j.codec.DecodeMonitor; +import org.apache.james.mime4j.codec.DecoderUtil; import org.apache.james.mime4j.codec.EncoderUtil; -import org.apache.james.mime4j.decoder.DecoderUtil; /** * This class represent email address. @@ -121,7 +122,8 @@ public class Address implements Parcelable { if (TextUtils.isEmpty(rawAddress)) { return null; } - String name, address; + String name; + String address; final Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(rawAddress); if (tokens.length > 0) { final String tokenizedName = tokens[0].getName(); @@ -171,7 +173,7 @@ public class Address implements Parcelable { if (personal != null) { personal = REMOVE_OPTIONAL_DQUOTE.matcher(personal).replaceAll("$1"); personal = UNQUOTE.matcher(personal).replaceAll("$1"); - personal = DecoderUtil.decodeEncodedWords(personal); + personal = DecoderUtil.decodeEncodedWords(personal, DecodeMonitor.STRICT); if (personal.length() == 0) { personal = null; } diff --git a/java/com/android/voicemail/impl/mail/internet/MimeMessage.java b/java/com/android/voicemail/impl/mail/internet/MimeMessage.java index dfb7d7c25..589720660 100644 --- a/java/com/android/voicemail/impl/mail/internet/MimeMessage.java +++ b/java/com/android/voicemail/impl/mail/internet/MimeMessage.java @@ -34,12 +34,14 @@ import java.util.Date; import java.util.Locale; import java.util.Stack; import java.util.regex.Pattern; -import org.apache.james.mime4j.BodyDescriptor; -import org.apache.james.mime4j.ContentHandler; -import org.apache.james.mime4j.EOLConvertingInputStream; -import org.apache.james.mime4j.MimeStreamParser; -import org.apache.james.mime4j.field.DateTimeField; -import org.apache.james.mime4j.field.Field; +import org.apache.james.mime4j.MimeException; +import org.apache.james.mime4j.dom.field.DateTimeField; +import org.apache.james.mime4j.field.DefaultFieldParser; +import org.apache.james.mime4j.io.EOLConvertingInputStream; +import org.apache.james.mime4j.parser.ContentHandler; +import org.apache.james.mime4j.parser.MimeStreamParser; +import org.apache.james.mime4j.stream.BodyDescriptor; +import org.apache.james.mime4j.stream.Field; /** * An implementation of Message that stores all of its metadata in RFC 822 and RFC 2045 style @@ -64,7 +66,6 @@ public class MimeMessage extends Message { private Body mBody; protected int mSize; private boolean mInhibitLocalMessageId = false; - private boolean mComplete = true; // Shared random source for generating local message-id values private static final java.util.Random sRandom = new java.util.Random(); @@ -114,7 +115,7 @@ public class MimeMessage extends Message { * @throws IOException * @throws MessagingException */ - public MimeMessage(InputStream in) throws IOException, MessagingException { + public MimeMessage(InputStream in) throws IOException, MessagingException, MimeException { parse(in); } @@ -136,17 +137,9 @@ public class MimeMessage extends Message { return parser; } - protected void parse(InputStream in) throws IOException, MessagingException { + public void parse(InputStream in) throws IOException, MessagingException, MimeException { final MimeStreamParser parser = init(); parser.parse(new EOLConvertingInputStream(in)); - mComplete = !parser.getPrematureEof(); - } - - public void parse(InputStream in, EOLConvertingInputStream.Callback callback) - throws IOException, MessagingException { - final MimeStreamParser parser = init(); - parser.parse(new EOLConvertingInputStream(in, getSize(), callback)); - mComplete = !parser.getPrematureEof(); } /** @@ -171,7 +164,8 @@ public class MimeMessage extends Message { try { DateTimeField field = (DateTimeField) - Field.parse("Date: " + MimeUtility.unfoldAndDecode(getFirstHeader("Date"))); + DefaultFieldParser.parse( + "Date: " + MimeUtility.unfoldAndDecode(getFirstHeader("Date"))); mSentDate = field.getDate(); // TODO: We should make it more clear what exceptions can be thrown here, // and whether they reflect a normal or error condition. @@ -184,7 +178,7 @@ public class MimeMessage extends Message { try { DateTimeField field = (DateTimeField) - Field.parse( + DefaultFieldParser.parse( "Date: " + MimeUtility.unfoldAndDecode(getFirstHeader("Delivery-date"))); mSentDate = field.getDate(); // TODO: We should make it more clear what exceptions can be thrown here, @@ -228,10 +222,6 @@ public class MimeMessage extends Message { } } - public boolean isComplete() { - return mComplete; - } - @Override public String getMimeType() throws MessagingException { return MimeUtility.getHeaderParameter(getContentType(), null); @@ -577,10 +567,10 @@ public class MimeMessage extends Message { } @Override - public void field(String fieldData) { + public void field(Field rawField) { expect(Part.class); try { - final String[] tokens = fieldData.split(":", 2); + final String[] tokens = rawField.getRaw().toString().split(":", 2); ((Part) stack.peek()).addHeader(tokens[0], tokens[1].trim()); } catch (MessagingException me) { throw new Error(me); diff --git a/java/com/android/voicemail/impl/mail/internet/MimeUtility.java b/java/com/android/voicemail/impl/mail/internet/MimeUtility.java index 99846027b..bd85e478c 100644 --- a/java/com/android/voicemail/impl/mail/internet/MimeUtility.java +++ b/java/com/android/voicemail/impl/mail/internet/MimeUtility.java @@ -34,9 +34,10 @@ import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.io.IOUtils; +import org.apache.james.mime4j.codec.DecodeMonitor; +import org.apache.james.mime4j.codec.DecoderUtil; import org.apache.james.mime4j.codec.EncoderUtil; -import org.apache.james.mime4j.decoder.DecoderUtil; -import org.apache.james.mime4j.decoder.QuotedPrintableInputStream; +import org.apache.james.mime4j.codec.QuotedPrintableInputStream; import org.apache.james.mime4j.util.CharsetUtil; public class MimeUtility { @@ -65,7 +66,7 @@ public class MimeUtility { if (s == null) { return null; } - return DecoderUtil.decodeEncodedWords(s); + return DecoderUtil.decodeEncodedWords(s, DecodeMonitor.STRICT); } public static String unfoldAndDecode(String s) { @@ -235,7 +236,7 @@ public class MimeUtility { /* * See if there is conversion from the MIME charset to the Java one. */ - charset = CharsetUtil.toJavaCharset(charset); + charset = CharsetUtil.lookup(charset).name(); } /* * No encoding, so use us-ascii, which is the standard. diff --git a/java/com/android/voicemail/impl/mail/store/ImapFolder.java b/java/com/android/voicemail/impl/mail/store/ImapFolder.java index 1d9b01120..5760ee216 100644 --- a/java/com/android/voicemail/impl/mail/store/ImapFolder.java +++ b/java/com/android/voicemail/impl/mail/store/ImapFolder.java @@ -22,6 +22,7 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.Base64DataException; import com.android.voicemail.impl.OmtpEvents; +import com.android.voicemail.impl.VvmLog; import com.android.voicemail.impl.mail.AuthenticationFailedException; import com.android.voicemail.impl.mail.Body; import com.android.voicemail.impl.mail.FetchProfile; @@ -41,7 +42,6 @@ import com.android.voicemail.impl.mail.store.imap.ImapElement; import com.android.voicemail.impl.mail.store.imap.ImapList; import com.android.voicemail.impl.mail.store.imap.ImapResponse; import com.android.voicemail.impl.mail.store.imap.ImapString; -import com.android.voicemail.impl.mail.utils.LogUtils; import com.android.voicemail.impl.mail.utils.Utility; import java.io.IOException; import java.io.InputStream; @@ -66,7 +66,7 @@ public class ImapFolder { private String mMode; private boolean mExists; /** A set of hashes that can be used to track dirtiness */ - Object mHash[]; + Object[] mHash; public static final String MODE_READ_ONLY = "mode_read_only"; public static final String MODE_READ_WRITE = "mode_read_write"; @@ -136,7 +136,7 @@ public class ImapFolder { try { expunge(); } catch (MessagingException e) { - LogUtils.e(TAG, e, "Messaging Exception"); + VvmLog.e(TAG, "Messaging Exception", e); } } mMessageCount = -1; @@ -174,13 +174,13 @@ public class ImapFolder { try { final String command = ImapConstants.UID_SEARCH + " " + searchCriteria; final String[] result = getSearchUids(mConnection.executeSimpleCommand(command)); - LogUtils.d(TAG, "searchForUids '" + searchCriteria + "' results: " + result.length); + VvmLog.d(TAG, "searchForUids '" + searchCriteria + "' results: " + result.length); return result; } catch (ImapException me) { - LogUtils.d(TAG, "ImapException in search: " + searchCriteria, me); + VvmLog.d(TAG, "ImapException in search: " + searchCriteria, me); return Utility.EMPTY_STRINGS; // Not found } catch (IOException ioe) { - LogUtils.d(TAG, "IOException in search: " + searchCriteria, ioe); + VvmLog.d(TAG, "IOException in search: " + searchCriteria, ioe); mStore.getImapHelper().handleEvent(OmtpEvents.DATA_GENERIC_IMAP_IOE); throw ioExceptionHandler(mConnection, ioe); } @@ -199,7 +199,7 @@ public class ImapFolder { return new ImapMessage(uid, this); } } - LogUtils.e(TAG, "UID " + uid + " not found on server"); + VvmLog.e(TAG, "UID " + uid + " not found on server"); return null; } @@ -235,7 +235,7 @@ public class ImapFolder { try { fetchInternal(messages, fp, listener); } catch (RuntimeException e) { // Probably a parser error. - LogUtils.w(TAG, "Exception detected: " + e.getMessage()); + VvmLog.w(TAG, "Exception detected: " + e.getMessage()); throw e; } } @@ -346,7 +346,11 @@ public class ImapFolder { message.setInternalDate(internalDate); message.setSize(size); - message.parse(Utility.streamFromAsciiString(header)); + try { + message.parse(Utility.streamFromAsciiString(header)); + } catch (Exception e) { + VvmLog.e(TAG, "Error parsing header %s", e); + } } if (fp.contains(FetchProfile.Item.STRUCTURE)) { ImapList bs = fetchList.getKeyedListOrEmpty(ImapConstants.BODYSTRUCTURE); @@ -354,7 +358,7 @@ public class ImapFolder { try { parseBodyStructure(bs, message, ImapConstants.TEXT); } catch (MessagingException e) { - LogUtils.v(TAG, e, "Error handling message"); + VvmLog.v(TAG, "Error handling message", e); message.setBody(null); } } @@ -365,11 +369,15 @@ public class ImapFolder { // TODO Should we accept "RFC822" as well?? ImapString body = fetchList.getKeyedStringOrEmpty("BODY[]", true); InputStream bodyStream = body.getAsStream(); - message.parse(bodyStream); + try { + message.parse(bodyStream); + } catch (Exception e) { + VvmLog.e(TAG, "Error parsing body %s", e); + } } if (fetchPart != null) { InputStream bodyStream = fetchList.getKeyedStringOrEmpty("BODY[", true).getAsStream(); - String encodings[] = fetchPart.getHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING); + String[] encodings = fetchPart.getHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING); String contentTransferEncoding = null; if (encodings != null && encodings.length > 0) { @@ -397,7 +405,7 @@ public class ImapFolder { // from here. This blanket catch-all is because we're not sure what to // do if we don't have a contentTransferEncoding, and we don't have // time to figure out what exceptions might be thrown. - LogUtils.e(TAG, "Error fetching body %s", e); + VvmLog.e(TAG, "Error fetching body %s", e); } } @@ -782,7 +790,7 @@ public class ImapFolder { } private MessagingException ioExceptionHandler(ImapConnection connection, IOException ioe) { - LogUtils.d(TAG, "IO Exception detected: ", ioe); + VvmLog.d(TAG, "IO Exception detected: ", ioe); connection.close(); if (connection == mConnection) { mConnection = null; // To prevent close() from returning the connection to the pool. diff --git a/java/com/android/voicemail/impl/mail/store/ImapStore.java b/java/com/android/voicemail/impl/mail/store/ImapStore.java index cadbe593f..838bae257 100644 --- a/java/com/android/voicemail/impl/mail/store/ImapStore.java +++ b/java/com/android/voicemail/impl/mail/store/ImapStore.java @@ -25,6 +25,7 @@ import com.android.voicemail.impl.mail.MessagingException; import com.android.voicemail.impl.mail.internet.MimeMessage; import java.io.IOException; import java.io.InputStream; +import org.apache.james.mime4j.MimeException; public class ImapStore { /** @@ -112,7 +113,7 @@ public class ImapStore { } @Override - public void parse(InputStream in) throws IOException, MessagingException { + public void parse(InputStream in) throws IOException, MessagingException, MimeException { super.parse(in); } diff --git a/java/com/android/voicemail/impl/protocol/Vvm3Protocol.java b/java/com/android/voicemail/impl/protocol/Vvm3Protocol.java index 5a720c609..fc7fdf3d4 100644 --- a/java/com/android/voicemail/impl/protocol/Vvm3Protocol.java +++ b/java/com/android/voicemail/impl/protocol/Vvm3Protocol.java @@ -25,8 +25,7 @@ import android.os.Bundle; import android.support.annotation.Nullable; import android.telecom.PhoneAccountHandle; import android.text.TextUtils; -import com.android.dialer.logging.Logger; -import com.android.dialer.logging.nano.DialerImpression; +import com.android.dialer.logging.DialerImpression; import com.android.voicemail.impl.ActivationTask; import com.android.voicemail.impl.OmtpConstants; import com.android.voicemail.impl.OmtpEvents; @@ -45,6 +44,7 @@ import com.android.voicemail.impl.sms.Vvm3MessageSender; import com.android.voicemail.impl.sync.VvmNetworkRequest; import com.android.voicemail.impl.sync.VvmNetworkRequest.NetworkWrapper; import com.android.voicemail.impl.sync.VvmNetworkRequest.RequestFailedException; +import com.android.voicemail.impl.utils.LoggerUtils; import java.io.IOException; import java.security.SecureRandom; import java.util.Locale; @@ -116,7 +116,8 @@ public class Vvm3Protocol extends VisualVoicemailProtocol { StatusMessage message, Bundle data) { VvmLog.i(TAG, "start vvm3 provisioning"); - Logger.get(config.getContext()).logImpression(DialerImpression.Type.VVM_PROVISIONING_STARTED); + LoggerUtils.logImpressionOnMainThread( + config.getContext(), DialerImpression.Type.VVM_PROVISIONING_STARTED); if (OmtpConstants.SUBSCRIBER_UNKNOWN.equals(message.getProvisioningStatus())) { VvmLog.i(TAG, "Provisioning status: Unknown"); if (VVM3_UNKNOWN_SUBSCRIBER_CAN_SUBSCRIBE_RESPONSE_CODE.equals(message.getReturnCode())) { @@ -229,8 +230,8 @@ public class Vvm3Protocol extends VisualVoicemailProtocol { // Only close new user tutorial if the PIN has been changed. helper.closeNewUserTutorial(); VvmLog.i(TAG, "new user: NUT closed"); - Logger.get(config.getContext()) - .logImpression(DialerImpression.Type.VVM_PROVISIONING_COMPLETED); + LoggerUtils.logImpressionOnMainThread( + config.getContext(), DialerImpression.Type.VVM_PROVISIONING_COMPLETED); config.requestStatus(null); } } catch (InitializingException | MessagingException | IOException e) { 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 b209eea0d..71263217f 100644 --- a/java/com/android/voicemail/impl/res/values-af/strings.xml +++ b/java/com/android/voicemail/impl/res/values-af/strings.xml @@ -24,7 +24,6 @@ "Gevorderde instellings" "Visuele stemboodskap" "Ekstra rugsteun en berging" - " ""Dit is \'n eksperimentele kenmerk"" wat ons tans toets. Dit kan potensieel stemboodskappe van jou stemboodskapbediener af uitvee. Daar is geen waarborg dat hierdie kenmerk in die toekoms gesteun sal word nie. Ons sal egter graag terugvoer oor die kenmerk wil hê." "Stel PIN" "Verander PIN" "Visuele stemboodskap moet geaktiveer wees om PIN te verander" 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 4124de5f7..d350bbd94 100644 --- a/java/com/android/voicemail/impl/res/values-am/strings.xml +++ b/java/com/android/voicemail/impl/res/values-am/strings.xml @@ -24,7 +24,6 @@ "የላቁ ቅንብሮች" "ምስላዊ የድምፅ መልዕክት" "ተጨማሪ ምትኬ እና ማከማቻ" - " ""ይህ የሙከራ ባህሪ ነው"" አሁን እየሞከርን ነው። ይህ ምናልባት ከድምፅ መልዕክት አገልጋይዎ ላይ የድምፅ መልዕክቶችን ሊሰርዝ ይችላል። ለወደፊቱ ይህን ባህሪ የመደገፍ ዋስትናዎችም የሉም። ነገር ግን በባህሪው ላይ ግብረመልስ ብናገኝ እንወዳለን።" "ፒን ያዘጋጁ" "ፒን ይቀይሩ" "ፒን ለመቀየር የእይታ የድምጽ መልዕክት መንቃት አለበት" 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 5d6fbba37..679dcce9c 100644 --- a/java/com/android/voicemail/impl/res/values-ar/strings.xml +++ b/java/com/android/voicemail/impl/res/values-ar/strings.xml @@ -24,7 +24,6 @@ "الإعدادات المتقدمة" "بريد صوتي مرئي" "نسخة احتياطية وسعة تخزين إضافية" - " ""هذه الميزة تجريبية"" نحن حاليًا في مرحلة اختبار. سيؤدي هذا على الأرجح إلى حذف رسائل البريد الصوتي من خادم البريد الصوتي. لا توجد أي ضمانات بشأن دعم هذه الميزة مستقبلاً. إلا أننا نود الحصول على تعليقات بشأن هذه الميزة." "تعيين رقم التعريف الشخصي" "تغيير رقم التعريف الشخصي" "ينبغي تشغيل البريد الصوتي المرئي لتغيير رقم التعريف الشخصي" 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 ce68f9963..87b4c0692 100644 --- a/java/com/android/voicemail/impl/res/values-az/strings.xml +++ b/java/com/android/voicemail/impl/res/values-az/strings.xml @@ -24,7 +24,6 @@ "Qabaqcıl Ayarlar" "Görünən Səsli e-poçt" "Əlavə yedəkləmə və yaddaş" - " Bu, hazırda yoxladığımız ""eksperimantal funksiyadır"". Bununla səsli e-poçt serverindən səsli e-məktublar potensial olaraq silinəcək. Gələcəkdə bu funksiyanın dəstəklənəcəyinə zəmanət verilmir. Lakin funksiya haqqında əks əlaqənizi istərdik." "PIN ayarlayın" "PIN-i dəyişin" "PIN-i dəyişmək üçün görünən səsli e-poçt aktiv olmalıdır" 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 new file mode 100644 index 000000000..193913081 --- /dev/null +++ b/java/com/android/voicemail/impl/res/values-b+sr+Latn/strings.xml @@ -0,0 +1,53 @@ + + + + + "Govorna pošta (%s)" + "Govorna pošta" + "Vibracija" + "Vibracija" + "Zvuk" + "Napredna podešavanja" + "Vizuelna govorna pošta" + "Dodatne rezervne kopije i prostor" + "Podesite PIN" + "Promenite PIN" + "Morate da omogućite vizuelnu govornu poštu da biste promenili PIN" + "Vizuelna govorna pošta još uvek nije aktivirana, probajte ponovo kasnije" + "Stari PIN" + "Novi PIN" + "Sačekajte." + "Novi PIN je prekratak." + "Novi PIN je predugačak." + "Novi PIN je preslab. Jaka lozinka ne treba da sadrži uzastopni niz ni ponovljene cifre." + "Stari PIN se ne podudara." + "Novi PIN sadrži nevažeće znakove." + "Promena PIN-a nije uspela" + "Nepodržani tip poruke. Pozovite %s da biste je preslušali." + "Promenite PIN kôd govorne pošte" + "Nastavi" + "Otkaži" + "Potvrdi" + "Potvrdite stari PIN" + "Unesite PIN kôd govorne pošte da biste nastavili." + "Podesite novi PIN" + "Broj cifara koje PIN mora da sadrži: %1$d%2$d." + "Potvrdite PIN" + "PIN-ovi se ne podudaraju" + "PIN kôd govorne pošte je ažuriran" + "Podešavanje PIN-a nije uspelo" + 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 ea4a00ca0..874b4791a 100644 --- a/java/com/android/voicemail/impl/res/values-be/strings.xml +++ b/java/com/android/voicemail/impl/res/values-be/strings.xml @@ -24,7 +24,6 @@ "Пашыраныя налады" "Візуальная галасавая пошта" "Дадатковае рэзервовае капір. і сховішча" - " ""Гэта эксперыментальная характарыстыка"", якую мы тэсціруем. Патэнцыяльна яна будзе выдаляць паведамленні галасавой пошты з вашага сервера галасавой пошты. Падтрымка гэтай характарыстыкі ў будучым не гарантуецца. Але мы будзем вельмі ўдзячны за водгукі на гэту характарыстыку." "Задаць PIN-код" "Змяніць PIN-код" "Трэба ўключыць візуальную галасавую пошту, каб змяніць PIN-код" 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 95cc05f36..f987015e9 100644 --- a/java/com/android/voicemail/impl/res/values-bg/strings.xml +++ b/java/com/android/voicemail/impl/res/values-bg/strings.xml @@ -24,7 +24,6 @@ "Разширени настройки" "Визуална гласова поща" "Допълнителни резервни копия и хранилище" - " ""Това е експериментална функция"", която тестваме понастоящем. Тя потенциално може да изтрие гласови съобщения от сървъра ви за гласова поща. Няма гаранции за поддръжката й в бъдеще. Но ще се радваме на отзиви за нея." "Задаване на ПИН код" "Промяна на ПИН кода" "За промяна на ПИН кода трябва да бъде активирана визуалната гласова поща" 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 dbbeb4d9f..699576d41 100644 --- a/java/com/android/voicemail/impl/res/values-bn/strings.xml +++ b/java/com/android/voicemail/impl/res/values-bn/strings.xml @@ -24,7 +24,6 @@ "উন্নত সেটিংস" "ভিজ্যুয়াল ভয়েসমেল" "অতিরিক্ত ব্যাক আপ এবং সঞ্চয়স্থান" - " ""এটি একটি পরীক্ষামূলক বৈশিষ্ট্য"" যা আমরা বর্তমানে পরীক্ষা করছি। এটি সম্ভবত আপনার ভয়েসমেল সার্ভার থেকে ভয়েসমেলগুলি মুছবে। যদিও ভবিষ্যতে এই বৈশিষ্ট্যতে সমর্থন পাওয়ার কোন গ্যারান্টি নেই। যদিও আমরা এই বৈশিষ্ট্যটির উপর মতামত পেলে খুব খুশি হব।" "পিন সেট করুন" "পিন পরিবর্তন করুন" "পিন পরিবর্তন করতে ভিজ্যুয়াল ভয়েসমেল অবশ্যই সক্ষম করতে হবে" 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 6d2b5b30c..2c8cc7682 100644 --- a/java/com/android/voicemail/impl/res/values-bs/strings.xml +++ b/java/com/android/voicemail/impl/res/values-bs/strings.xml @@ -24,7 +24,6 @@ "Napredne postavke" "Vizuelna govorna pošta" "Dodatna sigurnosna kopija i pohrana" - " ""Ovo je eksperimentalna funkcija"" koju trenutno testiramo. Moguće je da ova radnja izbriše poruke govorne pošte sa servera govorne pošte. Nema garancije da će ova funkcija biti podržana u budućnosti. Ipak bismo željeli primiti povratne informacije o funkciji." "Postavite PIN kôd" "Promijenite PIN kôd" "Vizuelna govorna pošta mora biti omogućena za promjenu PIN kôda" 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 bbac25294..b6525d02b 100644 --- a/java/com/android/voicemail/impl/res/values-ca/strings.xml +++ b/java/com/android/voicemail/impl/res/values-ca/strings.xml @@ -24,7 +24,6 @@ "Configuració avançada" "Bústia de veu visual" "Còpia de seguretat addicional i emmagatz." - " ""Aquesta funció està en mode de prova"" i és possible que suprimeixi els missatges de veu del servidor de la bústia. No podem garantir-ne la continuïtat en el futur. De tota manera, ens agradaria saber què en penses." "Defineix el PIN" "Canvia el PIN" "La bústia de veu visual ha d\'estar activada per poder canviar el PIN" 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 fb6be6cf4..987f9de01 100644 --- a/java/com/android/voicemail/impl/res/values-cs/strings.xml +++ b/java/com/android/voicemail/impl/res/values-cs/strings.xml @@ -24,7 +24,6 @@ "Pokročilá nastavení" "Vizuální hlasová schránka" "Další zálohování a úložiště" - " ""Toto je experimentální funkce"", kterou právě testujeme. Funkce vám může smazat hlasové zprávy ze serveru hlasové schránky. Nemůžeme zaručit, že bude podporována i v budoucnu, budeme vám ale vděční za zpětnou vazbu." "Nastavit kód PIN" "Změnit kód PIN" "Pokud chcete kód PIN změnit, musíte mít zapnutou vizuální hlasovou schránku" 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 760c3bc39..70ecb3699 100644 --- a/java/com/android/voicemail/impl/res/values-da/strings.xml +++ b/java/com/android/voicemail/impl/res/values-da/strings.xml @@ -24,7 +24,6 @@ "Avancerede indstillinger" "Visuel telefonsvarer" "Ekstra sikkerhedskopiering og lagerplads" - " ""Dette er en eksperimental funktion,"" som vi tester i øjeblikket. Der slettes måske talebeskeder fra din telefonsvarerserver. Der er ingen garanti for, at denne funktion understøttes fremover. Vi vil dog stadig gerne have feedback om funktionen." "Angiv pinkode" "Skift pinkode" "Visuel telefonsvarer skal være aktiveret, for at du kan skifte pinkode" 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 bc5c70f5e..2746629e9 100644 --- a/java/com/android/voicemail/impl/res/values-de/strings.xml +++ b/java/com/android/voicemail/impl/res/values-de/strings.xml @@ -24,7 +24,6 @@ "Erweiterte Einstellungen" "Visuelle Mailbox" "Zusätzliche Sicherung und mehr Speicher" - " ""Dies ist eine Funktion im Versuchsstadium"", die gerade getestet wird. Hiermit werden möglicherweise Mailboxnachrichten von deinem Mailbox-Server gelöscht. Es wird nicht garantiert, dass diese Funktion auch in Zukunft unterstützt wird. Wir würden uns aber sehr über Feedback dazu freuen." "PIN festlegen" "PIN ändern" "Die visuelle Mailbox muss aktiviert sein, um die PIN zu ändern" 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 a416936b9..e9f9835c6 100644 --- a/java/com/android/voicemail/impl/res/values-el/strings.xml +++ b/java/com/android/voicemail/impl/res/values-el/strings.xml @@ -24,7 +24,6 @@ "Σύνθετες ρυθμίσεις" "Οπτικός αυτόματος τηλεφωνητής" "Επιπλέον αντίγραφα ασφ. και αποθήκευση" - " ""Αυτή είναι μια πειραματική λειτουργία"" που δοκιμάζουμε προς το παρόν. Ενδέχεται να έχει ως αποτέλεσμα τη διαγραφή φωνητικών μηνυμάτων από τον διακομιστή αυτόματου τηλεφωνητή σας. Δεν παρέχονται εγγυήσεις για την υποστήριξη αυτής της λειτουργίας μελλοντικά. Ωστόσο, θα εκτιμούσαμε τα σχόλιά σας για τη λειτουργία αυτή." "Ορισμός PIN" "Αλλαγή κωδικού PIN" "Για αλλαγή του PIN, ενεργοποιήστε τον οπτικό αυτόματο τηλεφωνητή" 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 9b6484b45..ec08faf22 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 @@ -24,7 +24,6 @@ "Advanced settings" "Visual voicemail" "Extra backup and storage" - " ""This is an experimental feature"" that we are currently testing. This will potentially delete voicemail from your voicemail server. There are no guarantees that this feature will be supported in the future. We would love feedback on the feature though." "Set PIN" "Change PIN" "Visual voicemail must be enabled to change PIN" 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 9b6484b45..ec08faf22 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 @@ -24,7 +24,6 @@ "Advanced settings" "Visual voicemail" "Extra backup and storage" - " ""This is an experimental feature"" that we are currently testing. This will potentially delete voicemail from your voicemail server. There are no guarantees that this feature will be supported in the future. We would love feedback on the feature though." "Set PIN" "Change PIN" "Visual voicemail must be enabled to change PIN" 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 9b6484b45..ec08faf22 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 @@ -24,7 +24,6 @@ "Advanced settings" "Visual voicemail" "Extra backup and storage" - " ""This is an experimental feature"" that we are currently testing. This will potentially delete voicemail from your voicemail server. There are no guarantees that this feature will be supported in the future. We would love feedback on the feature though." "Set PIN" "Change PIN" "Visual voicemail must be enabled to change PIN" 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 6ae227a81..fcd9cc7c3 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 @@ -24,7 +24,6 @@ "Configuración avanzada" "Buzón de voz visual" "Copia de seguridad y almacenamiento adicional" - " ""Esta es una función experimental"" que estamos probando. Es posible que se borren los mensajes de voz del servidor correspondiente. No podemos garantizar la compatibilidad de la función en el futuro. Sin embargo, nos encantaría que nos hicieras comentarios acerca de ella." "Establecer PIN" "Cambiar PIN" "El buzón de voz visual se debe activar para cambiar el PIN" 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 bab4e0326..f20ebc5cf 100644 --- a/java/com/android/voicemail/impl/res/values-es/strings.xml +++ b/java/com/android/voicemail/impl/res/values-es/strings.xml @@ -24,7 +24,6 @@ "Configuración avanzada" "Buzón de voz visual" "Copias de seguridad y almacenamiento extra" - " ""Se trata de una función experimental"" que se encuentra actualmente en fase de prueba y que podría servir para eliminar los mensajes de tu servidor de buzón de voz. Aunque no garantizamos que esta función se siga admitiendo en el futuro, nos encantaría conocer tu opinión." "Establecer PIN" "Cambiar PIN" "Para poder cambiar el PIN, el buzón de voz visual debe estar habilitado" 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 02f13145d..dc7f685ba 100644 --- a/java/com/android/voicemail/impl/res/values-et/strings.xml +++ b/java/com/android/voicemail/impl/res/values-et/strings.xml @@ -24,7 +24,6 @@ "Täpsemad seaded" "Visuaalne kõnepost" "Lisavarundus ja -salvestusruum" - " ""See on katseline funktsioon"", mida praegu testime. See võib teie kõnepostisõnumid kõnepostiserverist kustutada. Me ei garanteeri, et seda funktsiooni tulevikus toetatakse. Soovime selle kohta siiski tagasisidet saada." "PIN-koodi määramine" "PIN-koodi muutmine" "PIN-koodi muutmiseks peab olema lubatud visuaalne kõnepost" 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 89afb830c..8a3bd640a 100644 --- a/java/com/android/voicemail/impl/res/values-eu/strings.xml +++ b/java/com/android/voicemail/impl/res/values-eu/strings.xml @@ -24,7 +24,6 @@ "Ezarpen aurreratuak" "Erantzungailu bisuala" "Babeskopiak eta edukia gordetzeko tokia" - " Oraindik probatzen ari garen ""eginbide esperimentala da hau"". Agian erantzungailuaren zerbitzarian gordetako mezuak ezabatuko dira. Ez dugu bermatzen egibide hau etorkizunean erabiltzeko aukera emango dugunik. Halere, bihotzez eskertuko genizuke eginbideari buruzko iritzia." "Ezarri PIN kodea" "Aldatu PIN kodea" "Ikusizko erantzungailuak gaituta egon behar du PIN kodea aldatu ahal izateko" 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 3db711b34..0b5d51333 100644 --- a/java/com/android/voicemail/impl/res/values-fa/strings.xml +++ b/java/com/android/voicemail/impl/res/values-fa/strings.xml @@ -24,7 +24,6 @@ "تنظیمات پیشرفته" "پست صوتی تصویری" "پشتیبان‌گیری و فضای ذخیره‌سازی اضافی" - " ""این یک قابلیت آزمایشی است"" که درحال آزمایش آن هستیم. این قابلیت به‌طور بالقوه پست‌های صوتی را از سرور پست صوتی شما حذف خواهد کرد. ضمانتی برای پشتیبانی از این قابلیت در آینده وجود ندارد. با این حال مشتاقیم درباره آن بازخورد دریافت کنیم." "تنظیم پین" "تغییر پین" "برای تغییر پین، پست صوتی تصویری باید فعال شود" 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 36f5fff5d..c20d3e481 100644 --- a/java/com/android/voicemail/impl/res/values-fi/strings.xml +++ b/java/com/android/voicemail/impl/res/values-fi/strings.xml @@ -24,7 +24,6 @@ "Lisäasetukset" "Visuaalinen vastaaja" "Lisävarmuuskopiointi ja ‑tallennustila" - " ""Tämä on kokeellinen ominaisuus"", jota testaamme parhaillaan. Vastaajaviestejä saatetaan poistaa vastaajapalvelimelta. Ominaisuuden tukemista tulevaisuudessa ei taata. Kuulemme kuitenkin mielellämme mielipiteesi ominaisuudesta." "Aseta PIN-koodi" "Vaihda PIN-koodi" "Ota visuaalinen puhelinvastaaja käyttöön, jotta voit vaihtaa PIN-koodin." 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 2c9a11a93..6bbd1341f 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 @@ -24,7 +24,6 @@ "Paramètres avancés" "Messagerie vocale visuelle" "Espace suppl. de sauvegarde et stockage" - " ""Fonction expérimentale"" en cours de test." "Définir un NIP" "Modifier le NIP" "La messagerie vocale visuelle doit être activée pour que vous puissiez modifier votre NIP" 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 391671c2e..dc21c76d3 100644 --- a/java/com/android/voicemail/impl/res/values-fr/strings.xml +++ b/java/com/android/voicemail/impl/res/values-fr/strings.xml @@ -24,7 +24,6 @@ "Paramètres avancés" "Messagerie vocale visuelle" "Espace suppl. de sauvegarde et stockage" - " ""Il s\'agit d\'une fonctionnalité expérimentale"" en cours de test. Des messages risquent d\'être supprimés de votre serveur de messagerie vocale. Nous ne pouvons pas garantir le maintien de cette fonctionnalité. Toutefois, n\'hésitez pas à nous faire part de vos commentaires." "Définir le code secret" "Modifier le code secret" "Pour que vous puissiez modifier le code secret, la messagerie vocale visuelle doit être activée" 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 70b949e6c..81f6e679a 100644 --- a/java/com/android/voicemail/impl/res/values-gl/strings.xml +++ b/java/com/android/voicemail/impl/res/values-gl/strings.xml @@ -24,7 +24,6 @@ "Configuración avanzada" "Correo de voz visual" "Copia de seguranza e almacenamento extra" - " ""Esta función está en modo de proba"", e é posible que elimine correos de voz do teu servidor de correo de voz. Non podemos garantir a súa continuidade no futuro. De todos modos, encantaríanos que nos deses a túa opinión." "Establecer PIN" "Cambiar PIN" "Para poder cambiar o PIN, o correo de voz visual ten que estar activado" 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 f9187a7d3..3e8948d19 100644 --- a/java/com/android/voicemail/impl/res/values-gu/strings.xml +++ b/java/com/android/voicemail/impl/res/values-gu/strings.xml @@ -24,7 +24,6 @@ "વિગતવાર સેટિંગ્સ" "વિઝ્યુઅલ વૉઇસમેઇલ" "અતિરિક્ત બેકઅપ અને સ્ટોરેજ" - " ""આ એક પ્રાયોગિક સુવિધા છે"" અમે હાલમાં પરીક્ષણ કરી રહ્યાં છીએ. આ તમારા વૉઇસમેઇલ સર્વરમાંથી સંભવિત રૂપે વૉઇસમેઇલ કાઢી નાખશે. ભવિષ્યમાં આ સુવિધાનું સમર્થન કરવાની કોઇ બાંંયધરી નથી. જોકે અમને આ સુવિધા પર પ્રતિસાદ ગમશે." "PIN સેટ કરો" "PIN બદલો" "PIN બદલવા માટે વિઝ્યુઅલ વૉઇસમેઇલ સક્ષમ હોય તે આવશ્યક છે" 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 488fba2a9..8daa3e3d7 100644 --- a/java/com/android/voicemail/impl/res/values-hi/strings.xml +++ b/java/com/android/voicemail/impl/res/values-hi/strings.xml @@ -24,7 +24,6 @@ "उन्नत सेटिंग" "विज़ुअल वॉइसमेल" "अतिरिक्त बैकअप और जगह" - " ""यह सुविधा एक तरह का प्रयोग है"" जिसका हम अभी परीक्षण कर रहे हैं. हो सकता है कि यह आपके वॉइसमेल सर्वर से वॉइसमेल हटा दे. भविष्य में यह सुविधा दी जाएगी या नहीं इसकी कोई गारंटी नहीं है. फिर भी सुविधा पर आपका फ़ीडबैक हमें अच्छा लगेगा." "पिन सेट करें" "पिन बदलें" "पिन बदलने के लिए विज़ुअल वॉइसमेल ज़रूर सक्षम होना चाहिए" 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 7d6695653..960909571 100644 --- a/java/com/android/voicemail/impl/res/values-hr/strings.xml +++ b/java/com/android/voicemail/impl/res/values-hr/strings.xml @@ -24,7 +24,6 @@ "Napredne postavke" "Vizualna govorna pošta" "Dodatno sigurnosno kopiranje i pohrana" - " ""Ovo je eksperimentalna značajka"" koju trenutačno testiramo. To će možda izbrisati poruke govorne pošte s vašeg poslužitelja govorne pošte. Nije sigurno da ćemo ovu značajku podržati u budućnosti. Međutim, voljeli bismo dobiti povratne informacije o njoj." "Postavljanje PIN-a" "Promjena PIN-a" "Za promjenu PIN-a potrebno je omogućiti vizualnu govornu poštu" 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 fae3ef4c7..ce18af799 100644 --- a/java/com/android/voicemail/impl/res/values-hu/strings.xml +++ b/java/com/android/voicemail/impl/res/values-hu/strings.xml @@ -24,7 +24,6 @@ "Speciális beállítások" "Vizuális hangpostaüzenet" "Extra tárhely és biztonsági mentés" - " ""Ez egy kísérleti funkció"", amelyet jelenleg tesztelünk. Előfordulhat, hogy letörli az Ön hangüzeneteit a hangpostaszerverről. Nem garantáljuk, hogy a funkció a jövőben is megmarad, de nagy örömmel vennénk, ha megírná róla a véleményét." "PIN-kód beállítása" "PIN-kód módosítása" "A PIN-kód módosításához engedélyezni kell a vizuális hangpostát." 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 e4126f877..eaa987aa4 100644 --- a/java/com/android/voicemail/impl/res/values-hy/strings.xml +++ b/java/com/android/voicemail/impl/res/values-hy/strings.xml @@ -24,7 +24,6 @@ "Ընդլայնված կարգավորումներ" "Տեսողական ձայնային փոստ" "Լրացուցիչ տարածք և պահուստավորում" - " ""Սա փորձնական գործառույթ է,"" որը գտնվում է փորձարկման փուլում: Այս ընթացքում ձայնային հաղորդագրությունները ձեր ձայնային փոստի սերվերից կարող են ջնջվել: Ոչ մի երաշխիք չկա, որ այն հետագայում կաջակցվի: Այդուհանդերձ, կցանկանայինք ձեր կարծիքն իմանալ այս գործառույթի մասին:" "Սահմանեք PIN կոդ" "Փոխեք PIN կոդը" "PIN կոդը փոխելու համար տեսողական ձայնային փոստը պետք է միացված լինի" 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 d47bd9b9b..6f7e6377e 100644 --- a/java/com/android/voicemail/impl/res/values-in/strings.xml +++ b/java/com/android/voicemail/impl/res/values-in/strings.xml @@ -24,7 +24,6 @@ "Setelan Lanjutan" "Pesan Suara Visual" "Penyimpanan dan backup ekstra" - " ""Ini adalah fitur eksperimental"" yang sedang kami uji. Fitur ini berpotensi menghapus pesan suara dari server pesan suara Anda. Tidak ada jaminan bahwa fitur ini akan didukung di masa mendatang. Kami akan menerima masukan terkait fitur ini dengan senang hati." "Setel PIN" "Ubah PIN" "Pesan suara visual harus diaktifkan untuk mengubah PIN" 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 c2019a3f5..5e00487af 100644 --- a/java/com/android/voicemail/impl/res/values-is/strings.xml +++ b/java/com/android/voicemail/impl/res/values-is/strings.xml @@ -24,7 +24,6 @@ "Ítarlegar stillingar" "Myndrænt talhólf" "Viðbótaröryggisafritun og samstilling" - " ""Þessi eiginleiki er í tilraunaútgáfu"" sem við erum að prófa að svo stöddu. Þetta mun mögulega eyða talhólfsskilaboðum af vefþjóni talhólfsins. Engin trygging er fyrir því að þessi eiginleiki verði studdur í framtíðinni. Við kunnum virkilega að meta allar ábendingar varðandi þennan eiginleika." "Stilla PIN-númer" "Breyta PIN-númeri" "Kveikt þarf að vera á myndrænu talhólfi til að breyta PIN-númeri" 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 3aeaca901..2c37ba281 100644 --- a/java/com/android/voicemail/impl/res/values-it/strings.xml +++ b/java/com/android/voicemail/impl/res/values-it/strings.xml @@ -24,7 +24,6 @@ "Impostazioni avanzate" "Leggi la segreteria" "Archiviazione supplementare e backup" - " ""Questa è una funzionalità sperimentale"" che si trova al momento in fase di test. È possibile che i messaggi vocali vengano eliminati dal server della segreteria. Non ci sono garanzie che la funzionalità continui a essere supportata in futuro, ma ci piacerebbe ricevere il tuo feedback." "Imposta PIN" "Cambia PIN" "La lettura delle segreteria deve essere attivata per cambiare il PIN" 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 98d31bc59..cdf58dd64 100644 --- a/java/com/android/voicemail/impl/res/values-iw/strings.xml +++ b/java/com/android/voicemail/impl/res/values-iw/strings.xml @@ -24,7 +24,6 @@ "הגדרות מתקדמות" "דואר קולי ויזואלי" "גיבוי ופינוי מקום" - " ""זוהי תכונה ניסיונית"" שאנחנו בודקים כרגע. היא עלולה למחוק הודעות קוליות מתא הדואר הקולי שלך בשרת. אנחנו לא מתחייבים שהתכונה תהיה זמינה בעתיד, אך נשמח לקבל עליה משוב." "הגדרת קוד גישה" "שינוי קוד הגישה" "צריך להפעיל את הדואר הקולי הוויזואלי כדי לשנות את קוד הגישה" 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 90bce09fb..e35359f01 100644 --- a/java/com/android/voicemail/impl/res/values-ja/strings.xml +++ b/java/com/android/voicemail/impl/res/values-ja/strings.xml @@ -24,7 +24,6 @@ "詳細設定" "ビジュアル ボイスメール" "追加のバックアップと保存容量" - " ""これは現在テスト中の試験運用機能""で、ボイスメール サーバーからボイスメールを削除することができます。今後この機能が正式にサポートされる保証はありませんが、フィードバックをお寄せいただければ幸いです。" "PIN の設定" "PIN の変更" "PIN を変更するには、ビジュアル ボイスメールを有効にする必要があります" 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 4e1413287..7eb792fd0 100644 --- a/java/com/android/voicemail/impl/res/values-ka/strings.xml +++ b/java/com/android/voicemail/impl/res/values-ka/strings.xml @@ -24,7 +24,6 @@ "გაფართოებული პარამეტრები" "ვიზუალური ხმოვანი ფოსტა" "დამატებითი სარეზ. ასლები და მეხსიერება" - " ""ეს არის ექსპერიმენტული ფუნქცია, რომელსაც"" ამჟამად ტესტირებას ვუტარებთ. სავარაუდოდ, ეს წაშლის ხმოვან შეტყობინებებს თქვენი ხმოვანი ფოსტის სერვერიდან. გარანტია, რომ ეს ფუნქცია მომავალში მხარდაჭერილი იქნება, არ არსებობს. თუმცა ამ ფუნქციის შესახებ გამოხმაურებას ინტერესით გავეცნობოდით." "PIN-კოდის დაყენება" "PIN-კოდის შეცვლა" "PIN-კოდის შესაცვლელად ჩართული უნდა იყოს ვიზუალური ხმოვანი ფოსტა" 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 36ba090ea..a03171d01 100644 --- a/java/com/android/voicemail/impl/res/values-kk/strings.xml +++ b/java/com/android/voicemail/impl/res/values-kk/strings.xml @@ -24,7 +24,6 @@ "Қосымша параметрлер" "Визуалды дауыстық пошта" "Қосымша сақтық көшірме жасау және сақтау" - " ""Бұл — қазір тексеріліп жатқан, тәжірибелік мүмкіндік"". Бұл дауыстық хабарларды дауыстық хабар серверінен өшіруі мүмкін. Осы мүмкіндікке алдағы уақытта қолдау көрсетілетініне ешқандай кепілдік жоқ. Сонда да осы мүмкіндікке қатысты пікір алғымыз келеді." "PIN кодын тағайындау" "PIN кодын өзгерту" "PIN кодын өзгерту үшін визуалды дауыс хабарын қосу қажет" 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 f97ff3e5e..3d55d00bb 100644 --- a/java/com/android/voicemail/impl/res/values-km/strings.xml +++ b/java/com/android/voicemail/impl/res/values-km/strings.xml @@ -24,7 +24,6 @@ "ការ​កំណត់​កម្រិត​ខ្ពស់" "សារជាសំឡេងអាចមើលឃើញ" "ទំហំ​ផ្ទុក និង​ការ​បម្រុងទុក​បន្ថែម" - " ""នេះ​​គឺ​ជា​មុខងារ​សាកល្បង"" បច្ចុប្បន្ន យើង​កំពុង​ធ្វើ​ការ​សាកល្បង។ វា​អាច​នឹង​លុប​សារ​ជា​សំឡេង​ពី​ម៉ាស៊ីន​មេ​សារ​ជា​សំឡេង​របស់​អ្នក។ មិន​មាន​ការ​ធានា​ធ្វើ​ឲ្យ​មុខងារ​នេះ​ដំណើរការ​នៅ​ថ្ងៃ​ក្រោយ​ទេ។ យើង​ចង់​ដឹង​មតិ​ស្ថាបនា​អំពី​មុខងារនេះ​ផង​ដែរ។" "កំណត់​កូដ PIN" "ផ្លាស់ប្ដូរ​កូដ PIN" "សារ​​ជា​សំឡេង​ដែល​មើល​ឃើញ​ត្រូវតែ​បើកដំណើរការ ដើម្បី​ផ្លាស់ប្ដូរ PIN" 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 6f8e21f88..379e656ce 100644 --- a/java/com/android/voicemail/impl/res/values-kn/strings.xml +++ b/java/com/android/voicemail/impl/res/values-kn/strings.xml @@ -24,7 +24,6 @@ "ಸುಧಾರಿತ ಸೆಟ್ಟಿಂಗ್‌ಗಳು" "ದೃಶ್ಯ ಧ್ವನಿಮೇಲ್" "ಹೆಚ್ಚುವರಿ ಬ್ಯಾಕಪ್ ಮತ್ತು ಸಂಗ್ರಹಣೆ" - " ""ಇದು ಪ್ರಾಯೋಗಿಕ ವೈಶಿಷ್ಟ್ಯವಾಗಿದೆ""ನಾವು ಪ್ರಸ್ತುತ ಪರೀಕ್ಷಿಸುತ್ತಿದ್ದೇವೆ. ಇದು ನಿಮ್ಮ ಧ್ವನಿಮೇಲ್ ಸರ್ವರ್‌ನಿಂದ ಧ್ವನಿಮೇಲ್‌ಗಳನ್ನು ಸಂಭಾವ್ಯವಾಗಿ ಅಳಿಸುತ್ತದೆ. ಭವಿಷ್ಯದಲ್ಲಿ ಈ ವೈಶಿಷ್ಟ್ಯವನ್ನು ಬೆಂಬಲಿಸುವ ಯಾವುದೇ ಖಾತ್ರಿ ಇಲ್ಲ. ಆದರೂ ನಿಮ್ಮ ಪ್ರತಿಕ್ರಿಯೆಗೆ ಸ್ವಾಗತ." "ಪಿನ್ ಹೊಂದಿಸಿ" "ಪಿನ್‌ ಬದಲಾಯಿಸಿ" "ಪಿನ್ ಬದಲಾಯಿಸಲು ದೃಶ್ಯ ಧ್ವನಿಮೇಲ್ ಸಕ್ರಿಯಗೊಳಿಸಬೇಕು" 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 f18d1d711..513a67546 100644 --- a/java/com/android/voicemail/impl/res/values-ko/strings.xml +++ b/java/com/android/voicemail/impl/res/values-ko/strings.xml @@ -24,7 +24,6 @@ "고급 설정" "시각적 음성사서함" "추가 백업 및 저장용량" - " 현재 테스트 중인 ""실험적 기능입니다"". 이 기능으로 인해 음성사서함 서버에서 메시지가 삭제될 수도 있습니다. 또한 Google에서는 추후 이 기능이 지원된다고 보장할 수 없습니다. 하지만 이 기능에 관해 의견을 주시면 감사하겠습니다." "PIN 설정" "PIN 변경" "PIN을 변경하려면 시각적 음성사서함이 사용 설정되어 있어야 합니다." 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 f5219a91c..12b7f18c5 100644 --- a/java/com/android/voicemail/impl/res/values-ky/strings.xml +++ b/java/com/android/voicemail/impl/res/values-ky/strings.xml @@ -24,7 +24,6 @@ "Өркүндөтүлгөн жөндөөлөр" "Визуалдык үн почтасы" "Кошумча камдык көчүрмөнү сактоо жана сактагыч" - " ""Бул, сыноодон өтүп жаткан"" эксперименталдык функция. Үн каттарыңыз серверден өчүрүлүп калышы мүмкүн. Бул функциянын кийин да колдонулаарына кепилдик бере албайбыз бирок, ал жөнүндө пикириңизди билгибиз келет." "PIN код коюу" "PIN кодду өзгөртүү" "PIN кодду өзгөртүү үчүн визуладык үн почтасын иштетүү керек" 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 212b12fd2..f4f45e592 100644 --- a/java/com/android/voicemail/impl/res/values-lo/strings.xml +++ b/java/com/android/voicemail/impl/res/values-lo/strings.xml @@ -24,7 +24,6 @@ "ການຕັ້ງຄ່າຂັ້ນສູງ" "ຂໍ້​ຄວາມ​ສຽງສະເໝືອນ" "ການສຳຮອງ ແລະ ບ່ອນຈັດເກັບຂໍ້ມູນພິເສດ" - " ""ນີ້ເປັນຄຸນສົມບັດທີ່ຢູ່ໃນຂັ້ນຕອນທົດລອງຢູ່"" ພວກເຮົາກຳລັງທົດສອບ. ມັນອາດລຶບຂໍ້ຄວາມສຽງອອກຈາກເຊີບເວີຂໍ້ຄວາມສຽງຂອງທ່ານໄດ້. ຈະບໍ່ມີການຮັບປະກັນການຊ່ວຍເຫຼືອຄຸນສົມບັດນີ້ໃນອະນາຄົດ. ຢ່າງໃດກໍຕາມພວກເຮົາຢາກຟັງຄຳຄິດເຫັນທີ່ມີຕໍ່ຄຸນສົມບັດດັ່ງກ່າວຈາກທ່ານ." "ຕັ້ງລະຫັດ PIN" "​ປ່ຽນ​ລະຫັດ PIN" "ຈະຕ້ອງເປີດໃຊ້ຂໍ້ຄວາມສຽງສະເໝືອນເພື່ອປ່ຽນ PIN" 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 d4d9c4dc3..59a15f452 100644 --- a/java/com/android/voicemail/impl/res/values-lt/strings.xml +++ b/java/com/android/voicemail/impl/res/values-lt/strings.xml @@ -24,7 +24,6 @@ "Išplėstiniai nustatymai" "Vaizdinis balso paštas" "Papild. saug. vt. ir ats. kop. kūr. f." - " ""Tai yra eksperimentinė funkcija"", kurią šiuo metu išbandome. Ją naudojant iš balso pašto serverio bus ištrinami balso pašto pranešimai. Negarantuojame, kad ateityje ši funkcija bus palaikoma, tačiau norėtume gauti atsiliepimų apie ją." "PIN kodo nustatymas" "PIN kodo keitimas" "Vaizdinis balso paštas turi būti įgalintas, kad būtų galima pakeisti PIN kodą" 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 1f758c467..0b8b2f92a 100644 --- a/java/com/android/voicemail/impl/res/values-lv/strings.xml +++ b/java/com/android/voicemail/impl/res/values-lv/strings.xml @@ -24,7 +24,6 @@ "Papildu iestatījumi" "Vizuālais balss pasts" "Papildu dublēšana un krātuve" - " ""Šī ir eksperimentāla funkcija"", ko mēs pašlaik testējam. Pastāv iespēja, ka no jūsu balss pasta servera tiks izdzēsti balss pasta ziņojumi. Mēs negarantējam šīs funkcijas turpmāku atbalstu, tomēr priecāsimies saņemt atsauksmes par to." "PIN iestatīšana" "PIN mainīšana" "Lai varētu mainīt PIN, ir jābūt iespējotam vizuālajam balss pastam." 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 39b8beefc..90c2f6cb2 100644 --- a/java/com/android/voicemail/impl/res/values-mk/strings.xml +++ b/java/com/android/voicemail/impl/res/values-mk/strings.xml @@ -24,7 +24,6 @@ "Напредни поставки" "Визуелна говорна пошта" "Дополнителен бекап и склад" - " ""Ова е експериментална функција"" што моментално ја тестираме. Постои можност да брише говорни пораки од вашиот сервер за говорна пошта. Нема гаранција дека функцијава ќе се поддржува во иднина. Сепак, многу би ни значеле повратните информации за функцијата." "Поставете PIN" "Променете PIN" "За променување на PIN-кодот, мора да се овозможи визуелна говорна пошта" 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 c30ebbcfe..d7fd31f1e 100644 --- a/java/com/android/voicemail/impl/res/values-ml/strings.xml +++ b/java/com/android/voicemail/impl/res/values-ml/strings.xml @@ -24,7 +24,6 @@ "വിപുലമായ ക്രമീകരണം" "വിഷ്വൽ വോയ്‌സ്‌മെയിൽ" "അധിക ബായ്‌ക്കപ്പും സ്‌റ്റോറേജും" - " ഇത് നിലവിൽ ഞങ്ങൾ പരീക്ഷിക്കുന്ന ""ഒരു പരീക്ഷണാത്മക ഫീച്ചറാണ്"". ഇത് നിങ്ങളുടെ വോയ്‌സ്‌മെയിൽ സെർവറിൽ നിന്ന് വോയ്‌സ്‌മെയിലുകൾ ഇല്ലാതാക്കാൻ സാധ്യതയുണ്ട്. ഈ ഫീച്ചർ ഭാവിയിൽ ഉപയോഗിക്കാനാവുമെന്ന് ഉറപ്പൊന്നുമില്ല. എങ്കിലും ഈ ഫീച്ചറിനെക്കുറിച്ചുള്ള ഫീഡ്‌ബാക്ക് അറിയാൻ ഞങ്ങൾ താൽപ്പര്യപ്പെടുന്നു." "പിൻ സജ്ജമാക്കുക" "പിൻ മാറ്റുക" "പിൻ മാറ്റുന്നതിന് വിഷ്വൽ വോയ്‌സ്‌മെയിൽ പ്രവർത്തനക്ഷമമാക്കേണ്ടതുണ്ട്" 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 a559d1900..5f726342f 100644 --- a/java/com/android/voicemail/impl/res/values-mn/strings.xml +++ b/java/com/android/voicemail/impl/res/values-mn/strings.xml @@ -24,7 +24,6 @@ "Нарийвчилсан тохиргоо" "Уншиж болохуйц дуут шуудан" "Нэмэлт нөөцлөлт болон хадгалах сан" - " Энэ бол бидний одоо шалгаж буй ""туршилтын функц"". Энэ таны дуут шуудангийн серверээс дуут шуудангуудыг устгах магадлалтай. Цаашид энэ функцийг дэмжих баталгаа байхгүй. Гэхдээ энэ функцийн талаар санал хүсэлт илгээвэл талархах болно." "PIN тохируулах" "PIN өөрчлөх" "Харагдах дуут шуудан PIN-г өөрчлөх боломжтой байх ёстой" 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 56e864b81..e8c546ce6 100644 --- a/java/com/android/voicemail/impl/res/values-mr/strings.xml +++ b/java/com/android/voicemail/impl/res/values-mr/strings.xml @@ -24,7 +24,6 @@ "प्रगत सेटिंग्ज" "दृश्‍यमान व्हॉइसमेल" "अतिरिक्त बॅक अप आणि संचय" - " ""हे प्रायोगिक वैशिष्ट्य आहे"" आम्ही सध्‍या चाचणी घेत आहोत. हे आपल्या व्हॉइसमेल सर्व्हर मधून संभाव्यपणे व्हॉइसमेल हटवेल. भविष्‍यात या वैशिष्‍ट्यास समर्थन देण्याची हमी नाही. तरीही आम्ही वैशिष्‍ट्यावरील अभिप्राय घेऊ इच्छितो." "पिन सेट करा" "पिन बदला" "पिन बदलण्‍यासाठी व्हिज्युअल व्हॉइसमेल सक्षम करणे आवश्‍यक आहे" 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 ea9b38f08..4468d49d7 100644 --- a/java/com/android/voicemail/impl/res/values-ms/strings.xml +++ b/java/com/android/voicemail/impl/res/values-ms/strings.xml @@ -24,7 +24,6 @@ "Tetapan Terperinci" "Mel Suara Visual" "Sandaran dan storan tambahan" - " ""Ini ialah ciri percubaan"" yang sedang kami uji. Ciri ini berupaya memadamkan mel suara daripada pelayan mel suara anda. Tiada jaminan bahawa ciri ini akan disokong pada masa hadapan. Namun begitu, kami berharap untuk menerima maklum balas tentang ciri ini." "Tetapkan PIN" "Tukar PIN" "Mel suara visual mesti didayakan untuk menukar PIN" 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 6c789275a..41e88351d 100644 --- a/java/com/android/voicemail/impl/res/values-my/strings.xml +++ b/java/com/android/voicemail/impl/res/values-my/strings.xml @@ -24,7 +24,6 @@ "အဆင့်မြင့် ဆက်တင်များ" "စာသားမှတ်တမ်းပါ အသံမေးလ်" "အပိုဆောင်း မိတ္တူနှင့် သိုလှောင်မှု" - " ဤသည်မှာ ""စမ်းသပ်ဆဲဝန်ဆောင်မှုတစ်ခု"" ဖြစ်ပါသည်။ ၎င်းက သင်၏အသံမေးလ်ဆာဗာမှ အသံမေးလ်များကို ဖျက်ပစ်နိုင်ပါသည်။ ဤဝန်ဆောင်မှုကို အနာဂတ်တွင် ဆက်လက်ရရှိနိုင်မည်ဟု အာမခံထားခြင်း မရှိသော်လည်း ၎င်းနှင့်ပတ်သက်သည့် အကြံပြုချက်များကို ရရှိလိုပါသည်။" "ပင်နံပါတ် သတ်မှတ်ပါ" "ပင်နံပါတ် ပြောင်းပါ" "ပင်နံပါတ်ပြောင်းရန် စာသားမှတ်တမ်းပါ အသံမေးလ်ကို ဖွင့်ထားရပါမည်" 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 93e9e2a2c..afbdd3bb8 100644 --- a/java/com/android/voicemail/impl/res/values-nb/strings.xml +++ b/java/com/android/voicemail/impl/res/values-nb/strings.xml @@ -24,7 +24,6 @@ "Avanserte innstillinger" "Visuell talepostkasse" "Ekstra sikkerhetskopi og lagring" - " ""Denne funksjonen er fortsatt under utforskning"", og det kan føre til at noen av talepostmelingene dine slettes. Vi kan dessverre ikke love at denne funksjonen støttes i fremtiden, men vi vil gjerne høre om hva du mener om den." "Angi PIN-kode" "Endre PIN-koden" "Du må slå på visuell talepost for å endre PIN-koden" 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 d729c2323..a186535b5 100644 --- a/java/com/android/voicemail/impl/res/values-ne/strings.xml +++ b/java/com/android/voicemail/impl/res/values-ne/strings.xml @@ -24,7 +24,6 @@ "उन्नत सेटिङहरू" "भिजुअल भ्वाइस मेल" "अतिरिक्त ब्याकअप र भण्डारण" - " ""यो एउटा प्रयोगात्मक विशेषता हो"" हामी अहिले परीक्षण गर्दैछौं। यसले सम्भवत: तपाईंको भ्वाइस मेल सर्भरका भ्वाइस मेलहरूलाई मेट्ने छ। भविष्यमा यो विशेषतालाई समर्थन गरिने कुराको ग्यारेन्टी छैन। तथापि हामी यो विशेषताका सम्बन्धमा प्रतिक्रिया आऊन् भन्ने चाहन्छौं।" "PIN सेट गर्नुहोस्" "PIN परिवर्तन गर्नुहोस्" "PIN परिवर्तन गर्न अनिवार्य रूपले भिजुअल भ्वाइस मेललाई सक्षम पारिनुपर्छ" 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 7ae9f4e0e..ed66ab303 100644 --- a/java/com/android/voicemail/impl/res/values-nl/strings.xml +++ b/java/com/android/voicemail/impl/res/values-nl/strings.xml @@ -24,7 +24,6 @@ "Geavanceerde instellingen" "Visuele voicemail" "Extra back-up en opslag" - " ""Dit is een experimentele functie"" die wordt getest. Mogelijk worden hierdoor voicemails van de voicemailserver verwijderd. Er is geen garantie dat we deze functie in de toekomst blijven ondersteunen. We zijn wel heel benieuwd naar jullie feedback over de functie." "Pincode instellen" "Pincode wijzigen" "Visuele voicemail moet zijn ingeschakeld om de pincode te wijzigen" 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 93e9e2a2c..afbdd3bb8 100644 --- a/java/com/android/voicemail/impl/res/values-no/strings.xml +++ b/java/com/android/voicemail/impl/res/values-no/strings.xml @@ -24,7 +24,6 @@ "Avanserte innstillinger" "Visuell talepostkasse" "Ekstra sikkerhetskopi og lagring" - " ""Denne funksjonen er fortsatt under utforskning"", og det kan føre til at noen av talepostmelingene dine slettes. Vi kan dessverre ikke love at denne funksjonen støttes i fremtiden, men vi vil gjerne høre om hva du mener om den." "Angi PIN-kode" "Endre PIN-koden" "Du må slå på visuell talepost for å endre PIN-koden" 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 f3551cc6e..ec68867c6 100644 --- a/java/com/android/voicemail/impl/res/values-pa/strings.xml +++ b/java/com/android/voicemail/impl/res/values-pa/strings.xml @@ -24,7 +24,6 @@ "ਉੱਨਤ ਸੈਟਿੰਗਾਂ" "ਦ੍ਰਿਸ਼ਟਾਂਤਕ ਵੌਇਸਮੇਲ" "ਵਾਧੂ ਬੈਕਅੱਪ ਅਤੇ ਸਟੋਰੇਜ" - " ""ਇਹ ਇੱਕ ਪ੍ਰਯੋਗਾਤਮਕ ਵਿਸ਼ੇਸ਼ਤਾ ਹੈ"" ਜਿਸਦੀ ਅਸੀਂ ਇਸ ਵੇਲੇ ਜਾਂਚ ਕਰ ਰਹੇ ਹਾਂ। ਇਹ ਸੰਭਾਵੀ ਤੌਰ \'ਤੇ ਤੁਹਾਡੇ ਵੌਇਸਮੇਲ ਸਰਵਰ ਤੋਂ ਵੌਇਸਮੇਲਾਂ ਨੂੰ ਮਿਟਾ ਦੇਵੇਗੀ। ਭਵਿੱਖ ਵਿੱਚ ਇਸ ਵਿਸ਼ੇਸ਼ਤਾ ਦਾ ਸਮਰਥਨ ਕਰਨ ਦੀਆਂ ਕੋਈ ਗਾਰੰਟੀਆਂ ਨਹੀਂ ਹਨ। ਅਸੀਂ ਹਾਲਾਂਕਿ ਵਿਸ਼ੇਸ਼ਤਾ \'ਤੇ ਪ੍ਰਤੀਕਰਮ ਨੂੰ ਪਸੰਦ ਕਰਾਂਗੇ।" "PIN ਸੈੱਟ ਕਰੋ" "PIN ਬਦਲੋ" "ਦ੍ਰਿਸ਼ਟਾਂਤਕ ਵੌਇਸਮੇਲ ਨੂੰ PIN ਬਦਲਣ ਲਈ ਯੋਗ ਬਣਾਇਆ ਜਾਣਾ ਲਾਜ਼ਮੀ ਹੈ" 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 83003df97..25b891475 100644 --- a/java/com/android/voicemail/impl/res/values-pl/strings.xml +++ b/java/com/android/voicemail/impl/res/values-pl/strings.xml @@ -24,7 +24,6 @@ "Ustawienia zaawansowane" "Wizualna poczta głosowa" "Dodatkowe miejsce i kopia zapasowa" - " ""To jest funkcja eksperymentalna"", którą obecnie testujemy. Może ona usunąć wiadomości głosowe z Twojego serwera poczty głosowej. Nie gwarantujemy, że ta funkcja będzie w przyszłości obsługiwana. Chętnie jednak dowiemy się, co o niej sądzisz." "Ustaw kod PIN" "Zmień kod PIN" "Aby można było zmienić kod PIN, wizualna poczta głosowa musi być włączona" 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 a0eee43ae..c93402e36 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 @@ -24,7 +24,6 @@ "Configurações avançadas" "Correio de voz visual" "Armazenamento extra e backup" - " ""Este é um recurso experimental"" que estamos testando. Talvez ele exclua os correios de voz do seu servidor. Não há garantias de suporte no futuro, mas gostaríamos de receber seu feedback." "Definir PIN" "Alterar PIN" "O correio de voz visual precisa ser ativado para alterar o PIN" 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 2be877e23..00ed0331b 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 @@ -24,7 +24,6 @@ "Definições avançadas" "Mensagem de correio de voz visual" "Cópia de segurança e armazenamento extra" - " ""É uma funcionalidade experimental"" que estamos a testar. Poderá eliminar mensagens de correio de voz do servidor de correio de voz. Não há garantias de suporte para esta funcionalidade. Gostaríamos de receber comentários sobre a mesma." "Definir PIN" "Alterar PIN" "A mensagem de correio de voz visual tem de estar ativada para poder alterar o PIN" 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 a0eee43ae..c93402e36 100644 --- a/java/com/android/voicemail/impl/res/values-pt/strings.xml +++ b/java/com/android/voicemail/impl/res/values-pt/strings.xml @@ -24,7 +24,6 @@ "Configurações avançadas" "Correio de voz visual" "Armazenamento extra e backup" - " ""Este é um recurso experimental"" que estamos testando. Talvez ele exclua os correios de voz do seu servidor. Não há garantias de suporte no futuro, mas gostaríamos de receber seu feedback." "Definir PIN" "Alterar PIN" "O correio de voz visual precisa ser ativado para alterar o PIN" 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 1c98d5a20..9099065c1 100644 --- a/java/com/android/voicemail/impl/res/values-ro/strings.xml +++ b/java/com/android/voicemail/impl/res/values-ro/strings.xml @@ -24,7 +24,6 @@ "Setări avansate" "Mesagerie vocală vizuală" "Backup și spațiu de stocare suplimentare" - " ""Aceasta este o funcție experimentală"" în curs de testare. E posibil ca mesajele vocale de pe serverul de mesagerie vocală să fie șterse. Nu se poate garanta acceptarea acestei funcții pe viitor, însă feedbackul dvs. e bine-venit." "Setați codul PIN" "Schimbați codul PIN" "Mesageria vocală vizuală trebuie activată pentru a schimba codul PIN." 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 f899f149e..322b41bfb 100644 --- a/java/com/android/voicemail/impl/res/values-ru/strings.xml +++ b/java/com/android/voicemail/impl/res/values-ru/strings.xml @@ -24,7 +24,6 @@ "Расширенные настройки" "Визуальная голосовая почта" "Дополнительное место для хранения и резервного копирования" - " ""Это экспериментальная функция"", которая сейчас проходит тестирование. Возможно, ваши голосовые сообщения будут удалены с вашего сервера. Поддержка этой функции в дальнейшем не гарантируется. Мы бы хотели узнать ваше мнение о ней." "Установка PIN-кода" "Изменение PIN-кода" "Чтобы изменить PIN-код, включите визуальную голосовую почту" 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 b5dc7826c..8ad6f87e6 100644 --- a/java/com/android/voicemail/impl/res/values-si/strings.xml +++ b/java/com/android/voicemail/impl/res/values-si/strings.xml @@ -24,7 +24,6 @@ "උසස් සැකසීම්" "දෘශ්‍ය හඬ තැපෑල" "අතිරේක උපස්ථය සහ ගබඩාව" - " ""මෙය අත්හදා බැලීමේ විශේෂාංගයකි"" අපි දැන් පරීක්ෂා කරමින් සිටිමු. මෙය විභව්‍යව හඬ තැපැල් ඔබේ සේවාදායකයෙන් මකනු ඇත. මෙම විශේෂාංගය අනාගතයේදී සහාය දැක්වීම ගැන ඇපවීම් නැත. එසේ වුවත් අපි විශේෂාංගය ගැන ප්‍රතිපෝෂණවලට ආදරය කරන්නෙමු." "PIN අංකය සකසන්න" "PIN අංකය වෙනස් කරන්න" "PIN අංකය වෙනස් කිරීමට දෘශ්‍ය හඬ තැපෑල සබල කළ යුතුය" 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 5a81a1bd4..80252d454 100644 --- a/java/com/android/voicemail/impl/res/values-sk/strings.xml +++ b/java/com/android/voicemail/impl/res/values-sk/strings.xml @@ -24,7 +24,6 @@ "Rozšírené nastavenia" "Vizuálna hlasová schránka" "Ďalšie zálohovanie a úložisko" - " ""Toto je experimentálna funkcia"", ktorú práve testujeme. Táto funkcia vám môže odstrániť hlasové správy zo servera hlasovej schránky. Nemôžeme zaručiť, že bude podporovaná aj v budúcnosti, no budeme vám vďační za poskytnutie spätnej väzby." "Nastavenie kódu PIN" "Zmena kódu PIN" "PIN možno zmeniť až po povolení vizuálnej hlasovej schránky" 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 ce0f40ec8..b634d156a 100644 --- a/java/com/android/voicemail/impl/res/values-sl/strings.xml +++ b/java/com/android/voicemail/impl/res/values-sl/strings.xml @@ -24,7 +24,6 @@ "Dodatne nastavitve" "Vizualno sporočilo v odzivniku" "Dodatno varnostno kopiranje in shramba" - " ""To je poskusna funkcija"", za katero trenutno izvajamo preskuse. Sporočila v odzivniku bodo morda izbrisana iz strežnika za sporočila v odzivniku. Ni mogoče jamčiti, da bo ta funkcija podprta tudi v prihodnje. Kljub temu bomo veseli vaših povratnih informacij o funkciji." "Nastavitev kode PIN" "Sprememba kode PIN" "Če želite spremeniti kodo PIN, morajo biti vizualna sporočila v odzivniku omogočena" 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 472e60c0d..59db0fd74 100644 --- a/java/com/android/voicemail/impl/res/values-sq/strings.xml +++ b/java/com/android/voicemail/impl/res/values-sq/strings.xml @@ -24,7 +24,6 @@ "Cilësimet e përparuara" "Posta zanore vizuale" "Rezervimi dhe hapësira ruajtëse shtesë" - " ""Ky është një funksion eksperimental"" që po e testojmë aktualisht. Kjo mund të fshijë posta zanore nga serveri i postës zanore. Nuk ka garanci për mbështetjen e këtij funksioni në të ardhmen. Megjithatë do të na pëlqente të merrnim komente për funksionin." "Konfiguro kodin PIN" "Ndrysho kodin PIN" "Duhet të aktivizohet posta zanore vizuale për të ndryshuar kodin PIN" 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 431d0dfb3..d4998ed2e 100644 --- a/java/com/android/voicemail/impl/res/values-sr/strings.xml +++ b/java/com/android/voicemail/impl/res/values-sr/strings.xml @@ -24,7 +24,6 @@ "Напредна подешавања" "Визуелна говорна пошта" "Додатне резервне копије и простор" - " ""Ово је експериментална функција"" коју тренутно тестирамо. Тако ће се можда избрисати говорне поруке са сервера говорне поште. Нема гаранција да ће ова функција бити подржана и у будућности. Ипак, желимо да добијамо повратне информације о њој." "Подесите PIN" "Промените PIN" "Морате да омогућите визуелну говорну пошту да бисте променили PIN" 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 cba2b15c8..c69a2df5f 100644 --- a/java/com/android/voicemail/impl/res/values-sv/strings.xml +++ b/java/com/android/voicemail/impl/res/values-sv/strings.xml @@ -24,7 +24,6 @@ "Avancerade inställningar" "Visuell röstbrevlåda" "Extra säkerhetskopiering och lagring" - " ""Det här är en experimentfunktion"" som vi för närvarande testar. Den kan potentiellt radera röstmeddelanden på röstbrevlådans server. Vi garanterar inte support för den här funktionen i framtiden. Vi är dock tacksamma för synpunkter om funktionen." "Ställ in pinkod" "Ändra pinkod" "Visuell röstbrevlåda måste vara aktiverat för att ändra pinkoden" 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 99de90ca5..d1cccc78c 100644 --- a/java/com/android/voicemail/impl/res/values-sw/strings.xml +++ b/java/com/android/voicemail/impl/res/values-sw/strings.xml @@ -24,7 +24,6 @@ "Mipangilio ya Kina" "Ujumbe wa Sauti Unaoonekana" "Nafasi ya ziada na hifadhi rudufu" - " ""Hiki ni kipengele cha majaribio"" tunachoijaribu kwa sasa. Huenda kitafuta ujumbe wa sauti kutoka kwenye seva yako ya ujumbe wa sauti. Hakuna hakikisho yoyote kwamba kipengele hiki kitatumika katika siku zijazo. Hata hivyo, tungependa kupata maoni yako kuhusu kipengele hiki." "Weka PIN" "Badilisha PIN" "Lazima uruhusu kipengele cha ujumbe wa sauti unaoonekana ili ubadilishe PIN" 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 a6c97c112..0c3c454e1 100644 --- a/java/com/android/voicemail/impl/res/values-ta/strings.xml +++ b/java/com/android/voicemail/impl/res/values-ta/strings.xml @@ -24,7 +24,6 @@ "மேம்பட்ட அமைப்புகள்" "விஷூவல் குரலஞ்சல்" "கூடுதல் காப்புப் பிரதியும் சேமிப்பகமும்" - " தற்போது நாங்கள் நடத்தி வரும் சோதனையில் ""இது ஒரு சோதனை அம்சமாகும்"". இது உங்கள் குரலஞ்சல் சேவையகத்திலிருந்து குரலஞ்சல்களை நீக்க சாத்தியமுள்ளது. இந்த அம்சம் எதிர்காலத்தில் ஆதரிக்கப்படும் என்பதற்கு உத்திரவாதம் இல்லை. இருப்பினும் இந்த அம்சத்தைப் பற்றிய கருத்தை வரவேற்கிறோம்." "பின்னை அமை" "பின்னை மாற்று" "பின்னை மாற்ற, விஷுவல் குரலஞ்சலை இயக்க வேண்டும்" 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 2ad08cffe..7a865f43f 100644 --- a/java/com/android/voicemail/impl/res/values-te/strings.xml +++ b/java/com/android/voicemail/impl/res/values-te/strings.xml @@ -24,7 +24,6 @@ "అధునాతన సెట్టింగ్‌లు" "దృశ్యమాన వాయిస్ మెయిల్" "అదనపు బ్యాకప్ మరియు నిల్వ" - " ""ఇది ప్రయోగాత్మక లక్షణం"" ప్రస్తుతం మేము దీన్ని పరీక్షిస్తున్నాము. దీని వలన మీ వాయిస్ మెయిల్ సర్వర్ నుండి సంభావ్యంగా వాయిస్ మెయిల్‌లు తొలగించబడతాయి. భవిష్యత్తులో ఈ లక్షణానికి మద్దతు ఉంటుందని ఎలాంటి హామీ అందించబడదు. అయితే, లక్షణంపై అభిప్రాయాన్ని అందిస్తే మేము సంతోషిస్తాము." "PINని సెట్ చేయండి" "PINను మార్చండి" "PINని మార్చడానికి తప్పనిసరిగా దృశ్యమాన వాయిస్ మెయిల్‌ను ప్రారంభించాలి" 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 49b07dfa2..68b32fb45 100644 --- a/java/com/android/voicemail/impl/res/values-th/strings.xml +++ b/java/com/android/voicemail/impl/res/values-th/strings.xml @@ -24,7 +24,6 @@ "การตั้งค่าขั้นสูง" "ภาพแสดงข้อความเสียง" "การสำรองข้อมูลและพื้นที่เก็บข้อมูลเพิ่มเติม" - " ""นี่คือคุณลักษณะทดลอง""ที่เรากำลังทดสอบการใช้งานอยู่ ซึ่งอาจลบข้อความเสียงออกจากเซิร์ฟเวอร์ข้อความเสียงได้ เราไม่รับประกันว่าจะรองรับคุณลักษณะนี้ในอนาคต แต่ยินดีรับฟังความคิดเห็น" "ตั้งค่า PIN" "เปลี่ยน PIN" "ต้องเปิดใช้ข้อความเสียงพร้อมภาพเพื่อเปลี่ยน PIN" 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 62623b633..c14919c03 100644 --- a/java/com/android/voicemail/impl/res/values-tl/strings.xml +++ b/java/com/android/voicemail/impl/res/values-tl/strings.xml @@ -24,7 +24,6 @@ "Mga Advanced na Setting" "Visual na Voicemail" "Karagdagang backup at storage" - " ""Eksperimental na feature ito"" na kasalukuyan naming sinusubukan. Posible nitong i-delete ang mga voicemail mula sa iyong server ng voicemail. Walang garantiyang susuportahan ang feature na ito sa hinaharap. Gayunpaman, gusto naming makakuha ng feedback tungkol sa feature." "Magtakda ng PIN" "Palitan ang PIN" "Dapat naka-enable ang visual na voicemail upang palitan ang PIN" 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 aed722a11..e8f9336f3 100644 --- a/java/com/android/voicemail/impl/res/values-tr/strings.xml +++ b/java/com/android/voicemail/impl/res/values-tr/strings.xml @@ -24,7 +24,6 @@ "Gelişmiş Ayarlar" "Görsel Sesli Mesaj" "Ekstra yedekleme ve depolama alanı" - " ""Bu, test etmekte olduğumuz ""deneysel bir özelliktir"". Bu özellik, sesli mesaj sunucunuzdaki mesajların silinmesine neden olabilir ve gelecekte desteklenmeyebilir. Yine de özellikle ilgili geri bildiriminizi öğrenmek isteriz." "PIN belirleyin" "PIN\'i değiştirin" "PIN\'i değiştirebilmek için görsel sesli mesaj etkinleştirilmelidir" 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 c3cbee681..760177ca4 100644 --- a/java/com/android/voicemail/impl/res/values-uk/strings.xml +++ b/java/com/android/voicemail/impl/res/values-uk/strings.xml @@ -24,7 +24,6 @@ "Розширені налаштування" "Візуальна голосова пошта" "Додаткова пам’ять і резервне копіювання" - " ""Це експериментальна функція,"" яку ми зараз тестуємо. У результаті її використання голосові повідомлення може бути видалено із сервера голосової пошти. Ми не гарантуємо, що ця функція підтримуватиметься в майбутньому, однак хочемо отримати відгук про неї." "Установити PIN-код" "Змінити PIN-код" "Щоб змінити PIN-код, потрібно ввімкнути візуальну голосову пошту" 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 201e6e910..2105fae08 100644 --- a/java/com/android/voicemail/impl/res/values-ur/strings.xml +++ b/java/com/android/voicemail/impl/res/values-ur/strings.xml @@ -24,7 +24,6 @@ "اعلی ترتیبات" "بصری صوتی میل" "اضافی بیک اپ اور اسٹوریج" - " ""یہ ایک تجرباتی خصوصیت ہے"" جسے ابھی ہم ٹیسٹ کر رہے ہیں۔ یہ ممکنہ طور پر آپ کے صوتی میل سرور پر سے آپ کی صوتی میلز کو حذف کر دے گی۔ مستقبل میں اس خصوصیت کی معاونت کی کوئی ضمانت نہیں ہے۔ لیکن ہم اس خصوصیت پر تاثرات پسند کریں گے۔" "‏PIN سیٹ کریں" "‏PIN تبدیل کریں" "‏PIN تبدیل کرنے کیلئے بصری صوتی میل اہل ہونی چاہئیے" 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 7f26475ec..fad79164d 100644 --- a/java/com/android/voicemail/impl/res/values-uz/strings.xml +++ b/java/com/android/voicemail/impl/res/values-uz/strings.xml @@ -24,7 +24,6 @@ "Kengaytirilgan sozlamalar" "Vizual ovozli pochta" "Zaxira. va saqlash u-n qo‘shimcha xotira" - " ""Bu – tajribaviy xususiyat bo‘lib,"" u ayni vaqtda sinovdan o‘tkazilmoqda. Sizning ovozli xabarlaringiz, ehtimol, ovozli pochta serveridan o‘chirib tashlanadi. Bu xususiyatning keyinchalik qo‘llab-quvvatlanishi kafolatlanmaydi. Shunday bo‘lsa-da, u haqda fikr-mulohaza bildirishingizni xohlaymiz." "PIN kod o‘rnatish" "PIN kodni o‘zgartirish" "PIN kodni o‘zgartirish uchun vizual ovozli pochtani yoqish lozim." 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 a0b25f803..1d029ea12 100644 --- a/java/com/android/voicemail/impl/res/values-vi/strings.xml +++ b/java/com/android/voicemail/impl/res/values-vi/strings.xml @@ -24,7 +24,6 @@ "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" - " ""Đây là một tính năng thử nghiệm"" chúng tôi hiện đang thử nghiệm. Tính năng này có khả năng sẽ xóa thư thoại khỏi máy chủ thư thoại của bạn. Không có đảm bảo về việc hỗ trợ tính năng này trong tương lai. Mặc dù vậy, chúng tôi vẫn mong muốn nhận được phản hồi về tính năng này." "Đặt mã PIN" "Thay đổi mã PIN" "Phải bật thư thoại kèm theo hình ảnh để thay đổi mã PIN" 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 9bfbe368d..d70f1fa51 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 @@ -24,7 +24,6 @@ "高级设置" "可视语音信箱" "额外存储空间和备份功能" - " ""这是一项试验性功能"" 我们目前正在进行测试。使用此功能可能会将语音邮件从您的语音邮件服务器上删除。我们不保证将来会支持此功能,但希望能收到针对此功能的反馈。" "设置 PIN 码" "更改 PIN 码" "必须启用可视语音信箱才可更改 PIN 码" 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 6c1ed4d15..4adc3fd97 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 @@ -24,7 +24,6 @@ "進階設定" "視像留言" "額外備份功能和儲存空間" - " ""此為我們目前正在測試的實驗性功能"",有可能會將您的留言從留言伺服器刪除。我們不保證日後會支援此功能,但還是歡迎您提供相關意見。" "設定 PIN" "變更 PIN" "必須啟用視像留言才能變更 PIN" 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 0af6ed152..6ff084f60 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 @@ -24,7 +24,6 @@ "進階設定" "視覺化語音信箱" "額外的備份功能和儲存空間" - " ""這是實驗性功能"",目前正在測試階段,而且可能會從你的語音信箱伺服器中刪除語音留言。我們不保證日後會支援此功能,但還是希望聽聽你的寶貴意見。" "設定 PIN" "變更 PIN" "必須啟用視覺化語音信箱才能變更 PIN" 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 81d4d3548..5adf300e5 100644 --- a/java/com/android/voicemail/impl/res/values-zu/strings.xml +++ b/java/com/android/voicemail/impl/res/values-zu/strings.xml @@ -24,7 +24,6 @@ "Izilungiselelo ezithuthukisiwe" "Ivoyisimeyili ebonakalayo" "Isipele esingeziwe nesitoreji" - " ""Lesi isici sokuhlola"" manje esisihlolayo. Lokhu kunamandla okususa amavoyisimeyili kusukela kuseva yakho yevoyisimeyili. Azikho iziqinisekiso zokusekela lesi sici ngokuzayo. Singathanda impendulo kusici yize kunjalo." "Setha i-PIN" "Shintsha i-PIN" "Ivoyisimeyili ebonakalayo kumele inikwe amandla ukuze ishintshe i-PIN" diff --git a/java/com/android/voicemail/impl/res/values/strings.xml b/java/com/android/voicemail/impl/res/values/strings.xml index c8085619b..bb754d18b 100644 --- a/java/com/android/voicemail/impl/res/values/strings.xml +++ b/java/com/android/voicemail/impl/res/values/strings.xml @@ -59,11 +59,6 @@ Extra backup and storage - - - This is a experimental feature we are currently testing. This will potentially delete voicemails from your voicemail server. There are no guarantees of supporting this feature in the future. We would love feedback on the feature though." - - Set PIN diff --git a/java/com/android/voicemail/impl/scheduling/BaseTask.java b/java/com/android/voicemail/impl/scheduling/BaseTask.java index 4cc6dd59e..0144e346f 100644 --- a/java/com/android/voicemail/impl/scheduling/BaseTask.java +++ b/java/com/android/voicemail/impl/scheduling/BaseTask.java @@ -18,12 +18,14 @@ package com.android.voicemail.impl.scheduling; import android.content.Context; import android.content.Intent; +import android.os.Bundle; import android.os.SystemClock; import android.support.annotation.CallSuper; import android.support.annotation.MainThread; import android.support.annotation.NonNull; import android.support.annotation.WorkerThread; import android.telecom.PhoneAccountHandle; +import com.android.dialer.proguard.UsedByReflection; import com.android.voicemail.impl.Assert; import com.android.voicemail.impl.NeededForTesting; import java.util.ArrayList; @@ -33,10 +35,15 @@ import java.util.List; * Provides common utilities for task implementations, such as execution time and managing {@link * Policy} */ +@UsedByReflection(value = "Tasks.java") public abstract class BaseTask implements Task { private static final String EXTRA_PHONE_ACCOUNT_HANDLE = "extra_phone_account_handle"; + private static final String EXTRA_EXECUTION_TIME = "extra_execution_time"; + + private Bundle mExtras; + private Context mContext; private int mId; @@ -58,7 +65,7 @@ public abstract class BaseTask implements Task { /** * Modify the task ID to prevent arbitrary task from executing. Can only be called before {@link - * #onCreate(Context, Intent, int, int)} returns. + * #onCreate(Context, Bundle)} returns. */ @MainThread public void setId(int id) { @@ -86,8 +93,7 @@ public abstract class BaseTask implements Task { return mPhoneAccountHandle; } /** - * Should be call in the constructor or {@link Policy#onCreate(BaseTask, Intent, int, int)} will - * be missed. + * Should be call in the constructor or {@link Policy#onCreate(BaseTask, Bundle)} will be missed. */ @MainThread public BaseTask addPolicy(Policy policy) { @@ -107,6 +113,7 @@ public abstract class BaseTask implements Task { mHasFailed = true; } + /** @param timeMillis the time since epoch, in milliseconds. */ @MainThread public void setExecutionTime(long timeMillis) { Assert.isMainThread(); @@ -131,7 +138,7 @@ public abstract class BaseTask implements Task { */ public static Intent createIntent( Context context, Class task, PhoneAccountHandle phoneAccountHandle) { - Intent intent = TaskSchedulerService.createIntent(context, task); + Intent intent = Tasks.createIntent(context, task); intent.putExtra(EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle); return intent; } @@ -141,13 +148,28 @@ public abstract class BaseTask implements Task { return new TaskId(mId, mPhoneAccountHandle); } + @Override + public Bundle toBundle() { + mExtras.putLong(EXTRA_EXECUTION_TIME, mExecutionTime); + return mExtras; + } + @Override @CallSuper - public void onCreate(Context context, Intent intent, int flags, int startId) { + public void onCreate(Context context, Bundle extras) { mContext = context; - mPhoneAccountHandle = intent.getParcelableExtra(EXTRA_PHONE_ACCOUNT_HANDLE); + mExtras = extras; + mPhoneAccountHandle = extras.getParcelable(EXTRA_PHONE_ACCOUNT_HANDLE); for (Policy policy : mPolicies) { - policy.onCreate(this, intent, flags, startId); + policy.onCreate(this, extras); + } + } + + @Override + @CallSuper + public void onRestore(Bundle extras) { + if (mExtras.containsKey(EXTRA_EXECUTION_TIME)) { + mExecutionTime = extras.getLong(EXTRA_EXECUTION_TIME); } } diff --git a/java/com/android/voicemail/impl/scheduling/BlockerTask.java b/java/com/android/voicemail/impl/scheduling/BlockerTask.java index 353508d56..1c8badaed 100644 --- a/java/com/android/voicemail/impl/scheduling/BlockerTask.java +++ b/java/com/android/voicemail/impl/scheduling/BlockerTask.java @@ -17,10 +17,12 @@ package com.android.voicemail.impl.scheduling; import android.content.Context; -import android.content.Intent; +import android.os.Bundle; +import com.android.dialer.proguard.UsedByReflection; import com.android.voicemail.impl.VvmLog; /** Task to block another task of the same ID from being queued for a certain amount of time. */ +@UsedByReflection(value = "Tasks.java") public class BlockerTask extends BaseTask { private static final String TAG = "BlockerTask"; @@ -33,10 +35,10 @@ public class BlockerTask extends BaseTask { } @Override - public void onCreate(Context context, Intent intent, int flags, int startId) { - super.onCreate(context, intent, flags, startId); - setId(intent.getIntExtra(EXTRA_TASK_ID, TASK_INVALID)); - setExecutionTime(getTimeMillis() + intent.getIntExtra(EXTRA_BLOCK_FOR_MILLIS, 0)); + public void onCreate(Context context, Bundle extras) { + super.onCreate(context, extras); + setId(extras.getInt(EXTRA_TASK_ID, TASK_INVALID)); + setExecutionTime(getTimeMillis() + extras.getInt(EXTRA_BLOCK_FOR_MILLIS, 0)); } @Override @@ -46,6 +48,6 @@ public class BlockerTask extends BaseTask { @Override public void onDuplicatedTaskAdded(Task task) { - VvmLog.v(TAG, task.toString() + "blocked, " + getReadyInMilliSeconds() + "millis remaining"); + VvmLog.i(TAG, task + "blocked, " + getReadyInMilliSeconds() + "millis remaining"); } } diff --git a/java/com/android/voicemail/impl/scheduling/MinimalIntervalPolicy.java b/java/com/android/voicemail/impl/scheduling/MinimalIntervalPolicy.java index 8b2fe7098..76fba4fb0 100644 --- a/java/com/android/voicemail/impl/scheduling/MinimalIntervalPolicy.java +++ b/java/com/android/voicemail/impl/scheduling/MinimalIntervalPolicy.java @@ -17,6 +17,7 @@ package com.android.voicemail.impl.scheduling; import android.content.Intent; +import android.os.Bundle; import com.android.voicemail.impl.scheduling.Task.TaskId; /** @@ -35,7 +36,7 @@ public class MinimalIntervalPolicy implements Policy { } @Override - public void onCreate(BaseTask task, Intent intent, int flags, int startId) { + public void onCreate(BaseTask task, Bundle extras) { mTask = task; mId = mTask.getId(); } @@ -47,7 +48,7 @@ public class MinimalIntervalPolicy implements Policy { public void onCompleted() { if (!mTask.hasFailed()) { Intent intent = - mTask.createIntent(mTask.getContext(), BlockerTask.class, mId.phoneAccountHandle); + BaseTask.createIntent(mTask.getContext(), BlockerTask.class, mId.phoneAccountHandle); intent.putExtra(BlockerTask.EXTRA_TASK_ID, mId.id); intent.putExtra(BlockerTask.EXTRA_BLOCK_FOR_MILLIS, mBlockForMillis); mTask.getContext().startService(intent); diff --git a/java/com/android/voicemail/impl/scheduling/Policy.java b/java/com/android/voicemail/impl/scheduling/Policy.java index 607782191..9624aeb7d 100644 --- a/java/com/android/voicemail/impl/scheduling/Policy.java +++ b/java/com/android/voicemail/impl/scheduling/Policy.java @@ -16,7 +16,7 @@ package com.android.voicemail.impl.scheduling; -import android.content.Intent; +import android.os.Bundle; /** * A set of listeners managed by {@link BaseTask} for common behaviors such as retrying. Call {@link @@ -24,7 +24,7 @@ import android.content.Intent; */ public interface Policy { - void onCreate(BaseTask task, Intent intent, int flags, int startId); + void onCreate(BaseTask task, Bundle extras); void onBeforeExecute(); diff --git a/java/com/android/voicemail/impl/scheduling/PostponePolicy.java b/java/com/android/voicemail/impl/scheduling/PostponePolicy.java index e24df0c7a..46773b53a 100644 --- a/java/com/android/voicemail/impl/scheduling/PostponePolicy.java +++ b/java/com/android/voicemail/impl/scheduling/PostponePolicy.java @@ -16,7 +16,7 @@ package com.android.voicemail.impl.scheduling; -import android.content.Intent; +import android.os.Bundle; import com.android.voicemail.impl.VvmLog; /** @@ -37,7 +37,7 @@ public class PostponePolicy implements Policy { } @Override - public void onCreate(BaseTask task, Intent intent, int flags, int startId) { + public void onCreate(BaseTask task, Bundle extras) { mTask = task; mTask.setExecutionTime(mTask.getTimeMillis() + mPostponeMillis); } @@ -62,7 +62,7 @@ public class PostponePolicy implements Policy { if (mTask.hasStarted()) { return; } - VvmLog.d(TAG, "postponing " + mTask); + VvmLog.i(TAG, "postponing " + mTask); mTask.setExecutionTime(mTask.getTimeMillis() + mPostponeMillis); } } diff --git a/java/com/android/voicemail/impl/scheduling/RetryPolicy.java b/java/com/android/voicemail/impl/scheduling/RetryPolicy.java index a8e4a3d3c..b8703ea15 100644 --- a/java/com/android/voicemail/impl/scheduling/RetryPolicy.java +++ b/java/com/android/voicemail/impl/scheduling/RetryPolicy.java @@ -17,6 +17,7 @@ package com.android.voicemail.impl.scheduling; import android.content.Intent; +import android.os.Bundle; import android.telecom.PhoneAccountHandle; import com.android.voicemail.impl.VoicemailStatus; import com.android.voicemail.impl.VvmLog; @@ -60,11 +61,11 @@ public class RetryPolicy implements Policy { } @Override - public void onCreate(BaseTask task, Intent intent, int flags, int startId) { + public void onCreate(BaseTask task, Bundle extras) { mTask = task; - mRetryCount = intent.getIntExtra(EXTRA_RETRY_COUNT, 0); + mRetryCount = extras.getInt(EXTRA_RETRY_COUNT, 0); if (mRetryCount > 0) { - VvmLog.d( + VvmLog.i( TAG, "retry #" + mRetryCount + " for " + mTask + " queued, executing in " + mRetryDelayMillis); mTask.setExecutionTime(mTask.getTimeMillis() + mRetryDelayMillis); @@ -85,10 +86,10 @@ public class RetryPolicy implements Policy { public void onCompleted() { if (!mFailed || !hasMoreRetries()) { if (!mFailed) { - VvmLog.d(TAG, mTask.toString() + " completed successfully"); + VvmLog.i(TAG, mTask + " completed successfully"); } if (!hasMoreRetries()) { - VvmLog.d(TAG, "Retry limit for " + mTask + " reached"); + VvmLog.i(TAG, "Retry limit for " + mTask + " reached"); } VvmLog.i(TAG, "committing deferred status: " + mVoicemailStatusEditor.getValues()); mVoicemailStatusEditor.deferredApply(); diff --git a/java/com/android/voicemail/impl/scheduling/Task.java b/java/com/android/voicemail/impl/scheduling/Task.java index 2d08f5b03..447a9db7b 100644 --- a/java/com/android/voicemail/impl/scheduling/Task.java +++ b/java/com/android/voicemail/impl/scheduling/Task.java @@ -17,26 +17,24 @@ package com.android.voicemail.impl.scheduling; import android.content.Context; -import android.content.Intent; +import android.os.Bundle; import android.support.annotation.MainThread; import android.support.annotation.WorkerThread; import android.telecom.PhoneAccountHandle; import java.util.Objects; /** - * A task for {@link TaskSchedulerService} to execute. Since the task is sent through a intent to - * the scheduler, The task must be constructable with the intent. Specifically, It must have a - * constructor with zero arguments, and have all relevant data packed inside the intent. Use {@link - * TaskSchedulerService#createIntent(Context, Class)} to create a intent that will construct the - * Task. + * A task for {@link TaskSchedulerService} to execute. Since the task is sent through a bundle to + * the scheduler, The task must be constructable with the bundle. Specifically, It must have a + * constructor with zero arguments, and have all relevant data packed inside the bundle. Use {@link + * Tasks#createIntent(Context, Class)} to create a intent that will construct the Task. * *

Only {@link #onExecuteInBackgroundThread()} is run on the worker thread. */ public interface Task { - /** * TaskId to indicate it has not be set. If a task does not provide a default TaskId it should be - * set before {@link Task#onCreate(Context, Intent, int, int) returns} + * set before {@link Task#onCreate(Context, Bundle)} returns */ int TASK_INVALID = -1; @@ -49,6 +47,7 @@ public interface Task { int TASK_UPLOAD = 1; int TASK_SYNC = 2; int TASK_ACTIVATION = 3; + int TASK_STATUS_CHECK = 4; /** * Used to differentiate between types of tasks. If a task with the same TaskId is already in the @@ -87,8 +86,29 @@ public interface Task { TaskId getId(); + /** + * Serializes the task into a bundle, which will be stored in a {@link android.app.job.JobInfo} + * and used to reconstruct the task even if the app is terminated. The task will be initialized + * with {@link #onCreate(Context, Bundle)}. + */ + Bundle toBundle(); + + /** + * A task object is created through reflection, calling the default constructor. The actual + * initialization is done in this method. If the task is not a new instance, but being restored + * from a bundle, {@link #onRestore(Bundle)} will be called afterwards. + */ + @MainThread + void onCreate(Context context, Bundle extras); + + /** + * Called after {@link #onCreate(Context, Bundle)} if the task is being restored from a Bundle + * instead creating a new instance. For example, if the task is stored in {@link + * TaskSchedulerJobService} during a long sleep, this will be called when the job is ran again and + * the tasks are being restored from the saved state. + */ @MainThread - void onCreate(Context context, Intent intent, int flags, int startId); + void onRestore(Bundle extras); /** * @return number of milliSeconds the scheduler should wait before running this task. A value less diff --git a/java/com/android/voicemail/impl/scheduling/TaskQueue.java b/java/com/android/voicemail/impl/scheduling/TaskQueue.java new file mode 100644 index 000000000..fc5aa947a --- /dev/null +++ b/java/com/android/voicemail/impl/scheduling/TaskQueue.java @@ -0,0 +1,149 @@ +/* + * 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.content.Context; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import com.android.voicemail.impl.Assert; +import com.android.voicemail.impl.VvmLog; +import com.android.voicemail.impl.scheduling.Task.TaskId; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Queue; + +/** + * A queue that manages priority and duplication of {@link Task}. A task is identified by a {@link + * TaskId}, which consists of an integer representing the operation the task, and a {@link + * android.telecom.PhoneAccountHandle} representing which SIM it is operated on. + */ +class TaskQueue implements Iterable { + + private final Queue queue = new ArrayDeque<>(); + + public List toBundles() { + List result = new ArrayList<>(queue.size()); + for (Task task : queue) { + result.add(Tasks.toBundle(task)); + } + return result; + } + + public void fromBundles(Context context, List pendingTasks) { + Assert.isTrue(queue.isEmpty()); + for (Bundle pendingTask : pendingTasks) { + Task task = Tasks.createTask(context, pendingTask); + task.onRestore(pendingTask); + add(task); + } + } + + /** + * Add a new task to the queue. A new task with a TaskId collision will be discarded, and {@link + * Task#onDuplicatedTaskAdded(Task)} will be called on the existing task. + * + * @return {@code true} if the task is added, or {@code false} if the task is discarded due to + * collision. + */ + public boolean add(Task task) { + if (task.getId().id == Task.TASK_INVALID) { + throw new AssertionError("Task id was not set to a valid value before adding."); + } + if (task.getId().id != Task.TASK_ALLOW_DUPLICATES) { + Task oldTask = getTask(task.getId()); + if (oldTask != null) { + oldTask.onDuplicatedTaskAdded(task); + VvmLog.i("TaskQueue.add", "duplicated task added"); + return false; + } + } + queue.add(task); + return true; + } + + public void remove(Task task) { + queue.remove(task); + } + + public Task getTask(TaskId id) { + Assert.isMainThread(); + for (Task task : queue) { + if (task.getId().equals(id)) { + return task; + } + } + return null; + } + + /** + * Packed return value of {@link #getNextTask(long)}. If a runnable task is found {@link + * #minimalWaitTimeMillis} will be {@code null}. If no tasks is runnable {@link #task} will be + * {@code null}, and {@link #minimalWaitTimeMillis} will contain the time to wait. If there are no + * tasks at all both will be {@code null}. + */ + static final class NextTask { + @Nullable final Task task; + @Nullable final Long minimalWaitTimeMillis; + + NextTask(@Nullable Task task, @Nullable Long minimalWaitTimeMillis) { + this.task = task; + this.minimalWaitTimeMillis = minimalWaitTimeMillis; + } + } + + /** + * The next task is the first task with {@link Task#getReadyInMilliSeconds()} return a value less + * then {@code readyToleranceMillis}, in insertion order. If no task matches this criteria, the + * minimal value of {@link Task#getReadyInMilliSeconds()} is returned instead. If there are no + * tasks at all, the minimalWaitTimeMillis will also be null. + */ + @NonNull + NextTask getNextTask(long readyToleranceMillis) { + Long minimalWaitTime = null; + for (Task task : queue) { + long waitTime = task.getReadyInMilliSeconds(); + if (waitTime < readyToleranceMillis) { + return new NextTask(task, 0L); + } else { + if (minimalWaitTime == null || waitTime < minimalWaitTime) { + minimalWaitTime = waitTime; + } + } + } + return new NextTask(null, minimalWaitTime); + } + + public void clear() { + queue.clear(); + } + + public int size() { + return queue.size(); + } + + public boolean isEmpty() { + return queue.isEmpty(); + } + + @Override + public Iterator iterator() { + return queue.iterator(); + } +} diff --git a/java/com/android/voicemail/impl/scheduling/TaskSchedulerJobService.java b/java/com/android/voicemail/impl/scheduling/TaskSchedulerJobService.java new file mode 100644 index 000000000..eab410eb0 --- /dev/null +++ b/java/com/android/voicemail/impl/scheduling/TaskSchedulerJobService.java @@ -0,0 +1,158 @@ +/* + * 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.app.job.JobInfo; +import android.app.job.JobParameters; +import android.app.job.JobScheduler; +import android.app.job.JobService; +import android.content.ComponentName; +import android.content.Context; +import android.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; +import com.android.voicemail.impl.Assert; +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}. + */ +@TargetApi(VERSION_CODES.O) +public class TaskSchedulerJobService extends JobService implements TaskSchedulerService.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); + return true /* job still running in background */; + } + + @Override + @MainThread + public boolean onStopJob(JobParameters params) { + scheduler.onStopJob(); + jobParameters = null; + return false /* don't reschedule. TaskScheduler 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. + * + * @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. + */ + @MainThread + public static void scheduleJob( + Context context, List pendingTasks, long delayMillis, boolean isNewJob) { + Assert.isMainThread(); + JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); + JobInfo pendingJob = jobScheduler.getPendingJob(ScheduledJobIds.VVM_TASK_SCHEDULER_JOB); + VvmLog.i(TAG, "scheduling job with " + pendingTasks.size() + " tasks"); + if (pendingJob != null) { + if (isNewJob) { + List existingTasks = + getBundleList( + pendingJob.getTransientExtras().getParcelableArray(EXTRA_TASK_EXTRAS_ARRAY)); + VvmLog.i(TAG, "merging job with " + existingTasks.size() + " existing tasks"); + TaskQueue queue = new TaskQueue(); + queue.fromBundles(context, existingTasks); + for (Bundle pendingTask : pendingTasks) { + queue.add(Tasks.createTask(context, pendingTask)); + } + pendingTasks = queue.toBundles(); + } + VvmLog.i(TAG, "canceling existing job."); + jobScheduler.cancel(ScheduledJobIds.VVM_TASK_SCHEDULER_JOB); + } + Bundle extras = new Bundle(); + extras.putParcelableArray( + EXTRA_TASK_EXTRAS_ARRAY, pendingTasks.toArray(new Bundle[pendingTasks.size()])); + JobInfo.Builder builder = + new JobInfo.Builder( + ScheduledJobIds.VVM_TASK_SCHEDULER_JOB, + new ComponentName(context, TaskSchedulerJobService.class)) + .setTransientExtras(extras) + .setMinimumLatency(delayMillis) + .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); + if (isNewJob) { + Assert.isTrue(delayMillis == 0); + builder.setOverrideDeadline(0); + VvmLog.i(TAG, "running job instantly."); + } + jobScheduler.schedule(builder.build()); + VvmLog.i(TAG, "job scheduled"); + } + + /** + * The system will hold a wakelock when {@link #onStartJob(JobParameters)} is called to ensure the + * device will not sleep when the job is still running. Finish the job so the system will release + * the wakelock + */ + @Override + public void finish() { + VvmLog.i(TAG, "finishing job and unbinding TaskSchedulerService"); + jobFinished(jobParameters, false); + jobParameters = null; + unbindService(mConnection); + } + + private static List getBundleList(Parcelable[] parcelables) { + List result = new ArrayList<>(parcelables.length); + for (Parcelable parcelable : parcelables) { + result.add((Bundle) parcelable); + } + return result; + } +} diff --git a/java/com/android/voicemail/impl/scheduling/TaskSchedulerService.java b/java/com/android/voicemail/impl/scheduling/TaskSchedulerService.java index 81bd36fee..5ad2447de 100644 --- a/java/com/android/voicemail/impl/scheduling/TaskSchedulerService.java +++ b/java/com/android/voicemail/impl/scheduling/TaskSchedulerService.java @@ -16,20 +16,18 @@ package com.android.voicemail.impl.scheduling; -import android.app.AlarmManager; -import android.app.PendingIntent; +import android.annotation.TargetApi; import android.app.Service; import android.content.Context; import android.content.Intent; import android.os.Binder; +import android.os.Build.VERSION_CODES; +import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; -import android.os.PowerManager; -import android.os.PowerManager.WakeLock; -import android.os.SystemClock; import android.support.annotation.MainThread; import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; @@ -37,20 +35,50 @@ import android.support.annotation.WorkerThread; import com.android.voicemail.impl.Assert; import com.android.voicemail.impl.NeededForTesting; import com.android.voicemail.impl.VvmLog; -import com.android.voicemail.impl.scheduling.Task.TaskId; -import java.util.ArrayDeque; -import java.util.Queue; +import com.android.voicemail.impl.scheduling.TaskQueue.NextTask; +import java.util.List; /** - * A service to queue and run {@link Task} on a worker thread. Only one task will be ran at a time, - * and same task cannot exist in the queue at the same time. The service will be started when a - * intent is received, and stopped when there are no more tasks in the queue. + * A service to queue and run {@link Task} with the {@link android.app.job.JobScheduler}. A task is + * queued using {@link Context#startService(Intent)}. The intent should contain enough information + * in {@link Intent#getExtras()} to construct the task (see {@link Tasks#createIntent(Context, + * Class)}). + * + *

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 + * #finishJob()}. 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 service will be started when a intent is received, and stopped when there are no more + * tasks in the queue. + * + *

{@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. + *
*/ +@SuppressWarnings("AndroidApiChecker") /* stream() */ +@TargetApi(VERSION_CODES.O) public class TaskSchedulerService extends Service { - private static final String TAG = "VvmTaskScheduler"; + interface Job { + void finish(); + } - private static final String ACTION_WAKEUP = "action_wakeup"; + private static final String TAG = "VvmTaskScheduler"; private static final int READY_TOLERANCE_MILLISECONDS = 100; @@ -58,15 +86,13 @@ public class TaskSchedulerService extends Service { * Threshold to determine whether to do a short or long sleep when a task is scheduled in the * future. * - *

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

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

A long sleep will release the wake lock and set a {@link AlarmManager} alarm. The alarm is - * exact and will wake up the device. Note: as this service is run in the telephony process it - * does not seem to be restricted by doze or sleep, it will fire exactly at the moment. The - * unbundled version should take doze into account. + *

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 = 60_000; + 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, @@ -75,14 +101,9 @@ public class TaskSchedulerService extends Service { */ private static final int STOP_DELAY_MILLISECONDS = 5_000; - private static final String EXTRA_CLASS_NAME = "extra_class_name"; - - private static final String WAKE_LOCK_TAG = "TaskSchedulerService_wakelock"; - // The thread to run tasks on private volatile WorkerThreadHandler mWorkerThreadHandler; - private Context mContext = this; /** * Used by tests to turn task handling into a single threaded process by calling {@link * Handler#handleMessage(Message)} directly @@ -91,21 +112,27 @@ public class TaskSchedulerService extends Service { private MainThreadHandler mMainThreadHandler; - private WakeLock mWakeLock; + // Binder given to clients + private final IBinder mBinder = new LocalBinder(); /** Main thread only, access through {@link #getTasks()} */ - private final Queue mTasks = new ArrayDeque<>(); + private final TaskQueue mTasks = new TaskQueue(); private boolean mWorkerThreadIsBusy = false; + private Job mJob; + private final Runnable mStopServiceWithDelay = new Runnable() { + @MainThread @Override public void run() { - VvmLog.d(TAG, "Stopping service"); + VvmLog.i(TAG, "Stopping service"); + finishJob(); stopSelf(); } }; + /** Should attempt to run the next task when a task has finished or been added. */ private boolean mTaskAutoRunDisabledForTesting = false; @@ -122,7 +149,7 @@ public class TaskSchedulerService extends Service { Assert.isNotMainThread(); Task task = (Task) msg.obj; try { - VvmLog.v(TAG, "executing task " + task); + VvmLog.i(TAG, "executing task " + task); task.onExecuteInBackgroundThread(); } catch (Throwable throwable) { VvmLog.e(TAG, "Exception while executing task " + task + ":", throwable); @@ -157,10 +184,6 @@ public class TaskSchedulerService extends Service { @MainThread public void onCreate() { super.onCreate(); - mWakeLock = - getSystemService(PowerManager.class) - .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKE_LOCK_TAG); - mWakeLock.setReferenceCounted(false); HandlerThread thread = new HandlerThread("VvmTaskSchedulerService"); thread.start(); @@ -171,27 +194,27 @@ public class TaskSchedulerService extends Service { @Override public void onDestroy() { mWorkerThreadHandler.getLooper().quit(); - mWakeLock.release(); } @Override @MainThread public int onStartCommand(@Nullable Intent intent, int flags, int startId) { Assert.isMainThread(); - // maybeRunNextTask() will release the wakelock either by entering a long sleep or stopping - // the service. - mWakeLock.acquire(); - if (ACTION_WAKEUP.equals(intent.getAction())) { - VvmLog.d(TAG, "woke up by AlarmManager"); + if (intent == null) { + VvmLog.w(TAG, "null intent received"); + return START_NOT_STICKY; + } + Task task = Tasks.createTask(this, intent.getExtras()); + Assert.isTrue(task != null); + addTask(task); + + mMainThreadHandler.removeCallbacks(mStopServiceWithDelay); + VvmLog.i(TAG, "task added"); + if (mJob == null) { + scheduleJob(0, true); } else { - Task task = createTask(intent, flags, startId); - if (task == null) { - VvmLog.e(TAG, "cannot create task form intent"); - } else { - addTask(task); - } + maybeRunNextTask(); } - maybeRunNextTask(); // STICKY means the service will be automatically restarted will the last intent if it is // killed. return START_NOT_STICKY; @@ -201,66 +224,14 @@ public class TaskSchedulerService extends Service { @VisibleForTesting void addTask(Task task) { Assert.isMainThread(); - if (task.getId().id == Task.TASK_INVALID) { - throw new AssertionError("Task id was not set to a valid value before adding."); - } - if (task.getId().id != Task.TASK_ALLOW_DUPLICATES) { - Task oldTask = getTask(task.getId()); - if (oldTask != null) { - oldTask.onDuplicatedTaskAdded(task); - return; - } - } - mMainThreadHandler.removeCallbacks(mStopServiceWithDelay); getTasks().add(task); - maybeRunNextTask(); - } - - @MainThread - @Nullable - private Task getTask(TaskId taskId) { - Assert.isMainThread(); - for (Task task : getTasks()) { - if (task.getId().equals(taskId)) { - return task; - } - } - return null; } @MainThread - private Queue getTasks() { - Assert.isMainThread(); - return mTasks; - } - - /** Create an intent that will queue the task */ - public static Intent createIntent(Context context, Class task) { - Intent intent = new Intent(context, TaskSchedulerService.class); - intent.putExtra(EXTRA_CLASS_NAME, task.getName()); - return intent; - } - @VisibleForTesting - @MainThread - @Nullable - Task createTask(@Nullable Intent intent, int flags, int startId) { + TaskQueue getTasks() { Assert.isMainThread(); - if (intent == null) { - return null; - } - String className = intent.getStringExtra(EXTRA_CLASS_NAME); - VvmLog.d(TAG, "create task:" + className); - if (className == null) { - throw new IllegalArgumentException("EXTRA_CLASS_NAME expected"); - } - try { - Task task = (Task) Class.forName(className).newInstance(); - task.onCreate(mContext, intent, flags, startId); - return task; - } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) { - throw new IllegalArgumentException(e); - } + return mTasks; } @MainThread @@ -282,37 +253,31 @@ public class TaskSchedulerService extends Service { @MainThread void runNextTask() { Assert.isMainThread(); - // The current alarm is no longer valid, a new one will be set up if required. - getSystemService(AlarmManager.class).cancel(getWakeupIntent()); if (getTasks().isEmpty()) { prepareStop(); return; } - Long minimalWaitTime = null; - for (Task task : getTasks()) { - long waitTime = task.getReadyInMilliSeconds(); - if (waitTime < READY_TOLERANCE_MILLISECONDS) { - task.onBeforeExecute(); - Message message = mWorkerThreadHandler.obtainMessage(); - message.obj = task; - mWorkerThreadIsBusy = true; - mMessageSender.send(message); - return; - } else { - if (minimalWaitTime == null || waitTime < minimalWaitTime) { - minimalWaitTime = waitTime; - } - } + NextTask nextTask = getTasks().getNextTask(READY_TOLERANCE_MILLISECONDS); + + if (nextTask.task != null) { + nextTask.task.onBeforeExecute(); + Message message = mWorkerThreadHandler.obtainMessage(); + message.obj = nextTask.task; + mWorkerThreadIsBusy = true; + mMessageSender.send(message); + return; } - VvmLog.d(TAG, "minimal wait time:" + minimalWaitTime); - if (!mTaskAutoRunDisabledForTesting && minimalWaitTime != null) { + VvmLog.i(TAG, "minimal wait time:" + nextTask.minimalWaitTimeMillis); + if (!mTaskAutoRunDisabledForTesting && 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(minimalWaitTime); + sleep(nextTask.minimalWaitTimeMillis); } } + @MainThread private void sleep(long timeMillis) { + VvmLog.i(TAG, "sleep for " + timeMillis + " millis"); if (timeMillis < SHORT_SLEEP_THRESHOLD_MILLISECONDS) { mMainThreadHandler.postDelayed( new Runnable() { @@ -324,34 +289,24 @@ public class TaskSchedulerService extends Service { timeMillis); return; } - - // Tasks does not have a strict timing requirement, use AlarmManager.set() so the OS could - // optimize the battery usage. As this service currently run in the telephony process the - // OS give it privileges to behave the same as setExact(), but set() is the targeted - // behavior once this is unbundled. - getSystemService(AlarmManager.class) - .set( - AlarmManager.ELAPSED_REALTIME_WAKEUP, - SystemClock.elapsedRealtime() + timeMillis, - getWakeupIntent()); - mWakeLock.release(); - VvmLog.d(TAG, "Long sleep for " + timeMillis + " millis"); + finishJob(); + mMainThreadHandler.post(() -> scheduleJob(timeMillis, false)); } - private PendingIntent getWakeupIntent() { - Intent intent = new Intent(ACTION_WAKEUP, null, this, getClass()); - return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); + private List serializePendingTasks() { + return getTasks().toBundles(); } private void prepareStop() { - VvmLog.d( + VvmLog.i( TAG, - "No more tasks, stopping service if no task are added in " + "no more tasks, stopping service if no task are added in " + STOP_DELAY_MILLISECONDS + " millis"); mMainThreadHandler.postDelayed(mStopServiceWithDelay, STOP_DELAY_MILLISECONDS); } + @NeededForTesting static class MessageSender { public void send(Message message) { @@ -359,11 +314,6 @@ public class TaskSchedulerService extends Service { } } - @NeededForTesting - void setContextForTest(Context context) { - mContext = context; - } - @NeededForTesting void setTaskAutoRunDisabledForTest(boolean value) { mTaskAutoRunDisabledForTesting = value; @@ -374,15 +324,65 @@ public class TaskSchedulerService extends Service { mMessageSender = sender; } - @NeededForTesting - void clearTasksForTest() { + /** + * 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"); + mJob = job; + mTasks.fromBundles(this, 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()) { + finishJob(); + mMainThreadHandler.post(() -> scheduleJob(0, true)); + } + } + + /** + * Serializes all pending tasks and schedule a new {@link TaskSchedulerJobService}. + * + * @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 + private void scheduleJob(long delayMillis, boolean isNewJob) { + Assert.isMainThread(); + TaskSchedulerJobService.scheduleJob(this, serializePendingTasks(), delayMillis, isNewJob); mTasks.clear(); } + /** + * 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 finishJob() { + Assert.isMainThread(); + VvmLog.i(TAG, "finishing Job"); + mJob.finish(); + mJob = null; + } + @Override @Nullable public IBinder onBind(Intent intent) { - return new LocalBinder(); + return mBinder; } @NeededForTesting @@ -393,4 +393,8 @@ public class TaskSchedulerService extends Service { return TaskSchedulerService.this; } } + + private boolean isJobRunning() { + return mJob != null; + } } diff --git a/java/com/android/voicemail/impl/scheduling/Tasks.java b/java/com/android/voicemail/impl/scheduling/Tasks.java new file mode 100644 index 000000000..34debaf29 --- /dev/null +++ b/java/com/android/voicemail/impl/scheduling/Tasks.java @@ -0,0 +1,73 @@ +/* + * 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.content.Context; +import android.content.Intent; +import android.os.Bundle; +import com.android.voicemail.impl.VvmLog; + +/** Common operations on {@link Task} */ +final class Tasks { + + private Tasks() {} + + static final String EXTRA_CLASS_NAME = "extra_class_name"; + + /** + * 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} + */ + public static Task createTask(Context context, Bundle extras) { + // The extra contains custom parcelables which cannot be unmarshalled by the framework class + // loader. + extras.setClassLoader(context.getClassLoader()); + String className = extras.getString(EXTRA_CLASS_NAME); + VvmLog.i("Task.createTask", "create task:" + className); + if (className == null) { + throw new IllegalArgumentException("EXTRA_CLASS_NAME expected"); + } + try { + Task task = (Task) Class.forName(className).getDeclaredConstructor().newInstance(); + task.onCreate(context, extras); + return task; + } catch (ReflectiveOperationException e) { + throw new IllegalArgumentException(e); + } + } + + /** + * Serializes necessary states to a bundle that can be used to restore the task with {@link + * #createTask(Context, Bundle)} + */ + public static Bundle toBundle(Task task) { + Bundle result = task.toBundle(); + result.putString(EXTRA_CLASS_NAME, task.getClass().getName()); + return result; + } + + /** + * Create an intent that when called with {@link Context#startService(Intent)}, will queue the + * task. Implementations of {@link Task} should use the result of this and fill in + * necessary information. + */ + public static Intent createIntent(Context context, Class task) { + Intent intent = new Intent(context, TaskSchedulerService.class); + intent.putExtra(EXTRA_CLASS_NAME, task.getName()); + return intent; + } +} diff --git a/java/com/android/voicemail/impl/settings/VisualVoicemailSettingsUtil.java b/java/com/android/voicemail/impl/settings/VisualVoicemailSettingsUtil.java index 4c95e7783..9ce32a97c 100644 --- a/java/com/android/voicemail/impl/settings/VisualVoicemailSettingsUtil.java +++ b/java/com/android/voicemail/impl/settings/VisualVoicemailSettingsUtil.java @@ -22,6 +22,7 @@ import com.android.voicemail.VoicemailComponent; import com.android.voicemail.impl.OmtpVvmCarrierConfigHelper; import com.android.voicemail.impl.R; import com.android.voicemail.impl.VisualVoicemailPreferences; +import com.android.voicemail.impl.VvmLog; import com.android.voicemail.impl.sync.VvmAccountManager; /** Save whether or not a particular account is enabled in shared to be retrieved later. */ @@ -31,6 +32,7 @@ public class VisualVoicemailSettingsUtil { public static void setEnabled( Context context, PhoneAccountHandle phoneAccount, boolean isEnabled) { + VvmLog.i("VisualVoicemailSettingsUtil.setEnable", phoneAccount + " enabled:" + isEnabled); new VisualVoicemailPreferences(context, phoneAccount) .edit() .putBoolean(IS_ENABLED_KEY, isEnabled) diff --git a/java/com/android/voicemail/impl/settings/VoicemailChangePinActivity.java b/java/com/android/voicemail/impl/settings/VoicemailChangePinActivity.java index 330dc3621..b22a765cf 100644 --- a/java/com/android/voicemail/impl/settings/VoicemailChangePinActivity.java +++ b/java/com/android/voicemail/impl/settings/VoicemailChangePinActivity.java @@ -45,8 +45,7 @@ import android.widget.EditText; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; import android.widget.Toast; -import com.android.dialer.logging.Logger; -import com.android.dialer.logging.nano.DialerImpression; +import com.android.dialer.logging.DialerImpression; import com.android.voicemail.impl.OmtpConstants; import com.android.voicemail.impl.OmtpConstants.ChangePinResult; import com.android.voicemail.impl.OmtpEvents; @@ -59,6 +58,7 @@ import com.android.voicemail.impl.imap.ImapHelper; import com.android.voicemail.impl.imap.ImapHelper.InitializingException; import com.android.voicemail.impl.mail.MessagingException; import com.android.voicemail.impl.sync.VvmNetworkRequestCallback; +import com.android.voicemail.impl.utils.LoggerUtils; /** * Dialog to change the voicemail PIN. The TUI (Telephony User Interface) PIN is used when accessing @@ -278,7 +278,8 @@ public class VoicemailChangePinActivity extends Activity activity.handleOmtpEvent(OmtpEvents.CONFIG_PIN_SET); activity.finish(); - Logger.get(activity).logImpression(DialerImpression.Type.VVM_CHANGE_PIN_COMPLETED); + LoggerUtils.logImpressionOnMainThread( + activity, DialerImpression.Type.VVM_CHANGE_PIN_COMPLETED); Toast.makeText( activity, activity.getString(R.string.change_pin_succeeded), Toast.LENGTH_SHORT) .show(); diff --git a/java/com/android/voicemail/impl/settings/VoicemailSettingsFragment.java b/java/com/android/voicemail/impl/settings/VoicemailSettingsFragment.java index 716f503ff..423fd11b4 100644 --- a/java/com/android/voicemail/impl/settings/VoicemailSettingsFragment.java +++ b/java/com/android/voicemail/impl/settings/VoicemailSettingsFragment.java @@ -27,8 +27,8 @@ import android.support.annotation.Nullable; import android.telecom.PhoneAccountHandle; 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.logging.nano.DialerImpression; import com.android.voicemail.VoicemailClient; import com.android.voicemail.VoicemailComponent; import com.android.voicemail.impl.OmtpVvmCarrierConfigHelper; @@ -164,8 +164,6 @@ public class VoicemailSettingsFragment extends PreferenceFragment VisualVoicemailSettingsUtil.isEnabled(getContext(), phoneAccountHandle)); autoArchiveSwitchPreference.setOnPreferenceChangeListener(this); - autoArchiveSwitchPreference.setSummary( - getText(R.string.voicemail_visual_voicemail_auto_archive_temporary_disclaimer)); autoArchiveSwitchPreference.setChecked( VisualVoicemailSettingsUtil.isArchiveEnabled(getContext(), phoneAccountHandle)); } else { diff --git a/java/com/android/voicemail/impl/sms/LegacyModeSmsHandler.java b/java/com/android/voicemail/impl/sms/LegacyModeSmsHandler.java index 1d1a639c5..5decf6376 100644 --- a/java/com/android/voicemail/impl/sms/LegacyModeSmsHandler.java +++ b/java/com/android/voicemail/impl/sms/LegacyModeSmsHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 Google Inc. All Rights Reserved. + * Copyright (C) 2016 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. @@ -16,13 +16,21 @@ package com.android.voicemail.impl.sms; +import android.annotation.TargetApi; +import android.app.PendingIntent; import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Build.VERSION_CODES; import android.os.Bundle; +import android.support.annotation.Nullable; +import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; +import android.telephony.TelephonyManager; import android.telephony.VisualVoicemailSms; +import com.android.voicemail.VoicemailClient; import com.android.voicemail.impl.OmtpConstants; import com.android.voicemail.impl.OmtpVvmCarrierConfigHelper; -import com.android.voicemail.impl.TelephonyManagerStub; import com.android.voicemail.impl.VvmLog; /** @@ -30,37 +38,95 @@ import com.android.voicemail.impl.VvmLog; * * @see OmtpVvmCarrierConfigHelper#isLegacyModeEnabled() */ +@TargetApi(VERSION_CODES.O) public class LegacyModeSmsHandler { private static final String TAG = "LegacyModeSmsHandler"; + private static final int CALL_VOICEMAIL_REQUEST_CODE = 1; + private static final int LAUNCH_VOICEMAIL_SETTINGS_REQUEST_CODE = 2; + public static void handle(Context context, VisualVoicemailSms sms) { - VvmLog.v(TAG, "processing VVM SMS on legacy mode"); + VvmLog.i(TAG, "processing VVM SMS on legacy mode"); String eventType = sms.getPrefix(); Bundle data = sms.getFields(); PhoneAccountHandle handle = sms.getPhoneAccountHandle(); if (eventType.equals(OmtpConstants.SYNC_SMS_PREFIX)) { SyncMessage message = new SyncMessage(data); - VvmLog.v( + VvmLog.i( TAG, "Received SYNC sms for " + handle + " with event " + message.getSyncTriggerEvent()); switch (message.getSyncTriggerEvent()) { case OmtpConstants.NEW_MESSAGE: case OmtpConstants.MAILBOX_UPDATE: - // The user has called into the voicemail and the new message count could - // change. - // For some carriers new message count could be set to 0 even if there are still - // unread messages, to clear the message waiting indicator. - VvmLog.v(TAG, "updating MWI"); - - // Setting voicemail message count to non-zero will show the telephony voicemail - // notification, and zero will clear it. - TelephonyManagerStub.showVoicemailNotification(message.getNewMessageCount()); + sendLegacyVoicemailNotification(context, handle, message.getNewMessageCount()); + break; default: break; } } } + + private static void sendLegacyVoicemailNotification( + Context context, PhoneAccountHandle phoneAccountHandle, int messageCount) { + // The user has called into the voicemail and the new message count could + // change. + // For some carriers new message count could be set to 0 even if there are still + // unread messages, to clear the message waiting indicator. + + VvmLog.i(TAG, "sending voicemail notification"); + 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 non-zero will show the telephony voicemail + // notification, and zero will clear it. + intent.putExtra(TelephonyManager.EXTRA_NOTIFICATION_COUNT, messageCount); + + String voicemailNumber = getVoicemailNumber(context, phoneAccountHandle); + PendingIntent callVoicemailPendingIntent = null; + PendingIntent launchVoicemailSettingsPendingIntent = null; + + if (voicemailNumber != null) { + callVoicemailPendingIntent = + PendingIntent.getActivity( + context, + CALL_VOICEMAIL_REQUEST_CODE, + new Intent( + Intent.ACTION_CALL, Uri.fromParts(PhoneAccount.SCHEME_VOICEMAIL, "", null)), + PendingIntent.FLAG_UPDATE_CURRENT); + } else { + Intent launchVoicemailSettingsIntent = + new Intent(TelephonyManager.ACTION_CONFIGURE_VOICEMAIL); + launchVoicemailSettingsIntent.putExtra(TelephonyManager.EXTRA_HIDE_PUBLIC_SETTINGS, true); + + launchVoicemailSettingsPendingIntent = + PendingIntent.getActivity( + context, + LAUNCH_VOICEMAIL_SETTINGS_REQUEST_CODE, + launchVoicemailSettingsIntent, + PendingIntent.FLAG_UPDATE_CURRENT); + } + + intent.putExtra(TelephonyManager.EXTRA_VOICEMAIL_NUMBER, voicemailNumber); + intent.putExtra(TelephonyManager.EXTRA_CALL_VOICEMAIL_INTENT, callVoicemailPendingIntent); + intent.putExtra( + TelephonyManager.EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT, + launchVoicemailSettingsPendingIntent); + + context.sendBroadcast(intent); + } + + @Nullable + private static String getVoicemailNumber(Context context, PhoneAccountHandle phoneAccountHandle) { + TelephonyManager telephonyManager = + context + .getSystemService(TelephonyManager.class) + .createForPhoneAccountHandle(phoneAccountHandle); + if (telephonyManager == null) { + return null; + } + return telephonyManager.getVoiceMailNumber(); + } } diff --git a/java/com/android/voicemail/impl/sync/OmtpVvmSyncService.java b/java/com/android/voicemail/impl/sync/OmtpVvmSyncService.java index 83a3960dd..af934dd3c 100644 --- a/java/com/android/voicemail/impl/sync/OmtpVvmSyncService.java +++ b/java/com/android/voicemail/impl/sync/OmtpVvmSyncService.java @@ -24,8 +24,7 @@ import android.support.v4.os.BuildCompat; import android.telecom.PhoneAccountHandle; import android.text.TextUtils; import android.util.ArrayMap; -import com.android.dialer.logging.Logger; -import com.android.dialer.logging.nano.DialerImpression; +import com.android.dialer.logging.DialerImpression; import com.android.voicemail.VoicemailComponent; import com.android.voicemail.impl.ActivationTask; import com.android.voicemail.impl.Assert; @@ -41,6 +40,7 @@ import com.android.voicemail.impl.scheduling.BaseTask; import com.android.voicemail.impl.settings.VisualVoicemailSettingsUtil; import com.android.voicemail.impl.sync.VvmNetworkRequest.NetworkWrapper; import com.android.voicemail.impl.sync.VvmNetworkRequest.RequestFailedException; +import com.android.voicemail.impl.utils.LoggerUtils; import com.android.voicemail.impl.utils.VoicemailDatabaseUtil; import java.util.List; import java.util.Map; @@ -98,7 +98,7 @@ public class OmtpVvmSyncService { } OmtpVvmCarrierConfigHelper config = new OmtpVvmCarrierConfigHelper(mContext, phoneAccount); - Logger.get(mContext).logImpression(DialerImpression.Type.VVM_SYNC_STARTED); + LoggerUtils.logImpressionOnMainThread(mContext, DialerImpression.Type.VVM_SYNC_STARTED); // DATA_IMAP_OPERATION_STARTED posting should not be deferred. This event clears all data // channel errors, which should happen when the task starts, not when it ends. It is the // "Sync in progress..." status. @@ -136,7 +136,7 @@ public class OmtpVvmSyncService { imapHelper.updateQuota(); autoDeleteAndArchiveVM(imapHelper, phoneAccount); imapHelper.handleEvent(OmtpEvents.DATA_IMAP_OPERATION_COMPLETED); - Logger.get(mContext).logImpression(DialerImpression.Type.VVM_SYNC_COMPLETED); + LoggerUtils.logImpressionOnMainThread(mContext, DialerImpression.Type.VVM_SYNC_COMPLETED); } else { task.fail(); } @@ -158,14 +158,15 @@ public class OmtpVvmSyncService { > AUTO_DELETE_ARCHIVE_VM_THRESHOLD) { deleteAndArchiveVM(imapHelper); imapHelper.updateQuota(); - Logger.get(mContext) - .logImpression(DialerImpression.Type.VVM_ARCHIVE_AUTO_DELETED_VM_FROM_SERVER); + 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 { - VvmLog.i(TAG, "isArchiveAllowedAndEnabled is false"); - Logger.get(mContext).logImpression(DialerImpression.Type.VVM_ARCHIVE_AUTO_DELETE_TURNED_OFF); + VvmLog.i(TAG, "autoDeleteAndArchiveVM is turned off"); + LoggerUtils.logImpressionOnMainThread( + mContext, DialerImpression.Type.VVM_ARCHIVE_AUTO_DELETE_TURNED_OFF); } } @@ -214,7 +215,7 @@ public class OmtpVvmSyncService { boolean downloadSuccess = true; if (SYNC_FULL_SYNC.equals(action) || SYNC_UPLOAD_ONLY.equals(action)) { - uploadSuccess = upload(imapHelper); + uploadSuccess = upload(account, imapHelper); } if (SYNC_FULL_SYNC.equals(action) || SYNC_DOWNLOAD_ONLY.equals(action)) { downloadSuccess = download(imapHelper, account); @@ -242,9 +243,9 @@ public class OmtpVvmSyncService { new TranscriptionFetchedCallback(mContext, voicemail), voicemail.getSourceData()); } - private boolean upload(ImapHelper imapHelper) { - List readVoicemails = mQueryHelper.getReadVoicemails(); - List deletedVoicemails = mQueryHelper.getDeletedVoicemails(); + private boolean upload(PhoneAccountHandle phoneAccountHandle, ImapHelper imapHelper) { + List readVoicemails = mQueryHelper.getReadVoicemails(phoneAccountHandle); + List deletedVoicemails = mQueryHelper.getDeletedVoicemails(phoneAccountHandle); boolean success = true; @@ -271,7 +272,7 @@ public class OmtpVvmSyncService { private boolean download(ImapHelper imapHelper, PhoneAccountHandle account) { List serverVoicemails = imapHelper.fetchAllVoicemails(); - List localVoicemails = mQueryHelper.getAllVoicemails(); + List localVoicemails = mQueryHelper.getAllVoicemails(account); if (localVoicemails == null || serverVoicemails == null) { // Null value means the query failed. @@ -302,7 +303,8 @@ public class OmtpVvmSyncService { if (!TextUtils.isEmpty(remoteVoicemail.getTranscription()) && TextUtils.isEmpty(localVoicemail.getTranscription())) { - Logger.get(mContext).logImpression(DialerImpression.Type.VVM_TRANSCRIPTION_DOWNLOADED); + LoggerUtils.logImpressionOnMainThread( + mContext, DialerImpression.Type.VVM_TRANSCRIPTION_DOWNLOADED); mQueryHelper.updateWithTranscription(localVoicemail, remoteVoicemail.getTranscription()); } } @@ -312,7 +314,8 @@ public class OmtpVvmSyncService { boolean prefetchEnabled = shouldPerformPrefetch(account, imapHelper); for (Voicemail remoteVoicemail : remoteMap.values()) { if (!TextUtils.isEmpty(remoteVoicemail.getTranscription())) { - Logger.get(mContext).logImpression(DialerImpression.Type.VVM_TRANSCRIPTION_DOWNLOADED); + LoggerUtils.logImpressionOnMainThread( + mContext, DialerImpression.Type.VVM_TRANSCRIPTION_DOWNLOADED); } Uri uri = VoicemailDatabaseUtil.insert(mContext, remoteVoicemail); if (prefetchEnabled) { diff --git a/java/com/android/voicemail/impl/sync/SyncOneTask.java b/java/com/android/voicemail/impl/sync/SyncOneTask.java index e57235e4b..19419ec8a 100644 --- a/java/com/android/voicemail/impl/sync/SyncOneTask.java +++ b/java/com/android/voicemail/impl/sync/SyncOneTask.java @@ -18,18 +18,21 @@ package com.android.voicemail.impl.sync; import android.content.Context; import android.content.Intent; +import android.os.Bundle; import android.telecom.PhoneAccountHandle; -import com.android.dialer.logging.Logger; -import com.android.dialer.logging.nano.DialerImpression; +import com.android.dialer.logging.DialerImpression; +import com.android.dialer.proguard.UsedByReflection; import com.android.voicemail.impl.Voicemail; import com.android.voicemail.impl.VoicemailStatus; import com.android.voicemail.impl.scheduling.BaseTask; import com.android.voicemail.impl.scheduling.RetryPolicy; +import com.android.voicemail.impl.utils.LoggerUtils; /** * Task to download a single voicemail from the server. This task is initiated by a SMS notifying * the new voicemail arrival, and ignores the duplicated tasks constraint. */ +@UsedByReflection(value = "Tasks.java") public class SyncOneTask extends BaseTask { private static final int RETRY_TIMES = 2; @@ -56,11 +59,12 @@ public class SyncOneTask extends BaseTask { addPolicy(new RetryPolicy(RETRY_TIMES, RETRY_INTERVAL_MILLIS)); } - public void onCreate(Context context, Intent intent, int flags, int startId) { - super.onCreate(context, intent, flags, startId); - mPhone = intent.getParcelableExtra(EXTRA_PHONE_ACCOUNT_HANDLE); - mSyncType = intent.getStringExtra(EXTRA_SYNC_TYPE); - mVoicemail = intent.getParcelableExtra(EXTRA_VOICEMAIL); + @Override + public void onCreate(Context context, Bundle extras) { + super.onCreate(context, extras); + mPhone = extras.getParcelable(EXTRA_PHONE_ACCOUNT_HANDLE); + mSyncType = extras.getString(EXTRA_SYNC_TYPE); + mVoicemail = extras.getParcelable(EXTRA_VOICEMAIL); } @Override @@ -71,7 +75,7 @@ public class SyncOneTask extends BaseTask { @Override public Intent createRestartIntent() { - Logger.get(getContext()).logImpression(DialerImpression.Type.VVM_AUTO_RETRY_SYNC); + LoggerUtils.logImpressionOnMainThread(getContext(), DialerImpression.Type.VVM_AUTO_RETRY_SYNC); Intent intent = super.createRestartIntent(); intent.putExtra(EXTRA_PHONE_ACCOUNT_HANDLE, mPhone); intent.putExtra(EXTRA_SYNC_TYPE, mSyncType); diff --git a/java/com/android/voicemail/impl/sync/SyncTask.java b/java/com/android/voicemail/impl/sync/SyncTask.java index a9e592068..27f803401 100644 --- a/java/com/android/voicemail/impl/sync/SyncTask.java +++ b/java/com/android/voicemail/impl/sync/SyncTask.java @@ -18,14 +18,17 @@ package com.android.voicemail.impl.sync; import android.content.Context; import android.content.Intent; +import android.os.Bundle; import android.telecom.PhoneAccountHandle; -import com.android.dialer.logging.Logger; -import com.android.dialer.logging.nano.DialerImpression; +import com.android.dialer.logging.DialerImpression; +import com.android.dialer.proguard.UsedByReflection; import com.android.voicemail.impl.scheduling.BaseTask; import com.android.voicemail.impl.scheduling.MinimalIntervalPolicy; import com.android.voicemail.impl.scheduling.RetryPolicy; +import com.android.voicemail.impl.utils.LoggerUtils; /** System initiated sync request. */ +@UsedByReflection(value = "Tasks.java") public class SyncTask extends BaseTask { // Try sync for a total of 5 times, should take around 5 minutes before finally giving up. @@ -55,10 +58,11 @@ public class SyncTask extends BaseTask { addPolicy(new MinimalIntervalPolicy(MINIMAL_INTERVAL_MILLIS)); } - public void onCreate(Context context, Intent intent, int flags, int startId) { - super.onCreate(context, intent, flags, startId); - mPhone = intent.getParcelableExtra(EXTRA_PHONE_ACCOUNT_HANDLE); - mSyncType = intent.getStringExtra(EXTRA_SYNC_TYPE); + @Override + public void onCreate(Context context, Bundle extras) { + super.onCreate(context, extras); + mPhone = extras.getParcelable(EXTRA_PHONE_ACCOUNT_HANDLE); + mSyncType = extras.getString(EXTRA_SYNC_TYPE); } @Override @@ -69,7 +73,7 @@ public class SyncTask extends BaseTask { @Override public Intent createRestartIntent() { - Logger.get(getContext()).logImpression(DialerImpression.Type.VVM_AUTO_RETRY_SYNC); + LoggerUtils.logImpressionOnMainThread(getContext(), DialerImpression.Type.VVM_AUTO_RETRY_SYNC); Intent intent = super.createRestartIntent(); intent.putExtra(EXTRA_PHONE_ACCOUNT_HANDLE, mPhone); intent.putExtra(EXTRA_SYNC_TYPE, mSyncType); diff --git a/java/com/android/voicemail/impl/sync/UploadTask.java b/java/com/android/voicemail/impl/sync/UploadTask.java index 7d1a79756..403074572 100644 --- a/java/com/android/voicemail/impl/sync/UploadTask.java +++ b/java/com/android/voicemail/impl/sync/UploadTask.java @@ -18,7 +18,9 @@ package com.android.voicemail.impl.sync; import android.content.Context; import android.content.Intent; +import android.os.Bundle; import android.telecom.PhoneAccountHandle; +import com.android.dialer.proguard.UsedByReflection; import com.android.voicemail.impl.VoicemailStatus; import com.android.voicemail.impl.VvmLog; import com.android.voicemail.impl.scheduling.BaseTask; @@ -28,6 +30,7 @@ import com.android.voicemail.impl.scheduling.PostponePolicy; * Upload task triggered by database changes. Will wait until the database has been stable for * {@link #POSTPONE_MILLIS} to execute. */ +@UsedByReflection(value = "Tasks.java") public class UploadTask extends BaseTask { private static final String TAG = "VvmUploadTask"; @@ -45,8 +48,8 @@ public class UploadTask extends BaseTask { } @Override - public void onCreate(Context context, Intent intent, int flags, int startId) { - super.onCreate(context, intent, flags, startId); + public void onCreate(Context context, Bundle extras) { + super.onCreate(context, extras); } @Override diff --git a/java/com/android/voicemail/impl/sync/VoicemailsQueryHelper.java b/java/com/android/voicemail/impl/sync/VoicemailsQueryHelper.java index fc8119a80..bfc2e5f20 100644 --- a/java/com/android/voicemail/impl/sync/VoicemailsQueryHelper.java +++ b/java/com/android/voicemail/impl/sync/VoicemailsQueryHelper.java @@ -25,7 +25,9 @@ import android.net.Uri; import android.os.Build.VERSION_CODES; 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; @@ -52,6 +54,12 @@ 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; @@ -68,8 +76,8 @@ public class VoicemailsQueryHelper { * * @return A list of read voicemails. */ - public List getReadVoicemails() { - return getLocalVoicemails(READ_SELECTION); + public List getReadVoicemails(@NonNull PhoneAccountHandle phoneAccountHandle) { + return getLocalVoicemails(phoneAccountHandle, READ_SELECTION); } /** @@ -77,8 +85,8 @@ public class VoicemailsQueryHelper { * * @return A list of deleted voicemails. */ - public List getDeletedVoicemails() { - return getLocalVoicemails(DELETED_SELECTION); + public List getDeletedVoicemails(@NonNull PhoneAccountHandle phoneAccountHandle) { + return getLocalVoicemails(phoneAccountHandle, DELETED_SELECTION); } /** @@ -86,8 +94,8 @@ public class VoicemailsQueryHelper { * * @return A list of all locally stored voicemails. */ - public List getAllVoicemails() { - return getLocalVoicemails(null); + public List getAllVoicemails(@NonNull PhoneAccountHandle phoneAccountHandle) { + return getLocalVoicemails(phoneAccountHandle, null); } /** @@ -96,8 +104,20 @@ public class VoicemailsQueryHelper { * @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(String selection) { - Cursor cursor = mContentResolver.query(mSourceUri, PROJECTION, selection, null, null); + 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); if (cursor == null) { return null; } diff --git a/java/com/android/voicemail/impl/utils/LoggerUtils.java b/java/com/android/voicemail/impl/utils/LoggerUtils.java new file mode 100644 index 000000000..070772f2f --- /dev/null +++ b/java/com/android/voicemail/impl/utils/LoggerUtils.java @@ -0,0 +1,33 @@ +/* + * 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.utils; + +import android.content.Context; +import android.support.annotation.AnyThread; +import com.android.dialer.common.concurrent.ThreadUtil; +import com.android.dialer.logging.DialerImpression; +import com.android.dialer.logging.Logger; + +/** Common utility method when using {@link Logger} */ +public class LoggerUtils { + + /** Posts the impression logging to the main thread so it will be thread safe. */ + @AnyThread + public static void logImpressionOnMainThread(Context context, DialerImpression.Type impression) { + ThreadUtil.postOnUiThread(() -> Logger.get(context).logImpression(impression)); + } +} -- cgit v1.2.3