diff options
Diffstat (limited to 'java/com/android/dialer/common')
8 files changed, 135 insertions, 219 deletions
diff --git a/java/com/android/dialer/common/Assert.java b/java/com/android/dialer/common/Assert.java index 943e1ddcf..2d7f199ab 100644 --- a/java/com/android/dialer/common/Assert.java +++ b/java/com/android/dialer/common/Assert.java @@ -59,6 +59,11 @@ public class Assert { } @CheckReturnValue + public static AssertionError createAssertionFailException(String msg, Throwable reason) { + return new AssertionError(msg, reason); + } + + @CheckReturnValue public static UnsupportedOperationException createUnsupportedOperationFailException() { return new UnsupportedOperationException(); } diff --git a/java/com/android/dialer/common/ConfigProvider.java b/java/com/android/dialer/common/ConfigProvider.java deleted file mode 100644 index c0791e979..000000000 --- a/java/com/android/dialer/common/ConfigProvider.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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. - * 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.common; - -/** Gets config values from the container application. */ -public interface ConfigProvider { - - String getString(String key, String defaultValue); - - long getLong(String key, long defaultValue); - - boolean getBoolean(String key, boolean defaultValue); -} diff --git a/java/com/android/dialer/common/ConfigProviderBindings.java b/java/com/android/dialer/common/ConfigProviderBindings.java deleted file mode 100644 index 9f045add4..000000000 --- a/java/com/android/dialer/common/ConfigProviderBindings.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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. - * 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.common; - -import android.content.Context; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.VisibleForTesting; -import android.support.v4.os.UserManagerCompat; - -/** Accessor for getting a {@link ConfigProvider}. */ -public class ConfigProviderBindings { - - private static ConfigProvider configProvider; - private static ConfigProvider configProviderStub; - - public static ConfigProvider get(@NonNull Context context) { - Assert.isNotNull(context); - if (configProvider != null) { - return configProvider; - } - if (!UserManagerCompat.isUserUnlocked(context)) { - if (configProviderStub == null) { - configProviderStub = new ConfigProviderStub(); - } - return configProviderStub; - } - - Context application = context.getApplicationContext(); - if (application instanceof ConfigProviderFactory) { - configProvider = ((ConfigProviderFactory) application).getConfigProvider(); - } - - if (configProvider == null) { - configProvider = new ConfigProviderStub(); - } - - return configProvider; - } - - @VisibleForTesting - public static void setForTesting(@Nullable ConfigProvider configProviderForTesting) { - configProvider = configProviderForTesting; - } - - private static class ConfigProviderStub implements ConfigProvider { - @Override - public String getString(String key, String defaultValue) { - return defaultValue; - } - - @Override - public long getLong(String key, long defaultValue) { - return defaultValue; - } - - @Override - public boolean getBoolean(String key, boolean defaultValue) { - return defaultValue; - } - } -} diff --git a/java/com/android/dialer/common/ConfigProviderFactory.java b/java/com/android/dialer/common/ConfigProviderFactory.java deleted file mode 100644 index aeb4f303a..000000000 --- a/java/com/android/dialer/common/ConfigProviderFactory.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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. - * 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.common; - -/** - * This interface should be implementated by the Application subclass. It allows dialer code to get - * references to a config provider. - */ -public interface ConfigProviderFactory { - - ConfigProvider getConfigProvider(); -} diff --git a/java/com/android/dialer/common/concurrent/DefaultDialerExecutorFactory.java b/java/com/android/dialer/common/concurrent/DefaultDialerExecutorFactory.java index 4b6d81afd..82e517d9a 100644 --- a/java/com/android/dialer/common/concurrent/DefaultDialerExecutorFactory.java +++ b/java/com/android/dialer/common/concurrent/DefaultDialerExecutorFactory.java @@ -17,6 +17,7 @@ package com.android.dialer.common.concurrent; import android.app.FragmentManager; +import android.os.AsyncTask; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import com.android.dialer.common.Assert; @@ -25,9 +26,13 @@ import com.android.dialer.common.concurrent.DialerExecutor.Builder; import com.android.dialer.common.concurrent.DialerExecutor.FailureListener; import com.android.dialer.common.concurrent.DialerExecutor.SuccessListener; import com.android.dialer.common.concurrent.DialerExecutor.Worker; +import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; import javax.inject.Inject; /** The production {@link DialerExecutorFactory}. */ @@ -62,16 +67,16 @@ public class DefaultDialerExecutorFactory implements DialerExecutorFactory { throwable -> { throw new RuntimeException(throwable); }; - @Nullable final ExecutorService serialExecutorService; - @Nullable final ExecutorService parallelExecutorService; + @Nullable final ScheduledExecutorService serialExecutorService; + @Nullable final Executor parallelExecutor; BaseTaskBuilder( Worker<InputT, OutputT> worker, - @Nullable ExecutorService serialExecutorService, - @Nullable ExecutorService parallelExecutorService) { + @Nullable ScheduledExecutorService serialExecutorService, + @Nullable Executor parallelExecutor) { this.worker = worker; this.serialExecutorService = serialExecutorService; - this.parallelExecutorService = parallelExecutorService; + this.parallelExecutor = parallelExecutor; } @NonNull @@ -91,6 +96,19 @@ public class DefaultDialerExecutorFactory implements DialerExecutorFactory { /** Convenience class for use by {@link DialerExecutorFactory} implementations. */ public static class UiTaskBuilder<InputT, OutputT> extends BaseTaskBuilder<InputT, OutputT> { + private static final ScheduledExecutorService defaultSerialExecutorService = + Executors.newSingleThreadScheduledExecutor( + new ThreadFactory() { + @Override + public Thread newThread(Runnable runnable) { + LogUtil.i("UiTaskBuilder.newThread", "creating serial thread"); + Thread thread = new Thread(runnable, "UiTaskBuilder-Serial"); + thread.setPriority(5); // Corresponds to Process.THREAD_PRIORITY_DEFAULT + return thread; + } + }); + + private static final Executor defaultParallelExecutorService = AsyncTask.THREAD_POOL_EXECUTOR; private final FragmentManager fragmentManager; private final String id; @@ -102,16 +120,16 @@ public class DefaultDialerExecutorFactory implements DialerExecutorFactory { fragmentManager, id, worker, - null /* serialExecutorService */, - null /* parallelExecutorService */); + defaultSerialExecutorService, + defaultParallelExecutorService); } public UiTaskBuilder( FragmentManager fragmentManager, String id, Worker<InputT, OutputT> worker, - ExecutorService serialExecutor, - ExecutorService parallelExecutor) { + ScheduledExecutorService serialExecutor, + Executor parallelExecutor) { super(worker, serialExecutor, parallelExecutor); this.fragmentManager = fragmentManager; this.id = id; @@ -128,46 +146,46 @@ public class DefaultDialerExecutorFactory implements DialerExecutorFactory { super.successListener, super.failureListener, serialExecutorService, - parallelExecutorService); + parallelExecutor); return new UiDialerExecutor<>(dialerUiTaskFragment); } } /** Convenience class for use by {@link DialerExecutorFactory} implementations. */ public static class NonUiTaskBuilder<InputT, OutputT> extends BaseTaskBuilder<InputT, OutputT> { - private static final ExecutorService defaultSerialExecutorService = - Executors.newSingleThreadExecutor( + private static final ScheduledExecutorService defaultSerialExecutorService = + Executors.newSingleThreadScheduledExecutor( new ThreadFactory() { @Override public Thread newThread(Runnable runnable) { LogUtil.i("NonUiTaskBuilder.newThread", "creating serial thread"); - Thread thread = new Thread(runnable, "NonUiTaskBuilder"); + Thread thread = new Thread(runnable, "NonUiTaskBuilder-Serial"); thread.setPriority(4); // Corresponds to Process.THREAD_PRIORITY_BACKGROUND return thread; } }); - private static final ExecutorService defaultParallelExecutorService = + private static final Executor defaultParallelExecutor = Executors.newFixedThreadPool( 5, new ThreadFactory() { @Override public Thread newThread(Runnable runnable) { LogUtil.i("NonUiTaskBuilder.newThread", "creating parallel thread"); - Thread thread = new Thread(runnable, "NonUiTaskBuilder"); + Thread thread = new Thread(runnable, "NonUiTaskBuilder-Parallel"); thread.setPriority(4); // Corresponds to Process.THREAD_PRIORITY_BACKGROUND return thread; } }); NonUiTaskBuilder(Worker<InputT, OutputT> worker) { - this(worker, defaultSerialExecutorService, defaultParallelExecutorService); + this(worker, defaultSerialExecutorService, defaultParallelExecutor); } public NonUiTaskBuilder( Worker<InputT, OutputT> worker, - @NonNull ExecutorService serialExecutor, - @NonNull ExecutorService parallelExecutor) { + @NonNull ScheduledExecutorService serialExecutor, + @NonNull Executor parallelExecutor) { super(worker, Assert.isNotNull(serialExecutor), Assert.isNotNull(parallelExecutor)); } @@ -179,7 +197,7 @@ public class DefaultDialerExecutorFactory implements DialerExecutorFactory { super.successListener, super.failureListener, serialExecutorService, - parallelExecutorService); + parallelExecutor); } } @@ -197,6 +215,11 @@ public class DefaultDialerExecutorFactory implements DialerExecutorFactory { } @Override + public void executeSerialWithWait(@Nullable InputT input, long waitMillis) { + dialerUiTaskFragment.executeSerialWithWait(input, waitMillis); + } + + @Override public void executeParallel(@Nullable InputT input) { dialerUiTaskFragment.executeParallel(input); } @@ -214,47 +237,59 @@ public class DefaultDialerExecutorFactory implements DialerExecutorFactory { private final SuccessListener<OutputT> successListener; private final FailureListener failureListener; - private final ExecutorService serialExecutorService; - private final ExecutorService parallelExecutorService; + private final ScheduledExecutorService serialExecutorService; + private final Executor parallelExecutor; + + private ScheduledFuture<?> scheduledFuture; NonUiDialerExecutor( Worker<InputT, OutputT> worker, SuccessListener<OutputT> successListener, FailureListener failureListener, - ExecutorService serialExecutorService, - ExecutorService parallelExecutorService) { + ScheduledExecutorService serialExecutorService, + Executor parallelExecutor) { this.worker = worker; this.successListener = successListener; this.failureListener = failureListener; this.serialExecutorService = serialExecutorService; - this.parallelExecutorService = parallelExecutorService; + this.parallelExecutor = parallelExecutor; } @Override public void executeSerial(@Nullable InputT input) { - executeOnCustomExecutorService(serialExecutorService, input); + serialExecutorService.execute(() -> run(input)); + } + + @Override + public void executeSerialWithWait(@Nullable InputT input, long waitMillis) { + if (scheduledFuture != null) { + LogUtil.i("NonUiDialerExecutor.executeSerialWithWait", "cancelling waiting task"); + scheduledFuture.cancel(false /* mayInterrupt */); + } + scheduledFuture = + serialExecutorService.schedule(() -> run(input), waitMillis, TimeUnit.MILLISECONDS); } @Override public void executeParallel(@Nullable InputT input) { - executeOnCustomExecutorService(parallelExecutorService, input); + parallelExecutor.execute(() -> run(input)); } @Override public void executeOnCustomExecutorService( @NonNull ExecutorService executorService, @Nullable InputT input) { - Assert.isNotNull(executorService) - .execute( - () -> { - OutputT output; - try { - output = worker.doInBackground(input); - } catch (Throwable throwable) { - ThreadUtil.postOnUiThread(() -> failureListener.onFailure(throwable)); - return; - } - ThreadUtil.postOnUiThread(() -> successListener.onSuccess(output)); - }); + Assert.isNotNull(executorService).execute(() -> run(input)); + } + + private void run(@Nullable InputT input) { + OutputT output; + try { + output = worker.doInBackground(input); + } catch (Throwable throwable) { + ThreadUtil.postOnUiThread(() -> failureListener.onFailure(throwable)); + return; + } + ThreadUtil.postOnUiThread(() -> successListener.onSuccess(output)); } } } diff --git a/java/com/android/dialer/common/concurrent/DialerExecutor.java b/java/com/android/dialer/common/concurrent/DialerExecutor.java index 0237e3a05..0414581d4 100644 --- a/java/com/android/dialer/common/concurrent/DialerExecutor.java +++ b/java/com/android/dialer/common/concurrent/DialerExecutor.java @@ -84,6 +84,16 @@ public interface DialerExecutor<InputT> { void executeSerial(@Nullable InputT input); /** + * Executes the task after waiting {@code waitMillis}. If called while the previous invocation is + * still waiting to be started, the original invocation is cancelled. + * + * <p>This is useful for tasks which might get scheduled many times in very quick succession, but + * it is only the last one that actually needs to be executed. + */ + @MainThread + void executeSerialWithWait(@Nullable InputT input, long waitMillis); + + /** * Executes the task on a thread pool shared across the application. Multiple calls using this * method may result in tasks being executed in parallel. */ diff --git a/java/com/android/dialer/common/concurrent/DialerUiTaskFragment.java b/java/com/android/dialer/common/concurrent/DialerUiTaskFragment.java index 627336895..7f2a5a06b 100644 --- a/java/com/android/dialer/common/concurrent/DialerUiTaskFragment.java +++ b/java/com/android/dialer/common/concurrent/DialerUiTaskFragment.java @@ -18,17 +18,21 @@ package com.android.dialer.common.concurrent; import android.app.Fragment; import android.app.FragmentManager; -import android.os.AsyncTask; import android.os.Bundle; import android.support.annotation.MainThread; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.annotation.WorkerThread; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; -import com.android.dialer.common.concurrent.AsyncTaskExecutors.SimpleAsyncTaskExecutor; import com.android.dialer.common.concurrent.DialerExecutor.FailureListener; import com.android.dialer.common.concurrent.DialerExecutor.SuccessListener; import com.android.dialer.common.concurrent.DialerExecutor.Worker; +import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; /** * Do not use this class directly. Instead use {@link DialerExecutors}. @@ -38,13 +42,13 @@ import java.util.concurrent.ExecutorService; */ public final class DialerUiTaskFragment<InputT, OutputT> extends Fragment { - private String taskId; private Worker<InputT, OutputT> worker; private SuccessListener<OutputT> successListener; private FailureListener failureListener; - private AsyncTaskExecutor serialExecutor = AsyncTaskExecutors.createAsyncTaskExecutor(); - private AsyncTaskExecutor parallelExecutor = AsyncTaskExecutors.createThreadPoolExecutor(); + private ScheduledExecutorService serialExecutor; + private Executor parallelExecutor; + private ScheduledFuture<?> scheduledFuture; /** * Creates a new {@link DialerUiTaskFragment} or gets an existing one in the event that a @@ -76,8 +80,8 @@ public final class DialerUiTaskFragment<InputT, OutputT> extends Fragment { Worker<InputT, OutputT> worker, SuccessListener<OutputT> successListener, FailureListener failureListener, - @Nullable ExecutorService serialExecutorService, - @Nullable ExecutorService parallelExecutorService) { + @NonNull ScheduledExecutorService serialExecutorService, + @NonNull Executor parallelExecutor) { Assert.isMainThread(); DialerUiTaskFragment<InputT, OutputT> fragment = @@ -88,16 +92,11 @@ public final class DialerUiTaskFragment<InputT, OutputT> extends Fragment { fragment = new DialerUiTaskFragment<>(); fragmentManager.beginTransaction().add(fragment, taskId).commit(); } - fragment.taskId = taskId; fragment.worker = worker; fragment.successListener = successListener; fragment.failureListener = failureListener; - if (serialExecutorService != null) { - fragment.serialExecutor = new SimpleAsyncTaskExecutor(serialExecutorService); - } - if (parallelExecutorService != null) { - fragment.parallelExecutor = new SimpleAsyncTaskExecutor(parallelExecutorService); - } + fragment.serialExecutor = Assert.isNotNull(serialExecutorService); + fragment.parallelExecutor = Assert.isNotNull(parallelExecutor); return fragment; } @@ -111,60 +110,51 @@ public final class DialerUiTaskFragment<InputT, OutputT> extends Fragment { public void onDetach() { super.onDetach(); LogUtil.enterBlock("DialerUiTaskFragment.onDetach"); - taskId = null; successListener = null; failureListener = null; + if (scheduledFuture != null) { + scheduledFuture.cancel(false /* mayInterrupt */); + scheduledFuture = null; + } } void executeSerial(InputT input) { - serialExecutor.submit(taskId, new InternalTask(), input); + serialExecutor.execute(() -> runTask(input)); + } + + void executeSerialWithWait(InputT input, long waitMillis) { + if (scheduledFuture != null) { + LogUtil.i("DialerUiTaskFragment.executeSerialWithWait", "cancelling waiting task"); + scheduledFuture.cancel(false /* mayInterrupt */); + } + scheduledFuture = + serialExecutor.schedule(() -> runTask(input), waitMillis, TimeUnit.MILLISECONDS); } void executeParallel(InputT input) { - parallelExecutor.submit(taskId, new InternalTask(), input); + parallelExecutor.execute(() -> runTask(input)); } void executeOnCustomExecutor(ExecutorService executor, InputT input) { - new SimpleAsyncTaskExecutor(executor).submit(taskId, new InternalTask(), input); + executor.execute(() -> runTask(input)); } - private final class InternalTask extends AsyncTask<InputT, Void, InternalTaskResult<OutputT>> { - - @SafeVarargs - @Override - protected final InternalTaskResult<OutputT> doInBackground(InputT... params) { - try { - return new InternalTaskResult<>(null, worker.doInBackground(params[0])); - } catch (Throwable throwable) { - LogUtil.e("InternalTask.doInBackground", "task failed", throwable); - return new InternalTaskResult<>(throwable, null); + @WorkerThread + private void runTask(@Nullable InputT input) { + try { + OutputT output = worker.doInBackground(input); + if (successListener == null) { + LogUtil.i("DialerUiTaskFragment.runTask", "task succeeded but UI is dead"); + } else { + ThreadUtil.postOnUiThread(() -> successListener.onSuccess(output)); } - } - - @Override - protected void onPostExecute(InternalTaskResult<OutputT> result) { - if (result.throwable != null) { - if (failureListener == null) { - LogUtil.i("InternalTask.onPostExecute", "task failed but UI is dead"); - } else { - failureListener.onFailure(result.throwable); - } - } else if (successListener == null) { - LogUtil.i("InternalTask.onPostExecute", "task succeeded but UI is dead"); + } catch (Throwable throwable) { + LogUtil.e("DialerUiTaskFragment.runTask", "task failed", throwable); + if (failureListener == null) { + LogUtil.i("DialerUiTaskFragment.runTask", "task failed but UI is dead"); } else { - successListener.onSuccess(result.result); + ThreadUtil.postOnUiThread(() -> failureListener.onFailure(throwable)); } } } - - private static class InternalTaskResult<OutputT> { - - private final Throwable throwable; - private final OutputT result; - - InternalTaskResult(Throwable throwable, OutputT result) { - this.throwable = throwable; - this.result = result; - } - } } diff --git a/java/com/android/dialer/common/concurrent/ThreadUtil.java b/java/com/android/dialer/common/concurrent/ThreadUtil.java index 21cf4634e..39b6cceff 100644 --- a/java/com/android/dialer/common/concurrent/ThreadUtil.java +++ b/java/com/android/dialer/common/concurrent/ThreadUtil.java @@ -28,6 +28,11 @@ public class ThreadUtil { getUiThreadHandler().post(runnable); } + /** Posts a runnable to the UI thread, to be run after the specified amount of time elapses. */ + public static void postDelayedOnUiThread(Runnable runnable, long delayMillis) { + getUiThreadHandler().postDelayed(runnable, delayMillis); + } + /** Gets a handler which uses the main looper. */ public static Handler getUiThreadHandler() { if (mainThreadHandler == null) { |