• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.managedprovisioning.provisioning;
18 
19 import android.os.Handler;
20 import android.os.HandlerThread;
21 import android.os.Looper;
22 import android.util.Pair;
23 
24 import com.android.internal.annotations.GuardedBy;
25 import com.android.managedprovisioning.common.ProvisionLogger;
26 
27 import java.util.ArrayList;
28 import java.util.List;
29 
30 /**
31  * Helper class for ProvisioningManager.
32  */
33 // TODO(b/123288153): Rearrange provisioning activity, manager, controller classes.
34 public class ProvisioningManagerHelper {
35 
36     private static final int CALLBACK_NONE = 0;
37     private static final int CALLBACK_ERROR = 1;
38     private static final int CALLBACK_PRE_FINALIZED = 2;
39 
40     private final Handler mUiHandler;
41 
42     @GuardedBy("this")
43     private List<ProvisioningManagerCallback> mCallbacks = new ArrayList<>();
44 
45     private int mLastCallback = CALLBACK_NONE;
46     private Pair<Pair<Integer, Integer>, Boolean> mLastError; // TODO: refactor
47     private HandlerThread mHandlerThread;
48 
ProvisioningManagerHelper()49     public ProvisioningManagerHelper() {
50         mUiHandler = new Handler(Looper.getMainLooper());
51     }
52 
startNewProvisioningLocked(AbstractProvisioningController controller)53     public void startNewProvisioningLocked(AbstractProvisioningController controller) {
54         if (mHandlerThread == null) {
55             mHandlerThread = new HandlerThread(
56                     String.format("%s Worker", controller.getClass().getName()));
57             mHandlerThread.start();
58         }
59         mLastCallback = CALLBACK_NONE;
60         mLastError = null;
61 
62         controller.start(mHandlerThread.getLooper());
63     }
64 
registerListener(ProvisioningManagerCallback callback)65     public void registerListener(ProvisioningManagerCallback callback) {
66         synchronized (this) {
67             mCallbacks.add(callback);
68             callLastCallbackLocked(callback);
69         }
70     }
71 
unregisterListener(ProvisioningManagerCallback callback)72     public void unregisterListener(ProvisioningManagerCallback callback) {
73         synchronized (this) {
74             mCallbacks.remove(callback);
75         }
76     }
77 
error(int titleId, int messageId, boolean factoryResetRequired)78     public void error(int titleId, int messageId, boolean factoryResetRequired) {
79         synchronized (this) {
80             for (ProvisioningManagerCallback callback : mCallbacks) {
81                 postCallbackToUiHandler(callback, () -> {
82                     callback.error(titleId, messageId, factoryResetRequired);
83                 });
84             }
85             mLastCallback = CALLBACK_ERROR;
86             mLastError = Pair.create(Pair.create(titleId, messageId), factoryResetRequired);
87         }
88     }
89 
callLastCallbackLocked(ProvisioningManagerCallback callback)90     private void callLastCallbackLocked(ProvisioningManagerCallback callback) {
91         switch (mLastCallback) {
92             case CALLBACK_ERROR:
93                 final Pair<Pair<Integer, Integer>, Boolean> error = mLastError;
94                 postCallbackToUiHandler(callback, () -> {
95                     callback.error(error.first.first, error.first.second, error.second);
96                 });
97                 break;
98             case CALLBACK_PRE_FINALIZED:
99                 postCallbackToUiHandler(callback, callback::preFinalizationCompleted);
100                 break;
101             default:
102                 ProvisionLogger.logd("No previous callback");
103         }
104     }
105 
cancelProvisioning(AbstractProvisioningController controller)106     public boolean cancelProvisioning(AbstractProvisioningController controller) {
107         synchronized (this) {
108             if (controller != null) {
109                 controller.cancel();
110                 return true;
111             } else {
112                 ProvisionLogger.loge("Trying to cancel provisioning, but controller is null");
113                 return false;
114             }
115         }
116     }
117 
notifyPreFinalizationCompleted()118     public void notifyPreFinalizationCompleted() {
119         synchronized (this) {
120             for (ProvisioningManagerCallback callback : mCallbacks) {
121                 postCallbackToUiHandler(callback, callback::preFinalizationCompleted);
122             }
123             mLastCallback = CALLBACK_PRE_FINALIZED;
124         }
125     }
126 
clearResourcesLocked()127     public void clearResourcesLocked() {
128         if (mHandlerThread != null) {
129             mHandlerThread.quitSafely();
130             mHandlerThread = null;
131         }
132     }
133 
134     /**
135      * Executes the callback method on the main thread.
136      *
137      * <p>Inside the main thread, we have to first verify the callback is still present on the
138      * callbacks list. This is because when a config change happens (e.g. a different locale was
139      * specified), {@link ProvisioningActivity} is recreated and the old
140      * {@link ProvisioningActivity} instance is left in a bad state. Any callbacks posted before
141      * this happens will still be executed. Fixes b/131719633.
142      */
postCallbackToUiHandler(ProvisioningManagerCallback callback, Runnable callbackRunnable)143     private void postCallbackToUiHandler(ProvisioningManagerCallback callback,
144             Runnable callbackRunnable) {
145         mUiHandler.post(() -> {
146             synchronized (ProvisioningManagerHelper.this) {
147                 if (isCallbackStillRequired(callback)) {
148                     callbackRunnable.run();
149                 }
150             }
151         });
152     }
153 
isCallbackStillRequired(ProvisioningManagerCallback callback)154     private boolean isCallbackStillRequired(ProvisioningManagerCallback callback) {
155         return mCallbacks.contains(callback);
156     }
157 }
158