diff options
Diffstat (limited to 'java/com/android/dialer/calllog/config/CallLogConfigImpl.java')
-rw-r--r-- | java/com/android/dialer/calllog/config/CallLogConfigImpl.java | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/java/com/android/dialer/calllog/config/CallLogConfigImpl.java b/java/com/android/dialer/calllog/config/CallLogConfigImpl.java new file mode 100644 index 000000000..9c7f472d5 --- /dev/null +++ b/java/com/android/dialer/calllog/config/CallLogConfigImpl.java @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.dialer.calllog.config; + +import android.annotation.SuppressLint; +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.SharedPreferences; +import android.support.v4.os.UserManagerCompat; +import com.android.dialer.calllog.CallLogFramework; +import com.android.dialer.common.Assert; +import com.android.dialer.common.LogUtil; +import com.android.dialer.common.concurrent.Annotations.BackgroundExecutor; +import com.android.dialer.common.concurrent.ThreadUtil; +import com.android.dialer.configprovider.ConfigProvider; +import com.android.dialer.constants.ScheduledJobIds; +import com.android.dialer.inject.ApplicationContext; +import com.android.dialer.storage.Unencrypted; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; +import java.util.concurrent.TimeUnit; +import javax.inject.Inject; + +/** + * Determines if new call log components are enabled. + * + * <p>When the underlying flag values from the {@link ConfigProvider} changes, it is necessary to do + * work such as registering/unregistering content observers, and this class is responsible for + * coordinating that work. + * + * <p>New UI application components should use this class instead of reading flags directly from the + * {@link ConfigProvider}. + */ +public final class CallLogConfigImpl implements CallLogConfig { + + private static final String NEW_CALL_LOG_FRAGMENT_ENABLED_PREF_KEY = "newCallLogFragmentEnabled"; + private static final String NEW_VOICEMAIL_FRAGMENT_ENABLED_PREF_KEY = + "newVoicemailFragmentEnabled"; + private static final String NEW_PEER_ENABLED_PREF_KEY = "newPeerEnabled"; + private static final String NEW_CALL_LOG_FRAMEWORK_ENABLED_PREF_KEY = + "newCallLogFrameworkEnabled"; + + private final Context appContext; + private final CallLogFramework callLogFramework; + private final SharedPreferences sharedPreferences; + private final ConfigProvider configProvider; + private final ListeningExecutorService backgroundExecutor; + + @Inject + public CallLogConfigImpl( + @ApplicationContext Context appContext, + CallLogFramework callLogFramework, + @Unencrypted SharedPreferences sharedPreferences, + ConfigProvider configProvider, + @BackgroundExecutor ListeningExecutorService backgroundExecutor) { + this.appContext = appContext; + this.callLogFramework = callLogFramework; + this.sharedPreferences = sharedPreferences; + this.configProvider = configProvider; + this.backgroundExecutor = backgroundExecutor; + } + + @Override + public ListenableFuture<Void> update() { + boolean newCallLogFragmentEnabledInConfigProvider = + configProvider.getBoolean("new_call_log_fragment_enabled", false); + boolean newVoicemailFragmentEnabledInConfigProvider = + configProvider.getBoolean("new_voicemail_fragment_enabled", false); + boolean newPeerEnabledInConfigProvider = configProvider.getBoolean("nui_peer_enabled", false); + + boolean isCallLogFrameworkEnabled = isCallLogFrameworkEnabled(); + boolean callLogFrameworkShouldBeEnabled = + newCallLogFragmentEnabledInConfigProvider + || newVoicemailFragmentEnabledInConfigProvider + || newPeerEnabledInConfigProvider; + + if (callLogFrameworkShouldBeEnabled && !isCallLogFrameworkEnabled) { + return Futures.transform( + callLogFramework.enable(), + unused -> { + // Reflect the flag changes only after the framework is enabled. + sharedPreferences + .edit() + .putBoolean( + NEW_CALL_LOG_FRAGMENT_ENABLED_PREF_KEY, + newCallLogFragmentEnabledInConfigProvider) + .putBoolean( + NEW_VOICEMAIL_FRAGMENT_ENABLED_PREF_KEY, + newVoicemailFragmentEnabledInConfigProvider) + .putBoolean(NEW_PEER_ENABLED_PREF_KEY, newPeerEnabledInConfigProvider) + .putBoolean(NEW_CALL_LOG_FRAMEWORK_ENABLED_PREF_KEY, true) + .apply(); + return null; + }, + backgroundExecutor); + } else if (!callLogFrameworkShouldBeEnabled && isCallLogFrameworkEnabled) { + // Reflect the flag changes before disabling the framework. + ListenableFuture<Void> writeSharedPrefsFuture = + backgroundExecutor.submit( + () -> { + sharedPreferences + .edit() + .putBoolean(NEW_CALL_LOG_FRAGMENT_ENABLED_PREF_KEY, false) + .putBoolean(NEW_VOICEMAIL_FRAGMENT_ENABLED_PREF_KEY, false) + .putBoolean(NEW_PEER_ENABLED_PREF_KEY, false) + .putBoolean(NEW_CALL_LOG_FRAMEWORK_ENABLED_PREF_KEY, false) + .apply(); + return null; + }); + return Futures.transformAsync( + writeSharedPrefsFuture, + unused -> callLogFramework.disable(), + MoreExecutors.directExecutor()); + } else { + // We didn't need to enable/disable the framework, but we still need to update the + // individual flags. + return backgroundExecutor.submit( + () -> { + sharedPreferences + .edit() + .putBoolean( + NEW_CALL_LOG_FRAGMENT_ENABLED_PREF_KEY, + newCallLogFragmentEnabledInConfigProvider) + .putBoolean( + NEW_VOICEMAIL_FRAGMENT_ENABLED_PREF_KEY, + newVoicemailFragmentEnabledInConfigProvider) + .putBoolean(NEW_PEER_ENABLED_PREF_KEY, newPeerEnabledInConfigProvider) + .apply(); + return null; + }); + } + } + + @Override + public boolean isNewCallLogFragmentEnabled() { + return sharedPreferences.getBoolean(NEW_CALL_LOG_FRAGMENT_ENABLED_PREF_KEY, false); + } + + @Override + public boolean isNewVoicemailFragmentEnabled() { + return sharedPreferences.getBoolean(NEW_VOICEMAIL_FRAGMENT_ENABLED_PREF_KEY, false); + } + + @Override + public boolean isNewPeerEnabled() { + return sharedPreferences.getBoolean(NEW_PEER_ENABLED_PREF_KEY, false); + } + + /** + * Returns true if the new call log framework is enabled, meaning that content observers are + * firing and PhoneLookupHistory is being populated, etc. + */ + @Override + public boolean isCallLogFrameworkEnabled() { + return sharedPreferences.getBoolean(NEW_CALL_LOG_FRAMEWORK_ENABLED_PREF_KEY, false); + } + + @Override + public void schedulePollingJob() { + if (UserManagerCompat.isUserUnlocked(appContext)) { + JobScheduler jobScheduler = Assert.isNotNull(appContext.getSystemService(JobScheduler.class)); + @SuppressLint("MissingPermission") // Dialer has RECEIVE_BOOT permission + JobInfo jobInfo = + new JobInfo.Builder( + ScheduledJobIds.CALL_LOG_CONFIG_POLLING_JOB, + new ComponentName(appContext, PollingJob.class)) + .setPeriodic(TimeUnit.HOURS.toMillis(24)) + .setPersisted(true) + .setRequiresCharging(true) + .setRequiresDeviceIdle(true) + .build(); + LogUtil.i("CallLogConfigImpl.schedulePollingJob", "scheduling"); + jobScheduler.schedule(jobInfo); + } + } + + /** + * Job which periodically force updates the {@link CallLogConfig}. This job is necessary to + * support {@link ConfigProvider ConfigProviders} which do not provide a reliable mechanism for + * listening to changes and calling {@link CallLogConfig#update()} directly, such as the {@link + * com.android.dialer.configprovider.SharedPrefConfigProvider}. + */ + public static final class PollingJob extends JobService { + + @Override + public boolean onStartJob(JobParameters params) { + LogUtil.enterBlock("PollingJob.onStartJob"); + Futures.addCallback( + CallLogConfigComponent.get(getApplicationContext()).callLogConfig().update(), + new FutureCallback<Void>() { + @Override + public void onSuccess(Void unused) { + jobFinished(params, false /* needsReschedule */); + } + + @Override + public void onFailure(Throwable throwable) { + ThreadUtil.getUiThreadHandler() + .post( + () -> { + throw new RuntimeException(throwable); + }); + jobFinished(params, false /* needsReschedule */); + } + }, + MoreExecutors.directExecutor()); + return true; + } + + @Override + public boolean onStopJob(JobParameters params) { + return false; + } + } +} |