summaryrefslogtreecommitdiff
path: root/java/com/android/dialer/common/concurrent
diff options
context:
space:
mode:
authorEric Erfanian <erfanian@google.com>2017-06-19 11:26:01 -0700
committerEric Erfanian <erfanian@google.com>2017-06-19 11:30:45 -0700
commit2f1c7586bcce334ca69022eb8dc6d8965ceb6a05 (patch)
treebf00ada449ee3de31ec983a14e84159200aa18c2 /java/com/android/dialer/common/concurrent
parent3d0ca68e466482971a4cf46576c50cb2bd42bcb5 (diff)
Update AOSP Dialer source from internal google3 repository at
cl/159428781. Test: make, treehugger This CL updates the AOSP Dialer source with all the changes that have gone into the private google3 repository. This includes all the changes from cl/152373142 (4/06/2017) to cl/159428781 (6/19/2017). This goal of these drops is to keep the AOSP source in sync with the internal google3 repository. Currently these sync are done by hand with very minor modifications to the internal source code. See the Android.mk file for list of modifications. Our current goal is to do frequent drops (daily if possible) and eventually switched to an automated process. Change-Id: Ie60a84b3936efd0ea3d95d7c86bf96d2b1663030
Diffstat (limited to 'java/com/android/dialer/common/concurrent')
-rw-r--r--java/com/android/dialer/common/concurrent/DefaultDialerExecutorFactory.java111
-rw-r--r--java/com/android/dialer/common/concurrent/DialerExecutor.java10
-rw-r--r--java/com/android/dialer/common/concurrent/DialerExecutorComponent.java39
-rw-r--r--java/com/android/dialer/common/concurrent/DialerExecutorModule.java28
-rw-r--r--java/com/android/dialer/common/concurrent/DialerUiTaskFragment.java94
-rw-r--r--java/com/android/dialer/common/concurrent/ThreadUtil.java5
6 files changed, 197 insertions, 90 deletions
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/DialerExecutorComponent.java b/java/com/android/dialer/common/concurrent/DialerExecutorComponent.java
new file mode 100644
index 000000000..25033251f
--- /dev/null
+++ b/java/com/android/dialer/common/concurrent/DialerExecutorComponent.java
@@ -0,0 +1,39 @@
+/*
+ * 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.dialer.common.concurrent;
+
+import android.content.Context;
+import com.android.dialer.inject.HasRootComponent;
+import dagger.Subcomponent;
+
+/** Dagger component which provides a {@link DialerExecutorFactory}. */
+@Subcomponent
+public abstract class DialerExecutorComponent {
+
+ public abstract DialerExecutorFactory dialerExecutorFactory();
+
+ public static DialerExecutorComponent get(Context context) {
+ return ((DialerExecutorComponent.HasComponent)
+ ((HasRootComponent) context.getApplicationContext()).component())
+ .dialerExecutorComponent();
+ }
+
+ /** Used to refer to the root application component. */
+ public interface HasComponent {
+ DialerExecutorComponent dialerExecutorComponent();
+ }
+}
diff --git a/java/com/android/dialer/common/concurrent/DialerExecutorModule.java b/java/com/android/dialer/common/concurrent/DialerExecutorModule.java
new file mode 100644
index 000000000..281f88c15
--- /dev/null
+++ b/java/com/android/dialer/common/concurrent/DialerExecutorModule.java
@@ -0,0 +1,28 @@
+/*
+ * 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.dialer.common.concurrent;
+
+import dagger.Binds;
+import dagger.Module;
+
+/** Module which binds the production {@link DialerExecutorFactory}. */
+@Module
+public abstract class DialerExecutorModule {
+
+ @Binds
+ abstract DialerExecutorFactory bindDialerExecutorFactory(
+ DefaultDialerExecutorFactory defaultDialerExecutorFactory);
+}
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) {