diff options
Diffstat (limited to 'java/com/android/voicemail')
10 files changed, 224 insertions, 61 deletions
diff --git a/java/com/android/voicemail/impl/ActivationTask.java b/java/com/android/voicemail/impl/ActivationTask.java index 91e369531..6e27b5015 100644 --- a/java/com/android/voicemail/impl/ActivationTask.java +++ b/java/com/android/voicemail/impl/ActivationTask.java @@ -19,11 +19,9 @@ package com.android.voicemail.impl; import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; -import android.database.ContentObserver; import android.os.Build.VERSION_CODES; import android.os.Bundle; import android.provider.Settings; -import android.provider.Settings.Global; import android.support.annotation.Nullable; import android.support.annotation.WorkerThread; import android.telecom.PhoneAccountHandle; @@ -43,8 +41,6 @@ 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; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -67,8 +63,6 @@ public class ActivationTask extends BaseTask { private static final String EXTRA_MESSAGE_DATA_BUNDLE = "extra_message_data_bundle"; - @Nullable private static DeviceProvisionedObserver sDeviceProvisionedObserver; - private final RetryPolicy mRetryPolicy; private Bundle mMessageData; @@ -98,7 +92,7 @@ public class ActivationTask extends BaseTask { // Activation might need information such as system language to be set, so wait until // the setup wizard is finished. The data bundle from the SMS will be re-requested upon // activation. - queueActivationAfterProvisioned(context, phoneAccountHandle); + DeviceProvisionedJobService.activateAfterProvisioned(context, phoneAccountHandle); return; } @@ -285,45 +279,4 @@ public class ActivationTask extends BaseTask { .createForPhoneAccountHandle(phoneAccountHandle); return telephonyManager.getServiceState().getState() == ServiceState.STATE_IN_SERVICE; } - - private static void queueActivationAfterProvisioned( - Context context, PhoneAccountHandle phoneAccountHandle) { - if (sDeviceProvisionedObserver == null) { - sDeviceProvisionedObserver = new DeviceProvisionedObserver(context); - context - .getContentResolver() - .registerContentObserver( - Settings.Global.getUriFor(Global.DEVICE_PROVISIONED), - false, - sDeviceProvisionedObserver); - } - sDeviceProvisionedObserver.addPhoneAcountHandle(phoneAccountHandle); - } - - private static class DeviceProvisionedObserver extends ContentObserver { - - private final Context mContext; - private final Set<PhoneAccountHandle> mPhoneAccountHandles = new HashSet<>(); - - private DeviceProvisionedObserver(Context context) { - super(null); - mContext = context; - } - - public void addPhoneAcountHandle(PhoneAccountHandle phoneAccountHandle) { - mPhoneAccountHandles.add(phoneAccountHandle); - } - - @Override - public void onChange(boolean selfChange) { - if (isDeviceProvisioned(mContext)) { - VvmLog.i(TAG, "device provisioned, resuming activation"); - for (PhoneAccountHandle phoneAccountHandle : mPhoneAccountHandles) { - start(mContext, phoneAccountHandle, null); - } - mContext.getContentResolver().unregisterContentObserver(sDeviceProvisionedObserver); - sDeviceProvisionedObserver = null; - } - } - } } diff --git a/java/com/android/voicemail/impl/AndroidManifest.xml b/java/com/android/voicemail/impl/AndroidManifest.xml index 8c0d67f6b..3e512ba1e 100644 --- a/java/com/android/voicemail/impl/AndroidManifest.xml +++ b/java/com/android/voicemail/impl/AndroidManifest.xml @@ -92,6 +92,11 @@ android:exported="false"/> <service + android:name="com.android.voicemail.impl.DeviceProvisionedJobService" + android:permission="android.permission.BIND_JOB_SERVICE" + android:exported="false"/> + + <service android:name="com.android.voicemail.impl.OmtpService" android:permission="android.permission.BIND_VISUAL_VOICEMAIL_SERVICE" android:exported="true" diff --git a/java/com/android/voicemail/impl/DeviceProvisionedJobService.java b/java/com/android/voicemail/impl/DeviceProvisionedJobService.java new file mode 100644 index 000000000..a0b999d23 --- /dev/null +++ b/java/com/android/voicemail/impl/DeviceProvisionedJobService.java @@ -0,0 +1,85 @@ +/* + * 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.JobInfo.TriggerContentUri; +import android.app.job.JobParameters; +import android.app.job.JobScheduler; +import android.app.job.JobService; +import android.app.job.JobWorkItem; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.os.Build.VERSION_CODES; +import android.provider.Settings; +import android.provider.Settings.Global; +import android.telecom.PhoneAccountHandle; +import com.android.dialer.constants.ScheduledJobIds; + +/** + * JobService triggered when the setup wizard is completed, and rerun all {@link ActivationTask} + * scheduled during the setup. + */ +@TargetApi(VERSION_CODES.O) +public class DeviceProvisionedJobService extends JobService { + + private static final String EXTRA_PHONE_ACCOUNT_HANDLE = "EXTRA_PHONE_ACCOUNT_HANDLE"; + + /** Queue the phone account to be reactivated after the setup wizard has completed. */ + public static void activateAfterProvisioned( + Context context, PhoneAccountHandle phoneAccountHandle) { + JobInfo jobInfo = + new JobInfo.Builder( + ScheduledJobIds.VVM_DEVICE_PROVISIONED_JOB, + new ComponentName(context, DeviceProvisionedJobService.class)) + .addTriggerContentUri( + new TriggerContentUri(Global.getUriFor(Global.DEVICE_PROVISIONED), 0)) + // VVM activation must be run as soon as possible to avoid voicemail loss + .setTriggerContentMaxDelay(0) + .build(); + + Intent intent = new Intent(); + intent.putExtra(EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle); + context.getSystemService(JobScheduler.class).enqueue(jobInfo, new JobWorkItem(intent)); + } + + @Override + public boolean onStartJob(JobParameters params) { + Assert.isTrue(isDeviceProvisioned()); + VvmLog.i("DeviceProvisionedJobService.onStartJob", "device provisioned"); + for (JobWorkItem item = params.dequeueWork(); item != null; item = params.dequeueWork()) { + PhoneAccountHandle phoneAccountHandle = + item.getIntent().getParcelableExtra(EXTRA_PHONE_ACCOUNT_HANDLE); + VvmLog.i( + "DeviceProvisionedJobService.onStartJob", + "restarting activation for " + phoneAccountHandle); + ActivationTask.start(this, phoneAccountHandle, null); + } + return false; // job not running in background + } + + @Override + public boolean onStopJob(JobParameters params) { + return true; // reschedule job + } + + private boolean isDeviceProvisioned() { + return Settings.Global.getInt(getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) == 1; + } +} diff --git a/java/com/android/voicemail/impl/OmtpService.java b/java/com/android/voicemail/impl/OmtpService.java index ad24e1243..759be4fd1 100644 --- a/java/com/android/voicemail/impl/OmtpService.java +++ b/java/com/android/voicemail/impl/OmtpService.java @@ -27,6 +27,7 @@ import com.android.dialer.logging.DialerImpression; import com.android.dialer.logging.Logger; import com.android.voicemail.VoicemailComponent; import com.android.voicemail.impl.settings.VisualVoicemailSettingsUtil; +import com.android.voicemail.impl.sms.LegacyModeSmsHandler; import com.android.voicemail.impl.sync.VvmAccountManager; /** Implements {@link VisualVoicemailService} to receive visual voicemail events */ @@ -74,6 +75,11 @@ public class OmtpService extends VisualVoicemailService { return; } + if (!isUserUnlocked()) { + LegacyModeSmsHandler.handle(this, sms); + return; + } + VvmPackageInstallHandler.scanNewPackages(this); if (!isServiceEnabled(sms.getPhoneAccountHandle())) { diff --git a/java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java b/java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java index 04b3e73da..4a9e43370 100644 --- a/java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java +++ b/java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java @@ -107,8 +107,7 @@ public class OmtpVvmCarrierConfigHelper { mCarrierConfig = getCarrierConfig(telephonyManager); mTelephonyConfig = - new TelephonyVvmConfigManager(context.getResources()) - .getConfig(telephonyManager.getSimOperator()); + new TelephonyVvmConfigManager(context).getConfig(telephonyManager.getSimOperator()); mVvmType = getVvmType(); mProtocol = VisualVoicemailProtocolFactory.create(mContext.getResources(), mVvmType); diff --git a/java/com/android/voicemail/impl/TelephonyVvmConfigManager.java b/java/com/android/voicemail/impl/TelephonyVvmConfigManager.java index 04012c9c2..b4def2fc3 100644 --- a/java/com/android/voicemail/impl/TelephonyVvmConfigManager.java +++ b/java/com/android/voicemail/impl/TelephonyVvmConfigManager.java @@ -16,11 +16,12 @@ package com.android.voicemail.impl; -import android.content.res.Resources; +import android.content.Context; import android.os.PersistableBundle; import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; import android.util.ArrayMap; +import com.android.dialer.common.ConfigProviderBindings; import com.android.voicemail.impl.utils.XmlUtils; import java.io.IOException; import java.util.ArrayList; @@ -38,22 +39,24 @@ public class TelephonyVvmConfigManager { private static final String TAG_PERSISTABLEMAP = "pbundle_as_map"; - static final String KEY_MCCMNC = "mccmnc"; + @VisibleForTesting static final String KEY_MCCMNC = "mccmnc"; + + private static final String KEY_FEATURE_FLAG_NAME = "feature_flag_name"; private static Map<String, PersistableBundle> sCachedConfigs; private final Map<String, PersistableBundle> mConfigs; - public TelephonyVvmConfigManager(Resources resources) { + public TelephonyVvmConfigManager(Context context) { if (sCachedConfigs == null) { - sCachedConfigs = loadConfigs(resources.getXml(R.xml.vvm_config)); + sCachedConfigs = loadConfigs(context, context.getResources().getXml(R.xml.vvm_config)); } mConfigs = sCachedConfigs; } @VisibleForTesting - TelephonyVvmConfigManager(XmlPullParser parser) { - mConfigs = loadConfigs(parser); + TelephonyVvmConfigManager(Context context, XmlPullParser parser) { + mConfigs = loadConfigs(context, parser); } @Nullable @@ -64,7 +67,7 @@ public class TelephonyVvmConfigManager { return mConfigs.get(mccMnc); } - private static Map<String, PersistableBundle> loadConfigs(XmlPullParser parser) { + private static Map<String, PersistableBundle> loadConfigs(Context context, XmlPullParser parser) { Map<String, PersistableBundle> configs = new ArrayMap<>(); try { ArrayList list = readBundleList(parser); @@ -73,6 +76,13 @@ public class TelephonyVvmConfigManager { throw new IllegalArgumentException("PersistableBundle expected, got " + object); } PersistableBundle bundle = (PersistableBundle) object; + + if (bundle.containsKey(KEY_FEATURE_FLAG_NAME) + && !ConfigProviderBindings.get(context) + .getBoolean(bundle.getString(KEY_FEATURE_FLAG_NAME), false)) { + continue; + } + String[] mccMncs = bundle.getStringArray(KEY_MCCMNC); if (mccMncs == null) { throw new IllegalArgumentException("MCCMNC is null"); diff --git a/java/com/android/voicemail/impl/res/xml/vvm_config.xml b/java/com/android/voicemail/impl/res/xml/vvm_config.xml index 230d40f90..daba3d511 100644 --- a/java/com/android/voicemail/impl/res/xml/vvm_config.xml +++ b/java/com/android/voicemail/impl/res/xml/vvm_config.xml @@ -23,6 +23,30 @@ </pbundle_as_map> <pbundle_as_map> + <!-- Orange Belgium --> + <string name="feature_flag_name">vvm_carrier_flag_20610</string> + <string-array name="mccmnc"> + <item value="20610"/> + </string-array> + + <int + name="vvm_port_number_int" + value="0"/> + <string name="vvm_destination_number_string">8082</string> + <string-array name="carrier_vvm_package_name_string_array"> + <item value="com.orange.vvm"/> + </string-array> + <string name="vvm_type_string">vvm_type_omtp</string> + <boolean + name="vvm_cellular_data_required_bool" + value="true"/> + <string-array name="vvm_disabled_capabilities_string_array"> + <!-- b/32365569 --> + <item value="STARTTLS"/> + </string-array> + </pbundle_as_map> + + <pbundle_as_map> <!-- Orange France --> <string-array name="mccmnc"> <item value="20801"/> @@ -47,6 +71,30 @@ </pbundle_as_map> <pbundle_as_map> + <!-- Orange Luxembourg --> + <string name="feature_flag_name">vvm_carrier_flag_20610</string> + <string-array name="mccmnc"> + <item value="27099"/> + </string-array> + + <int + name="vvm_port_number_int" + value="0"/> + <string name="vvm_destination_number_string">64085</string> + <string-array name="carrier_vvm_package_name_string_array"> + <item value="com.orange.vvm"/> + </string-array> + <string name="vvm_type_string">vvm_type_omtp</string> + <boolean + name="vvm_cellular_data_required_bool" + value="true"/> + <string-array name="vvm_disabled_capabilities_string_array"> + <!-- b/32365569 --> + <item value="STARTTLS"/> + </string-array> + </pbundle_as_map> + + <pbundle_as_map> <!-- T-Mobile USA--> <string-array name="mccmnc"> <item value="310160"/> @@ -86,6 +134,22 @@ </pbundle_as_map> <pbundle_as_map> + <!-- Telus Canada --> + <string name="feature_flag_name">vvm_carrier_flag_302220</string> + <string-array name="mccmnc"> + <item value="302220"/> + </string-array> + <int + name="vvm_port_number_int" + value="5499"/> + <string name="vvm_destination_number_string">7723</string> + <string name="vvm_type_string">vvm_type_omtp</string> + <boolean + name="vvm_cellular_data_required_bool" + value="true"/> + </pbundle_as_map> + + <pbundle_as_map> <!-- Verizon USA --> <string-array name="mccmnc"> <item value="310004"/> diff --git a/java/com/android/voicemail/impl/scheduling/TaskExecutor.java b/java/com/android/voicemail/impl/scheduling/TaskExecutor.java index 84dc1db4a..e3b718e50 100644 --- a/java/com/android/voicemail/impl/scheduling/TaskExecutor.java +++ b/java/com/android/voicemail/impl/scheduling/TaskExecutor.java @@ -193,13 +193,13 @@ final class TaskExecutor { /** Should attempt to run the next task when a task has finished or been added. */ private boolean taskAutoRunDisabledForTesting = false; + /** Handles execution of the background task in teh worker thread. */ @VisibleForTesting final class WorkerThreadHandler extends Handler { public WorkerThreadHandler(Looper looper) { super(looper); } - @Override @WorkerThread public void handleMessage(Message msg) { @@ -218,6 +218,7 @@ final class TaskExecutor { } } + /** Handles completion of the background task in the main thread. */ @VisibleForTesting final class MainThreadHandler extends Handler { @@ -233,6 +234,11 @@ final class TaskExecutor { getTasks().remove(task); task.onCompleted(); isWorkerThreadBusy = false; + if (!isJobRunning() || isTerminating()) { + // TaskExecutor was terminated when the task is running in background, don't need to run the + // next task or terminate again + return; + } maybeRunNextTask(); } } @@ -290,6 +296,7 @@ final class TaskExecutor { @MainThread private void maybeRunNextTask() { Assert.isMainThread(); + if (isWorkerThreadBusy) { return; } diff --git a/java/com/android/voicemail/impl/scheduling/TaskReceiver.java b/java/com/android/voicemail/impl/scheduling/TaskReceiver.java index 00d36d00f..e78dcf72c 100644 --- a/java/com/android/voicemail/impl/scheduling/TaskReceiver.java +++ b/java/com/android/voicemail/impl/scheduling/TaskReceiver.java @@ -49,6 +49,7 @@ public class TaskReceiver extends BroadcastReceiver { for (Intent intent : deferredBroadcasts) { context.sendBroadcast(intent); } + deferredBroadcasts.clear(); } @Override @@ -68,13 +69,13 @@ public class TaskReceiver extends BroadcastReceiver { deferredBroadcasts.add(intent); return; } - Task task = Tasks.createTask(context, intent.getExtras()); + Task task = Tasks.createTask(context.getApplicationContext(), intent.getExtras()); taskExecutor.addTask(task); } else { VvmLog.i(TAG, "scheduling new job"); List<Bundle> taskList = new ArrayList<>(); taskList.add(intent.getExtras()); - TaskSchedulerJobService.scheduleJob(context, taskList, 0, true); + TaskSchedulerJobService.scheduleJob(context.getApplicationContext(), taskList, 0, true); } } } diff --git a/java/com/android/voicemail/impl/scheduling/TaskSchedulerJobService.java b/java/com/android/voicemail/impl/scheduling/TaskSchedulerJobService.java index 9bfce0052..107234edc 100644 --- a/java/com/android/voicemail/impl/scheduling/TaskSchedulerJobService.java +++ b/java/com/android/voicemail/impl/scheduling/TaskSchedulerJobService.java @@ -23,9 +23,11 @@ import android.app.job.JobScheduler; import android.app.job.JobService; import android.content.ComponentName; import android.content.Context; +import android.content.SharedPreferences; import android.os.Build.VERSION_CODES; import android.os.Bundle; import android.os.Parcelable; +import android.preference.PreferenceManager; import android.support.annotation.MainThread; import com.android.dialer.constants.ScheduledJobIds; import com.android.voicemail.impl.Assert; @@ -41,11 +43,28 @@ public class TaskSchedulerJobService extends JobService implements TaskExecutor. private static final String EXTRA_TASK_EXTRAS_ARRAY = "extra_task_extras_array"; + private static final String EXTRA_JOB_ID = "extra_job_id"; + + private static final String EXPECTED_JOB_ID = + "com.android.voicemail.impl.scheduling.TaskSchedulerJobService.EXPECTED_JOB_ID"; + + private static final String NEXT_JOB_ID = + "com.android.voicemail.impl.scheduling.TaskSchedulerJobService.NEXT_JOB_ID"; + private JobParameters jobParameters; @Override @MainThread public boolean onStartJob(JobParameters params) { + int jobId = params.getTransientExtras().getInt(EXTRA_JOB_ID); + int expectedJobId = + PreferenceManager.getDefaultSharedPreferences(this).getInt(EXPECTED_JOB_ID, 0); + if (jobId != expectedJobId) { + VvmLog.e( + TAG, "Job " + jobId + " is not the last scheduled job " + expectedJobId + ", ignoring"); + return false; // nothing more to do. Job not running in background. + } + VvmLog.i(TAG, "starting " + jobId); jobParameters = params; TaskExecutor.createRunningInstance(this); TaskExecutor.getRunningInstance() @@ -97,6 +116,13 @@ public class TaskSchedulerJobService extends JobService implements TaskExecutor. jobScheduler.cancel(ScheduledJobIds.VVM_TASK_SCHEDULER_JOB); } Bundle extras = new Bundle(); + int jobId = createJobId(context); + extras.putInt(EXTRA_JOB_ID, jobId); + PreferenceManager.getDefaultSharedPreferences(context) + .edit() + .putInt(EXPECTED_JOB_ID, jobId) + .apply(); + extras.putParcelableArray( EXTRA_TASK_EXTRAS_ARRAY, pendingTasks.toArray(new Bundle[pendingTasks.size()])); JobInfo.Builder builder = @@ -112,7 +138,7 @@ public class TaskSchedulerJobService extends JobService implements TaskExecutor. VvmLog.i(TAG, "running job instantly."); } jobScheduler.schedule(builder.build()); - VvmLog.i(TAG, "job scheduled"); + VvmLog.i(TAG, "job " + jobId + " scheduled"); } /** @@ -143,4 +169,11 @@ public class TaskSchedulerJobService extends JobService implements TaskExecutor. } return result; } + + private static int createJobId(Context context) { + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); + int jobId = sharedPreferences.getInt(NEXT_JOB_ID, 0); + sharedPreferences.edit().putInt(NEXT_JOB_ID, jobId + 1).apply(); + return jobId; + } } |