1d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian/*
2d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * Copyright (C) 2017 The Android Open Source Project
3d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *
4d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * Licensed under the Apache License, Version 2.0 (the "License");
5d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * you may not use this file except in compliance with the License.
6d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * You may obtain a copy of the License at
7d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *
8d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *      http://www.apache.org/licenses/LICENSE-2.0
9d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *
10d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * Unless required by applicable law or agreed to in writing, software
11d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * distributed under the License is distributed on an "AS IS" BASIS,
12d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * See the License for the specific language governing permissions and
14d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * limitations under the License
15d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian */
16d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian
17d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanianpackage com.android.dialer.common.concurrent;
18d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian
19d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanianimport android.app.FragmentManager;
20d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanianimport android.support.annotation.NonNull;
21d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanianimport com.android.dialer.common.Assert;
22d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanianimport com.android.dialer.common.concurrent.DialerExecutor.Worker;
23d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian
24d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian/**
25d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * Factory methods for creating {@link DialerExecutor} objects for doing background work.
26d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *
27d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * <p>You may create an executor from a UI component (activity or fragment) or a non-UI component.
28d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * Using this class provides a number of benefits:
29d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *
30d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * <ul>
31d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *   <li>Ensures that UI tasks keep running across configuration changes by using a headless
32d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *       fragment.
33d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *   <li>Forces exceptions to crash the application, unless the user implements their own onFailure
34d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *       method.
35d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *   <li>Checks for dead UI components which can be encountered if a UI task runs longer than its
36d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *       UI. If a dead UI component is encountered, onSuccess/onFailure are not called (because they
37d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *       can't be) but a message is logged.
38d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *   <li>Helps prevents memory leaks in UI tasks by ensuring that callbacks are nulled out when the
39d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *       headless fragment is detached.
40d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *   <li>UI and non-UI threads are shared across the application and run at reasonable priorities
41d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * </ul>
42d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *
43d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * <p>Executors accept a single input and output parameter which should be immutable data objects.
44d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * If you don't require an input or output, use Void and null as needed.
45d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *
46d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * <p>You may optionally specify onSuccess and onFailure listeners; the default behavior on success
47d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * is a no-op and the default behavior on failure is to crash the application.
48d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *
49d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * <p>To use an executor from a UI component, you must create it in your onCreate method and then
50d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * use it from anywhere:
51d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *
52d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * <pre><code>
53d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *
54d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * public class MyActivity extends Activity {
55d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *
56d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *   private final DialerExecutor&lt;MyInputType&gt; myExecutor;
57d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *
58d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *   public void onCreate(Bundle state) {
59d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *     super.onCreate(bundle);
60d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *
61d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *     // Must be called in onCreate; don't use non-static or anonymous inner classes for worker!
62d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *     myExecutor = DialerExecutors.createUiTaskBuilder(fragmentManager, taskId, worker)
63d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *         .onSuccess(this::onSuccess)  // Lambdas, anonymous, or non-static inner classes all fine
64d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *         .onFailure(this::onFailure)  // Lambdas, anonymous, or non-static inner classes all fine
65d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *         .build();
66d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *     );
67d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *   }
68d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *
69d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *   private static class MyWorker implements Worker&lt;MyInputType, MyOutputType&gt; {
70d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *     MyOutputType doInBackground(MyInputType input) { ... }
71d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *   }
72d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *   private void onSuccess(MyOutputType output) { ... }
73d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *   private void onFailure(Throwable throwable) { ... }
74d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *
75d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *   private void userDidSomething() { myExecutor.executeParallel(input); }
76d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * }
77d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * </code></pre>
78d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *
79d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * <p>Usage for non-UI tasks is the same, except that tasks can be created from anywhere instead of
80d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * in onCreate. Non-UI tasks use low-priority threads separate from the UI task threads so as not to
81d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * compete with more critical UI tasks.
82d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *
83d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * <pre><code>
84d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *
85d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * public class MyManager {
86d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *
87d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *   private final DialerExecutor&lt;MyInputType&gt; myExecutor;
88d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *
89d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *   public void init() {
90d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *     // Don't use non-static or anonymous inner classes for worker!
91d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *     myExecutor = DialerExecutors.createNonUiTaskBuilder(worker)
92d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *         .onSuccess(this::onSuccess)  // Lambdas, anonymous, or non-static inner classes all fine
93d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *         .onFailure(this::onFailure)  // Lambdas, anonymous, or non-static inner classes all fine
94d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *         .build();
95d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *     );
96d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *   }
97d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *
98d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *   private static class MyWorker implements Worker&lt;MyInputType, MyOutputType&gt; {
99d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *     MyOutputType doInBackground(MyInputType input) { ... }
100d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *   }
101d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *   private void onSuccess(MyOutputType output) { ... }
102d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *   private void onFailure(Throwable throwable) { ... }
103d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *
104d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *   private void userDidSomething() { myExecutor.executeParallel(input); }
105d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * }
106d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * </code></pre>
107d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian *
108d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * Note that non-UI tasks are intended to be relatively quick; for example reading/writing shared
109d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * preferences or doing simple database work. If you submit long running non-UI tasks you may
110d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * saturate the shared application threads and block other tasks. Also, this class does not create
111d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * any wakelocks, so a long running task could be killed if the device goes to sleep while your task
112d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * is still running. If you have to do long running or periodic work, consider using a job
113d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian * scheduler.
114d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian */
115d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanianpublic final class DialerExecutors {
116d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian
117d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian  /** @see DialerExecutorFactory#createUiTaskBuilder(FragmentManager, String, Worker) */
118d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian  @NonNull
119d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian  public static <InputT, OutputT> DialerExecutor.Builder<InputT, OutputT> createUiTaskBuilder(
120d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian      @NonNull FragmentManager fragmentManager,
121d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian      @NonNull String taskId,
122d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian      @NonNull Worker<InputT, OutputT> worker) {
123d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian    return new DefaultDialerExecutorFactory()
124d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian        .createUiTaskBuilder(
125d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian            Assert.isNotNull(fragmentManager), Assert.isNotNull(taskId), Assert.isNotNull(worker));
126d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian  }
127d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian
128d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian  /** @see DialerExecutorFactory#createNonUiTaskBuilder(Worker) */
129d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian  @NonNull
130d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian  public static <InputT, OutputT> DialerExecutor.Builder<InputT, OutputT> createNonUiTaskBuilder(
131d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian      @NonNull Worker<InputT, OutputT> worker) {
132d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian    return new DefaultDialerExecutorFactory().createNonUiTaskBuilder(Assert.isNotNull(worker));
133d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian  }
134d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian}
135