summaryrefslogtreecommitdiff
path: root/java/com/android/dialer/common
diff options
context:
space:
mode:
authorEric Erfanian <erfanian@google.com>2017-06-19 12:40:59 -0700
committerEric Erfanian <erfanian@google.com>2017-06-19 20:00:08 +0000
commitea7890cd5e829ed3f0b5f726561c569690af2030 (patch)
tree235ab5ab9f9215782c29ef350d275fe12e7b2f74 /java/com/android/dialer/common
parent91ce7d2a476bd04fe525049a37a2f8b2824e9724 (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/158012278 (6/05/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. Merged-In: Ie60a84b3936efd0ea3d95d7c86bf96d2b1663030 Change-Id: If1fa394df2609f0d38b4f794c83f4db3f1006484
Diffstat (limited to 'java/com/android/dialer/common')
-rw-r--r--java/com/android/dialer/common/Assert.java5
-rw-r--r--java/com/android/dialer/common/ConfigProvider.java27
-rw-r--r--java/com/android/dialer/common/ConfigProviderBindings.java76
-rw-r--r--java/com/android/dialer/common/ConfigProviderFactory.java26
-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/DialerUiTaskFragment.java94
-rw-r--r--java/com/android/dialer/common/concurrent/ThreadUtil.java5
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) {