1 /* 2 * Copyright 2016, 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 static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_TOTAL_TASK_TIME_MS; 20 import static com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker.CANCELLED_DURING_PROVISIONING; 21 22 import static java.util.Objects.requireNonNull; 23 24 import android.content.Context; 25 import android.os.Bundle; 26 27 import androidx.appcompat.app.AppCompatActivity; 28 import androidx.lifecycle.ViewModelProvider; 29 import androidx.lifecycle.ViewModelStoreOwner; 30 31 import com.android.internal.annotations.GuardedBy; 32 import com.android.internal.annotations.VisibleForTesting; 33 import com.android.managedprovisioning.analytics.MetricsWriterFactory; 34 import com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker; 35 import com.android.managedprovisioning.analytics.TimeLogger; 36 import com.android.managedprovisioning.common.ManagedProvisioningSharedPreferences; 37 import com.android.managedprovisioning.common.ProvisionLogger; 38 import com.android.managedprovisioning.common.SettingsFacade; 39 import com.android.managedprovisioning.model.ProvisioningParams; 40 import com.android.managedprovisioning.provisioning.ProvisioningViewModel.ProvisioningViewModelFactory; 41 import com.android.managedprovisioning.provisioning.TransitionAnimationHelper.TransitionAnimationState; 42 43 /** 44 * Singleton instance that provides communications between the ongoing provisioning process and the 45 * UI layer. 46 * <p>{@link #setViewModelStoreOwner(ViewModelStoreOwner)} must be called when the view model store 47 * owner has been created (for example, {@link AppCompatActivity#onCreate(Bundle)}). In addition, 48 * to prevent memory leaks when the view model store owner is destroyed, {@link 49 * #clearViewModelStoreOwner()} must be called (for example, in {@link 50 * AppCompatActivity#onDestroy()} when {@link AppCompatActivity#isFinishing()} is {@code true}). 51 */ 52 public class ProvisioningManager implements ProvisioningControllerCallback, 53 ProvisioningManagerInterface { 54 55 private static ProvisioningManager sInstance; 56 57 private final Context mContext; 58 private final ProvisioningControllerFactory mFactory; 59 private final ProvisioningAnalyticsTracker mProvisioningAnalyticsTracker; 60 private final TimeLogger mTimeLogger; 61 private final ProvisioningManagerHelper mHelper; 62 private ProvisioningViewModel mViewModel; 63 64 @GuardedBy("this") 65 private AbstractProvisioningController mController; 66 getInstance(Context context)67 public static ProvisioningManager getInstance(Context context) { 68 if (sInstance == null) { 69 sInstance = new ProvisioningManager(context.getApplicationContext()); 70 } 71 return sInstance; 72 } 73 ProvisioningManager(Context context)74 private ProvisioningManager(Context context) { 75 this( 76 context, 77 new ProvisioningControllerFactory(), 78 new ProvisioningAnalyticsTracker( 79 MetricsWriterFactory.getMetricsWriter(context, new SettingsFacade()), 80 new ManagedProvisioningSharedPreferences(context)), 81 new TimeLogger(context, PROVISIONING_TOTAL_TASK_TIME_MS)); 82 } 83 84 @VisibleForTesting ProvisioningManager( Context context, ProvisioningControllerFactory factory, ProvisioningAnalyticsTracker analyticsTracker, TimeLogger timeLogger)85 ProvisioningManager( 86 Context context, 87 ProvisioningControllerFactory factory, 88 ProvisioningAnalyticsTracker analyticsTracker, 89 TimeLogger timeLogger) { 90 mContext = requireNonNull(context); 91 mFactory = requireNonNull(factory); 92 mProvisioningAnalyticsTracker = requireNonNull(analyticsTracker); 93 mTimeLogger = requireNonNull(timeLogger); 94 mHelper = new ProvisioningManagerHelper(); 95 } 96 97 /** 98 * Sets the view model store owner. 99 * <p>Must be called when the view model store owner has been created (for example, {@link 100 * AppCompatActivity#onCreate(Bundle)}). 101 * @see #clearViewModelStoreOwner() 102 */ setViewModelStoreOwner(ViewModelStoreOwner owner)103 void setViewModelStoreOwner(ViewModelStoreOwner owner) { 104 mViewModel = new ViewModelProvider(owner, new ProvisioningViewModelFactory()) 105 .get(ProvisioningViewModel.class); 106 } 107 108 /** 109 * Clears the view model store owner. 110 * <p>Must be called when the view model store owner is getting destroyed (for example, in 111 * {@link AppCompatActivity#onDestroy()} when {@link AppCompatActivity#isFinishing()} is {@code 112 * true}), in order to clean the reference and prevent memory leaks. 113 */ clearViewModelStoreOwner()114 void clearViewModelStoreOwner() { 115 mViewModel = null; 116 } 117 118 @Override maybeStartProvisioning(final ProvisioningParams params)119 public void maybeStartProvisioning(final ProvisioningParams params) { 120 synchronized (this) { 121 if (mController == null) { 122 mTimeLogger.start(); 123 mController = getController(params); 124 mHelper.startNewProvisioningLocked(mController); 125 mProvisioningAnalyticsTracker.logProvisioningStarted(mContext, params); 126 } else { 127 ProvisionLogger.loge("Trying to start provisioning, but it's already running"); 128 } 129 } 130 } 131 132 @Override registerListener(ProvisioningManagerCallback callback)133 public void registerListener(ProvisioningManagerCallback callback) { 134 mHelper.registerListener(callback); 135 } 136 137 @Override unregisterListener(ProvisioningManagerCallback callback)138 public void unregisterListener(ProvisioningManagerCallback callback) { 139 mHelper.unregisterListener(callback); 140 } 141 142 @Override cancelProvisioning()143 public void cancelProvisioning() { 144 synchronized (this) { 145 final boolean provisioningCanceled = mHelper.cancelProvisioning(mController); 146 if (provisioningCanceled) { 147 mProvisioningAnalyticsTracker.logProvisioningCancelled(mContext, 148 CANCELLED_DURING_PROVISIONING); 149 } 150 } 151 } 152 153 @Override provisioningTasksCompleted()154 public void provisioningTasksCompleted() { 155 synchronized (this) { 156 mTimeLogger.stop(); 157 preFinalizationCompleted(); 158 } 159 } 160 161 @Override preFinalizationCompleted()162 public void preFinalizationCompleted() { 163 synchronized (this) { 164 mHelper.notifyPreFinalizationCompleted(); 165 mProvisioningAnalyticsTracker.logProvisioningSessionCompleted(mContext); 166 clearControllerLocked(); 167 ProvisionLogger.logi("ProvisioningManager pre-finalization completed"); 168 } 169 } 170 171 @Override cleanUpCompleted()172 public void cleanUpCompleted() { 173 synchronized (this) { 174 clearControllerLocked(); 175 } 176 } 177 178 @Override error(int titleId, int messageId, boolean factoryResetRequired)179 public void error(int titleId, int messageId, boolean factoryResetRequired) { 180 mHelper.error(titleId, messageId, factoryResetRequired); 181 } 182 saveTransitionAnimationState(TransitionAnimationState transitionAnimationState)183 void saveTransitionAnimationState(TransitionAnimationState transitionAnimationState) { 184 mViewModel.saveTransitionAnimationState(transitionAnimationState); 185 } 186 restoreTransitionAnimationState()187 TransitionAnimationState restoreTransitionAnimationState() { 188 return mViewModel.restoreTransitionAnimationState(); 189 } 190 getController(ProvisioningParams params)191 private AbstractProvisioningController getController(ProvisioningParams params) { 192 return mFactory.createProvisioningController(mContext, params, this); 193 } 194 clearControllerLocked()195 private void clearControllerLocked() { 196 mController = null; 197 mHelper.clearResourcesLocked(); 198 } 199 } 200