• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_PROVISIONING_ACTIVITY_TIME_MS;
20 
21 import android.Manifest;
22 import android.Manifest.permission;
23 import android.app.Activity;
24 import android.app.DialogFragment;
25 import android.app.admin.DevicePolicyManager;
26 import android.content.ComponentName;
27 import android.content.Intent;
28 import android.content.pm.PackageManager;
29 import android.content.pm.ResolveInfo;
30 import android.os.Bundle;
31 import android.support.annotation.VisibleForTesting;
32 import android.view.accessibility.AccessibilityEvent;
33 import android.widget.TextView;
34 
35 import com.android.managedprovisioning.R;
36 import com.android.managedprovisioning.common.DialogBuilder;
37 import com.android.managedprovisioning.common.ProvisionLogger;
38 import com.android.managedprovisioning.common.SetupGlifLayoutActivity;
39 import com.android.managedprovisioning.common.SimpleDialog;
40 import com.android.managedprovisioning.common.Utils;
41 import com.android.managedprovisioning.model.CustomizationParams;
42 import com.android.managedprovisioning.model.ProvisioningParams;
43 import java.util.List;
44 
45 /**
46  * Progress activity shown whilst provisioning is ongoing.
47  *
48  * <p>This activity registers for updates of the provisioning process from the
49  * {@link ProvisioningManager}. It shows progress updates as provisioning progresses and handles
50  * showing of cancel and error dialogs.</p>
51  */
52 public class ProvisioningActivity extends SetupGlifLayoutActivity
53         implements SimpleDialog.SimpleDialogListener, ProvisioningManagerCallback {
54 
55     private static final String KEY_PROVISIONING_STARTED = "ProvisioningStarted";
56 
57     private static final String ERROR_DIALOG_OK = "ErrorDialogOk";
58     private static final String ERROR_DIALOG_RESET = "ErrorDialogReset";
59     private static final String CANCEL_PROVISIONING_DIALOG_OK = "CancelProvisioningDialogOk";
60     private static final String CANCEL_PROVISIONING_DIALOG_RESET = "CancelProvisioningDialogReset";
61 
62     private ProvisioningParams mParams;
63     private ProvisioningManager mProvisioningManager;
64 
ProvisioningActivity()65     public ProvisioningActivity() {
66         this(null, new Utils());
67     }
68 
69     @VisibleForTesting
ProvisioningActivity(ProvisioningManager provisioningManager, Utils utils)70     public ProvisioningActivity(ProvisioningManager provisioningManager, Utils utils) {
71         super(utils);
72         mProvisioningManager = provisioningManager;
73     }
74 
75     // Lazily initialize ProvisioningManager, since we can't call in ProvisioningManager.getInstance
76     // in constructor as base context is not available in constructor
getProvisioningManager()77     private ProvisioningManager getProvisioningManager() {
78         if (mProvisioningManager == null) {
79             mProvisioningManager = ProvisioningManager.getInstance(this);
80         }
81         return mProvisioningManager;
82     }
83 
84     @Override
onCreate(Bundle savedInstanceState)85     protected void onCreate(Bundle savedInstanceState) {
86         super.onCreate(savedInstanceState);
87         mParams = getIntent().getParcelableExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS);
88         initializeUi(mParams);
89 
90         if (savedInstanceState == null
91                 || !savedInstanceState.getBoolean(KEY_PROVISIONING_STARTED)) {
92             getProvisioningManager().maybeStartProvisioning(mParams);
93         }
94     }
95 
96     @Override
onSaveInstanceState(Bundle outState)97     protected void onSaveInstanceState(Bundle outState) {
98         super.onSaveInstanceState(outState);
99         outState.putBoolean(KEY_PROVISIONING_STARTED, true);
100     }
101 
102     @Override
onResume()103     protected void onResume() {
104         super.onResume();
105         if (!isAnyDialogAdded()) {
106             getProvisioningManager().registerListener(this);
107         }
108     }
109 
isAnyDialogAdded()110     private boolean isAnyDialogAdded() {
111         return isDialogAdded(ERROR_DIALOG_OK)
112                 || isDialogAdded(ERROR_DIALOG_RESET)
113                 || isDialogAdded(CANCEL_PROVISIONING_DIALOG_OK)
114                 || isDialogAdded(CANCEL_PROVISIONING_DIALOG_RESET);
115     }
116 
117     @Override
onPause()118     public void onPause() {
119         getProvisioningManager().unregisterListener(this);
120         super.onPause();
121     }
122 
123     @Override
onBackPressed()124     public void onBackPressed() {
125         // if EXTRA_PROVISIONING_SKIP_USER_CONSENT is specified, don't allow user to cancel
126         if (mParams.skipUserConsent) {
127             return;
128         }
129 
130         showCancelProvisioningDialog();
131     }
132 
133     @Override
preFinalizationCompleted()134     public void preFinalizationCompleted() {
135         ProvisionLogger.logi("ProvisioningActivity pre-finalization completed");
136         setResult(Activity.RESULT_OK);
137         maybeLaunchNfcUserSetupCompleteIntent();
138         finish();
139     }
140 
maybeLaunchNfcUserSetupCompleteIntent()141     private void maybeLaunchNfcUserSetupCompleteIntent() {
142         if (mParams != null && mParams.isNfc) {
143             // Start SetupWizard to complete the intent.
144             final Intent intent = new Intent(DevicePolicyManager.ACTION_STATE_USER_SETUP_COMPLETE)
145                     .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
146             final PackageManager pm = getPackageManager();
147             List<ResolveInfo> ris = pm.queryIntentActivities(intent, 0);
148 
149             // Look for the first legitimate component protected by the permission
150             ComponentName targetComponent = null;
151             for (ResolveInfo ri : ris) {
152                 if (ri.activityInfo == null) {
153                     continue;
154                 }
155                 if (!permission.BIND_DEVICE_ADMIN.equals(ri.activityInfo.permission)) {
156                     ProvisionLogger.loge("Component " + ri.activityInfo.getComponentName()
157                             + " is not protected by " + permission.BIND_DEVICE_ADMIN);
158                 } else if (pm.checkPermission(permission.DISPATCH_PROVISIONING_MESSAGE,
159                         ri.activityInfo.packageName) != PackageManager.PERMISSION_GRANTED) {
160                     ProvisionLogger.loge("Package " + ri.activityInfo.packageName
161                             + " does not have " + permission.DISPATCH_PROVISIONING_MESSAGE);
162                 } else {
163                     targetComponent = ri.activityInfo.getComponentName();
164                     break;
165                 }
166             }
167 
168             if (targetComponent == null) {
169                 ProvisionLogger.logw("No activity accepts intent ACTION_STATE_USER_SETUP_COMPLETE");
170                 return;
171             }
172 
173             intent.setComponent(targetComponent);
174             startActivity(intent);
175             ProvisionLogger.logi("Launched ACTION_STATE_USER_SETUP_COMPLETE with component "
176                     + targetComponent);
177         }
178     }
179 
180     @Override
progressUpdate(int progressMessage)181     public void progressUpdate(int progressMessage) {
182     }
183 
184     @Override
error(int titleId, int messageId, boolean resetRequired)185     public void error(int titleId, int messageId, boolean resetRequired) {
186         SimpleDialog.Builder dialogBuilder = new SimpleDialog.Builder()
187                 .setTitle(titleId)
188                 .setMessage(messageId)
189                 .setCancelable(false)
190                 .setPositiveButtonMessage(resetRequired
191                         ? R.string.reset : R.string.device_owner_error_ok);
192 
193         showDialog(dialogBuilder, resetRequired ? ERROR_DIALOG_RESET : ERROR_DIALOG_OK);
194     }
195 
196     @Override
showDialog(DialogBuilder builder, String tag)197     protected void showDialog(DialogBuilder builder, String tag) {
198         // Whenever a dialog is shown, stop listening for further updates
199         getProvisioningManager().unregisterListener(this);
200         super.showDialog(builder, tag);
201     }
202 
203     @Override
getMetricsCategory()204     protected int getMetricsCategory() {
205         return PROVISIONING_PROVISIONING_ACTIVITY_TIME_MS;
206     }
207 
showCancelProvisioningDialog()208     private void showCancelProvisioningDialog() {
209         final boolean isDoProvisioning = getUtils().isDeviceOwnerAction(mParams.provisioningAction);
210         final String dialogTag = isDoProvisioning ? CANCEL_PROVISIONING_DIALOG_RESET
211                 : CANCEL_PROVISIONING_DIALOG_OK;
212         final int positiveResId = isDoProvisioning ? R.string.reset
213                 : R.string.profile_owner_cancel_ok;
214         final int negativeResId = isDoProvisioning ? R.string.device_owner_cancel_cancel
215                 : R.string.profile_owner_cancel_cancel;
216         final int dialogMsgResId = isDoProvisioning
217                 ? R.string.this_will_reset_take_back_first_screen
218                 : R.string.profile_owner_cancel_message;
219 
220         SimpleDialog.Builder dialogBuilder = new SimpleDialog.Builder()
221                 .setCancelable(false)
222                 .setMessage(dialogMsgResId)
223                 .setNegativeButtonMessage(negativeResId)
224                 .setPositiveButtonMessage(positiveResId);
225         if (isDoProvisioning) {
226             dialogBuilder.setTitle(R.string.stop_setup_reset_device_question);
227         }
228 
229         showDialog(dialogBuilder, dialogTag);
230     }
231 
onProvisioningAborted()232     private void onProvisioningAborted() {
233         setResult(Activity.RESULT_CANCELED);
234         finish();
235     }
236 
237     @Override
onNegativeButtonClick(DialogFragment dialog)238     public void onNegativeButtonClick(DialogFragment dialog) {
239         switch (dialog.getTag()) {
240             case CANCEL_PROVISIONING_DIALOG_OK:
241             case CANCEL_PROVISIONING_DIALOG_RESET:
242                 dialog.dismiss();
243                 break;
244             default:
245                 SimpleDialog.throwButtonClickHandlerNotImplemented(dialog);
246         }
247         getProvisioningManager().registerListener(this);
248     }
249 
250     @Override
onPositiveButtonClick(DialogFragment dialog)251     public void onPositiveButtonClick(DialogFragment dialog) {
252         switch (dialog.getTag()) {
253             case CANCEL_PROVISIONING_DIALOG_OK:
254                 getProvisioningManager().cancelProvisioning();
255                 onProvisioningAborted();
256                 break;
257             case CANCEL_PROVISIONING_DIALOG_RESET:
258                 getUtils().sendFactoryResetBroadcast(this, "DO provisioning cancelled by user");
259                 onProvisioningAborted();
260                 break;
261             case ERROR_DIALOG_OK:
262                 onProvisioningAborted();
263                 break;
264             case ERROR_DIALOG_RESET:
265                 getUtils().sendFactoryResetBroadcast(this, "Error during DO provisioning");
266                 onProvisioningAborted();
267                 break;
268             default:
269                 SimpleDialog.throwButtonClickHandlerNotImplemented(dialog);
270         }
271     }
272 
initializeUi(ProvisioningParams params)273     private void initializeUi(ProvisioningParams params) {
274         final boolean isDoProvisioning = getUtils().isDeviceOwnerAction(params.provisioningAction);
275         final int headerResId = isDoProvisioning ? R.string.setup_work_device
276                 : R.string.setting_up_workspace;
277         final int titleResId = isDoProvisioning ? R.string.setup_device_progress
278                 : R.string.setup_profile_progress;
279 
280         initializeLayoutParams(R.layout.progress, headerResId, true,
281                 CustomizationParams.createInstance(mParams, this, mUtils).statusBarColor);
282         setTitle(titleResId);
283     }
284 }