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<MyInputType> 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<MyInputType, MyOutputType> { 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<MyInputType> 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<MyInputType, MyOutputType> { 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