• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014, 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;
18 
19 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE;
20 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME;
21 
22 import android.accounts.Account;
23 import android.accounts.AccountManager;
24 import android.accounts.AccountManagerFuture;
25 import android.accounts.AuthenticatorException;
26 import android.accounts.OperationCanceledException;
27 import android.app.Activity;
28 import android.app.AlertDialog;
29 import android.app.ProgressDialog;
30 import android.app.admin.DevicePolicyManager;
31 import android.content.BroadcastReceiver;
32 import android.content.Context;
33 import android.content.DialogInterface;
34 import android.content.Intent;
35 import android.content.IntentFilter;
36 import android.os.AsyncTask;
37 import android.os.Bundle;
38 import android.os.ConditionVariable;
39 import android.os.Handler;
40 import android.os.UserHandle;
41 import android.os.UserManager;
42 import android.provider.Settings;
43 import android.support.v4.content.LocalBroadcastManager;
44 import android.view.View;
45 import android.widget.TextView;
46 
47 import com.android.managedprovisioning.model.ProvisioningParams;
48 
49 import java.io.IOException;
50 import java.util.concurrent.ExecutionException;
51 
52 /**
53  * Profile owner provisioning sets up a separate profile on a device whose primary user is already
54  * set up or being set up.
55  *
56  * <p>
57  * The typical example is setting up a corporate profile that is controlled by their employer on a
58  * users personal device to keep personal and work data separate.
59  *
60  * <p>
61  * The activity handles the UI for managed profile provisioning and starts the
62  * {@link ProfileOwnerProvisioningService}, which runs through the setup steps in an
63  * async task.
64  */
65 public class ProfileOwnerProvisioningActivity extends SetupLayoutActivity {
66     protected static final String ACTION_CANCEL_PROVISIONING =
67             "com.android.managedprovisioning.CANCEL_PROVISIONING";
68 
69     private BroadcastReceiver mServiceMessageReceiver;
70 
71     private static final int BROADCAST_TIMEOUT = 2 * 60 * 1000;
72 
73     // Provisioning service started
74     private static final int STATUS_PROVISIONING = 1;
75     // Back button pressed during provisioning, confirm dialog showing.
76     private static final int STATUS_CANCEL_CONFIRMING = 2;
77     // Cancel confirmed, waiting for the provisioning service to complete.
78     private static final int STATUS_CANCELLING = 3;
79     // Cancelling not possible anymore, provisioning already finished successfully.
80     private static final int STATUS_FINALIZING = 4;
81 
82     private static final String KEY_STATUS= "status";
83     private static final String KEY_PENDING_INTENT = "pending_intent";
84 
85     private int mCancelStatus = STATUS_PROVISIONING;
86     private Intent mPendingProvisioningResult = null;
87     private ProgressDialog mCancelProgressDialog = null;
88     private AccountManager mAccountManager;
89 
90     private ProvisioningParams mParams;
91 
92     @Override
onCreate(Bundle savedInstanceState)93     protected void onCreate(Bundle savedInstanceState) {
94         super.onCreate(savedInstanceState);
95         ProvisionLogger.logd("Profile owner provisioning activity ONCREATE");
96         mAccountManager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE);
97 
98         if (savedInstanceState != null) {
99             mCancelStatus = savedInstanceState.getInt(KEY_STATUS, STATUS_PROVISIONING);
100             mPendingProvisioningResult = savedInstanceState.getParcelable(KEY_PENDING_INTENT);
101         }
102 
103         initializeLayoutParams(R.layout.progress, R.string.setting_up_workspace, true);
104         setTitle(R.string.setup_profile_progress);
105 
106         if (mCancelStatus == STATUS_CANCEL_CONFIRMING) {
107             showCancelProvisioningDialog();
108         } else if (mCancelStatus == STATUS_CANCELLING) {
109             showCancelProgressDialog();
110         }
111         mParams = (ProvisioningParams) getIntent().getParcelableExtra(
112                 ProvisioningParams.EXTRA_PROVISIONING_PARAMS);
113         if (mParams != null) {
114             maybeSetLogoAndMainColor(mParams.mainColor);
115         }
116     }
117 
118     @Override
onResume()119     protected void onResume() {
120         super.onResume();
121 
122         // Setup broadcast receiver for feedback from service.
123         mServiceMessageReceiver = new ServiceMessageReceiver();
124         IntentFilter filter = new IntentFilter();
125         filter.addAction(ProfileOwnerProvisioningService.ACTION_PROVISIONING_SUCCESS);
126         filter.addAction(ProfileOwnerProvisioningService.ACTION_PROVISIONING_ERROR);
127         filter.addAction(ProfileOwnerProvisioningService.ACTION_PROVISIONING_CANCELLED);
128         LocalBroadcastManager.getInstance(this).registerReceiver(mServiceMessageReceiver, filter);
129 
130         // Start service async to make sure the UI is loaded first.
131         final Handler handler = new Handler(getMainLooper());
132         handler.post(new Runnable() {
133             @Override
134             public void run() {
135                 Intent intent = new Intent(ProfileOwnerProvisioningActivity.this,
136                         ProfileOwnerProvisioningService.class);
137                 intent.putExtras(getIntent());
138                 startService(intent);
139             }
140         });
141     }
142 
143     class ServiceMessageReceiver extends BroadcastReceiver {
144         @Override
onReceive(Context context, Intent intent)145         public void onReceive(Context context, Intent intent) {
146             if (mCancelStatus == STATUS_CANCEL_CONFIRMING) {
147                 // Store the incoming intent and only process it after the user has responded to
148                 // the cancel dialog
149                 mPendingProvisioningResult = intent;
150                 return;
151             }
152             handleProvisioningResult(intent);
153         }
154     }
155 
handleProvisioningResult(Intent intent)156     private void handleProvisioningResult(Intent intent) {
157         String action = intent.getAction();
158         if (ProfileOwnerProvisioningService.ACTION_PROVISIONING_SUCCESS.equals(action)) {
159             if (mCancelStatus == STATUS_CANCELLING) {
160                 return;
161             }
162 
163             ProvisionLogger.logd("Successfully provisioned."
164                     + "Finishing ProfileOwnerProvisioningActivity");
165 
166             onProvisioningSuccess();
167         } else if (ProfileOwnerProvisioningService.ACTION_PROVISIONING_ERROR.equals(action)) {
168             if (mCancelStatus == STATUS_CANCELLING){
169                 return;
170             }
171             String errorLogMessage = intent.getStringExtra(
172                     ProfileOwnerProvisioningService.EXTRA_LOG_MESSAGE_KEY);
173             ProvisionLogger.logd("Error reported: " + errorLogMessage);
174             error(R.string.managed_provisioning_error_text, errorLogMessage);
175             // Note that this will be reported as a canceled action
176             mCancelStatus = STATUS_FINALIZING;
177         } else if (ProfileOwnerProvisioningService.ACTION_PROVISIONING_CANCELLED.equals(action)) {
178             if (mCancelStatus != STATUS_CANCELLING) {
179                 return;
180             }
181             mCancelProgressDialog.dismiss();
182             onProvisioningAborted();
183         }
184     }
185 
onProvisioningAborted()186     private void onProvisioningAborted() {
187         stopService(new Intent(this, ProfileOwnerProvisioningService.class));
188         setResult(Activity.RESULT_CANCELED);
189         finish();
190     }
191 
192     @Override
onBackPressed()193     public void onBackPressed() {
194         if (mCancelStatus == STATUS_PROVISIONING) {
195             mCancelStatus = STATUS_CANCEL_CONFIRMING;
196             showCancelProvisioningDialog();
197         } else {
198             super.onBackPressed();
199         }
200     }
201 
showCancelProvisioningDialog()202     private void showCancelProvisioningDialog() {
203         AlertDialog alertDialog = new AlertDialog.Builder(this)
204                 .setCancelable(false)
205                 .setMessage(R.string.profile_owner_cancel_message)
206                 .setNegativeButton(R.string.profile_owner_cancel_cancel,
207                         new DialogInterface.OnClickListener() {
208                             @Override
209                             public void onClick(DialogInterface dialog,int id) {
210                                 mCancelStatus = STATUS_PROVISIONING;
211                                 if (mPendingProvisioningResult != null) {
212                                     handleProvisioningResult(mPendingProvisioningResult);
213                                 }
214                             }
215                         })
216                 .setPositiveButton(R.string.profile_owner_cancel_ok,
217                         new DialogInterface.OnClickListener() {
218                             @Override
219                             public void onClick(DialogInterface dialog,int id) {
220                                 confirmCancel();
221                             }
222                         })
223                 .create();
224         alertDialog.show();
225     }
226 
showCancelProgressDialog()227     protected void showCancelProgressDialog() {
228         mCancelProgressDialog = new ProgressDialog(this);
229         mCancelProgressDialog.setMessage(getText(R.string.profile_owner_cancelling));
230         mCancelProgressDialog.setCancelable(false);
231         mCancelProgressDialog.setCanceledOnTouchOutside(false);
232         mCancelProgressDialog.show();
233     }
234 
error(int resourceId, String logText)235     public void error(int resourceId, String logText) {
236         ProvisionLogger.loge(logText);
237         new AlertDialog.Builder(this)
238                 .setTitle(R.string.provisioning_error_title)
239                 .setMessage(resourceId)
240                 .setCancelable(false)
241                 .setPositiveButton(R.string.device_owner_error_ok,
242                         new DialogInterface.OnClickListener() {
243                             @Override
244                             public void onClick(DialogInterface dialog,int id) {
245                                 onProvisioningAborted();
246                             }
247                         })
248                 .show();
249     }
250 
confirmCancel()251     private void confirmCancel() {
252         if (mCancelStatus != STATUS_CANCEL_CONFIRMING) {
253             // Can only cancel if provisioning hasn't finished at this point.
254             return;
255         }
256         mCancelStatus = STATUS_CANCELLING;
257         Intent intent = new Intent(ProfileOwnerProvisioningActivity.this,
258                 ProfileOwnerProvisioningService.class);
259         intent.setAction(ACTION_CANCEL_PROVISIONING);
260         startService(intent);
261         showCancelProgressDialog();
262     }
263 
264     /**
265      * Finish activity and stop service.
266      */
onProvisioningSuccess()267     private void onProvisioningSuccess() {
268         mCancelStatus = STATUS_FINALIZING;
269         stopService(new Intent(this, ProfileOwnerProvisioningService.class));
270         setResult(Activity.RESULT_OK);
271         finish();
272     }
273 
274     @Override
onSaveInstanceState(Bundle outState)275     protected void onSaveInstanceState(Bundle outState) {
276         outState.putInt(KEY_STATUS, mCancelStatus);
277         outState.putParcelable(KEY_PENDING_INTENT, mPendingProvisioningResult);
278     }
279 
280     @Override
onPause()281     public void onPause() {
282         LocalBroadcastManager.getInstance(this).unregisterReceiver(mServiceMessageReceiver);
283         super.onPause();
284     }
285 }
286