• 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.uiflows;
18 
19 import android.annotation.NonNull;
20 import android.app.Activity;
21 import android.app.AlertDialog;
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.DialogInterface;
25 import android.content.Intent;
26 import android.os.Bundle;
27 import android.os.UserHandle;
28 import android.os.UserManager;
29 import android.provider.Settings;
30 import android.view.View;
31 import android.widget.Button;
32 import android.widget.ImageView;
33 import android.widget.TextView;
34 
35 import com.android.managedprovisioning.DeleteManagedProfileDialog;
36 import com.android.managedprovisioning.DeviceOwnerProvisioningActivity;
37 import com.android.managedprovisioning.LogoUtils;
38 import com.android.managedprovisioning.ProfileOwnerProvisioningActivity;
39 import com.android.managedprovisioning.ProvisionLogger;
40 import com.android.managedprovisioning.R;
41 import com.android.managedprovisioning.SetupLayoutActivity;
42 import com.android.managedprovisioning.UserConsentDialog;
43 import com.android.managedprovisioning.common.MdmPackageInfo;
44 import com.android.managedprovisioning.model.ProvisioningParams;
45 
46 public class PreProvisioningActivity extends SetupLayoutActivity
47         implements UserConsentDialog.ConsentCallback,
48         DeleteManagedProfileDialog.DeleteManagedProfileCallback,
49         PreProvisioningController.Ui {
50 
51     protected static final int ENCRYPT_DEVICE_REQUEST_CODE = 1;
52     protected static final int PROVISIONING_REQUEST_CODE = 2;
53     protected static final int WIFI_REQUEST_CODE = 3;
54     protected static final int CHANGE_LAUNCHER_REQUEST_CODE = 4;
55 
56     // Note: must match the constant defined in HomeSettings
57     private static final String EXTRA_SUPPORT_MANAGED_PROFILES = "support_managed_profiles";
58 
59     protected PreProvisioningController mController;
60 
61     protected TextView mConsentMessageTextView;
62     protected TextView mMdmInfoTextView;
63 
64     @Override
onCreate(Bundle savedInstanceState)65     protected void onCreate(Bundle savedInstanceState) {
66         super.onCreate(savedInstanceState);
67 
68         mController = new PreProvisioningController(
69                 this,
70                 this);
71 
72         mController.initiateProvisioning(getIntent(), getCallingPackage());
73     }
74 
75     @Override
finish()76     public void finish() {
77         // The user has backed out of provisioning, so we perform the necessary clean up steps.
78         LogoUtils.cleanUp(this);
79         EncryptionController.getInstance(this).cancelEncryptionReminder();
80         super.finish();
81     }
82 
83     @Override
onActivityResult(int requestCode, int resultCode, Intent data)84     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
85         if (requestCode == ENCRYPT_DEVICE_REQUEST_CODE) {
86             if (resultCode == RESULT_CANCELED) {
87                 ProvisionLogger.loge("User canceled device encryption.");
88                 setResult(Activity.RESULT_CANCELED);
89                 finish();
90             }
91         } else if (requestCode == PROVISIONING_REQUEST_CODE) {
92             setResult(resultCode);
93             finish();
94         } else if (requestCode == CHANGE_LAUNCHER_REQUEST_CODE) {
95             if (!mUtils.currentLauncherSupportsManagedProfiles(this)) {
96                 showCurrentLauncherInvalid();
97             } else {
98                 startProfileOwnerProvisioning(mController.getParams());
99             }
100         } else if (requestCode == WIFI_REQUEST_CODE) {
101             if (resultCode == RESULT_CANCELED) {
102                 ProvisionLogger.loge("User canceled wifi picking.");
103                 setResult(RESULT_CANCELED);
104                 finish();
105             } else if (resultCode == RESULT_OK) {
106                 ProvisionLogger.logd("Wifi request result is OK");
107                 if (mUtils.isConnectedToWifi(this)) {
108                     mController.askForConsentOrStartDeviceOwnerProvisioning();
109                 } else {
110                     requestWifiPick();
111                 }
112             }
113         } else {
114             ProvisionLogger.logw("Unknown result code :" + resultCode);
115         }
116     }
117 
118     @Override
showErrorAndClose(int resourceId, String logText)119     public void showErrorAndClose(int resourceId, String logText) {
120         ProvisionLogger.loge(logText);
121         new AlertDialog.Builder(this)
122                 .setTitle(R.string.provisioning_error_title)
123                 .setMessage(resourceId)
124                 .setCancelable(false)
125                 .setPositiveButton(R.string.device_owner_error_ok,
126                         new DialogInterface.OnClickListener() {
127                             @Override
128                             public void onClick(DialogInterface dialog,int id) {
129                                 // Close activity
130                                 PreProvisioningActivity.this.setResult(
131                                         Activity.RESULT_CANCELED);
132                                 PreProvisioningActivity.this.finish();
133                             }
134                         })
135                 .show();
136     }
137 
138     @Override
requestEncryption(ProvisioningParams params)139     public void requestEncryption(ProvisioningParams params) {
140         Intent encryptIntent = new Intent(this, EncryptDeviceActivity.class);
141         encryptIntent.putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, params);
142         startActivityForResult(encryptIntent, ENCRYPT_DEVICE_REQUEST_CODE);
143     }
144 
145     @Override
requestWifiPick()146     public void requestWifiPick() {
147         startActivityForResult(mUtils.getWifiPickIntent(), WIFI_REQUEST_CODE);
148     }
149 
150     @Override
showCurrentLauncherInvalid()151     public void showCurrentLauncherInvalid() {
152         new AlertDialog.Builder(this)
153                 .setCancelable(false)
154                 .setMessage(R.string.managed_provisioning_not_supported_by_launcher)
155                 .setNegativeButton(R.string.cancel_provisioning,
156                         new DialogInterface.OnClickListener() {
157                             @Override
158                             public void onClick(DialogInterface dialog,int id) {
159                                 dialog.dismiss();
160                                 setResult(Activity.RESULT_CANCELED);
161                                 finish();
162                             }
163                         })
164                 .setPositiveButton(R.string.pick_launcher,
165                         new DialogInterface.OnClickListener() {
166                             @Override
167                             public void onClick(DialogInterface dialog,int id) {
168                                 requestLauncherPick();
169                             }
170                         })
171                 .show();
172     }
173 
requestLauncherPick()174     private void requestLauncherPick() {
175         Intent changeLauncherIntent = new Intent(Settings.ACTION_HOME_SETTINGS);
176         changeLauncherIntent.putExtra(EXTRA_SUPPORT_MANAGED_PROFILES, true);
177         startActivityForResult(changeLauncherIntent, CHANGE_LAUNCHER_REQUEST_CODE);
178     }
179 
180     @Override
startDeviceOwnerProvisioning(int userId, ProvisioningParams params)181     public void startDeviceOwnerProvisioning(int userId, ProvisioningParams params) {
182         Intent intent = new Intent(this, DeviceOwnerProvisioningActivity.class);
183         intent.putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, params);
184         startActivityForResultAsUser(intent, PROVISIONING_REQUEST_CODE, new UserHandle(userId));
185         // Set cross-fade transition animation into the interstitial progress activity.
186         overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
187     }
188 
189     @Override
startProfileOwnerProvisioning(ProvisioningParams params)190     public void startProfileOwnerProvisioning(ProvisioningParams params) {
191         Intent intent = new Intent(this, ProfileOwnerProvisioningActivity.class);
192         intent.putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, params);
193         startActivityForResult(intent, PROVISIONING_REQUEST_CODE);
194         // Set cross-fade transition animation into the interstitial progress activity.
195         overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
196     }
197 
198     @Override
initiateUi(int headerRes, int titleRes, int consentRes, int mdmInfoRes, ProvisioningParams params)199     public void initiateUi(int headerRes, int titleRes, int consentRes, int mdmInfoRes,
200             ProvisioningParams params) {
201         // Setup the UI.
202         initializeLayoutParams(R.layout.user_consent, headerRes, false);
203         Button nextButton = (Button) findViewById(R.id.setup_button);
204         nextButton.setOnClickListener(new View.OnClickListener() {
205             @Override
206             public void onClick(View v) {
207                 mController.afterNavigateNext();
208             }
209         });
210         nextButton.setText(R.string.next);
211 
212         mConsentMessageTextView = (TextView) findViewById(R.id.user_consent_message);
213         mMdmInfoTextView = (TextView) findViewById(R.id.mdm_info_message);
214 
215         mConsentMessageTextView.setText(consentRes);
216         mMdmInfoTextView.setText(mdmInfoRes);
217 
218         setMdmIconAndLabel(params.inferDeviceAdminPackageName());
219 
220         maybeSetLogoAndMainColor(params.mainColor);
221 
222         setTitle(titleRes);
223     }
224 
setMdmIconAndLabel(@onNull String packageName)225     private void setMdmIconAndLabel(@NonNull String packageName) {
226         MdmPackageInfo packageInfo = MdmPackageInfo.createFromPackageName(this, packageName);
227         TextView deviceManagerName = (TextView) findViewById(R.id.device_manager_name);
228         if (packageInfo != null) {
229             String appLabel = packageInfo.appLabel;
230             ImageView imageView = (ImageView) findViewById(R.id.device_manager_icon_view);
231             imageView.setImageDrawable(packageInfo.packageIcon);
232             imageView.setContentDescription(
233                     getResources().getString(R.string.mdm_icon_label, appLabel));
234 
235             deviceManagerName.setText(appLabel);
236         } else {
237             // During provisioning from trusted source, the package is not actually on the device
238             // yet, so show a default information.
239             deviceManagerName.setText(packageName);
240         }
241     }
242 
243     @Override
showUserConsentDialog(ProvisioningParams params, boolean isProfileOwnerProvisioning)244     public void showUserConsentDialog(ProvisioningParams params,
245             boolean isProfileOwnerProvisioning) {
246         UserConsentDialog dialog;
247         if (isProfileOwnerProvisioning) {
248             dialog = UserConsentDialog.newProfileOwnerInstance();
249         } else {
250             dialog = UserConsentDialog.newDeviceOwnerInstance(!params.startedByTrustedSource);
251         }
252         dialog.show(getFragmentManager(), "UserConsentDialogFragment");
253     }
254 
255     /**
256      * Callback for successful user consent request.
257      */
258     @Override
onDialogConsent()259     public void onDialogConsent() {
260         // Right after user consent, provisioning will be started. To avoid talkback reading out
261         // the activity title in the time this activity briefly comes back to the foreground, we
262         // remove the title.
263         setTitle("");
264 
265         mController.continueProvisioningAfterUserConsent();
266     }
267 
268     /**
269      * Callback for cancelled user consent request.
270      */
271     @Override
onDialogCancel()272     public void onDialogCancel() {
273         // only show special UI for device owner provisioning.
274         if (mController.isProfileOwnerProvisioning()) {
275             return;
276         }
277 
278         // For Nfc provisioning, we automatically show the user consent dialog if applicable.
279         // If the user then decides to cancel, we should finish the entire activity and exit.
280         // For other cases, dismissing the consent dialog will lead back to PreProvisioningActivity,
281         // where we show another dialog asking for user confirmation to cancel the setup and
282         // factory reset the device.
283         if (mController.getParams().startedByTrustedSource) {
284             setResult(RESULT_CANCELED);
285             finish();
286         } else {
287             new AlertDialog.Builder(this)
288                     .setTitle(R.string.cancel_setup_and_factory_reset_dialog_title)
289                     .setMessage(R.string.cancel_setup_and_factory_reset_dialog_msg)
290                     .setNegativeButton(R.string.cancel_setup_and_factory_reset_dialog_cancel, null)
291                     .setPositiveButton(R.string.cancel_setup_and_factory_reset_dialog_ok,
292                             new AlertDialog.OnClickListener() {
293                                 @Override
294                                 public void onClick(DialogInterface dialog, int id) {
295                                     mUtils.sendFactoryResetBroadcast(
296                                             PreProvisioningActivity.this,
297                                             "Device owner setup cancelled");
298                                 }
299                             })
300                     .show();
301         }
302     }
303 
304     @Override
showDeleteManagedProfileDialog(ComponentName mdmPackageName, String domainName, int userId)305     public void showDeleteManagedProfileDialog(ComponentName mdmPackageName, String domainName,
306             int userId) {
307         DeleteManagedProfileDialog.newInstance(userId, mdmPackageName, domainName)
308                 .show(getFragmentManager(), "DeleteManagedProfileDialogFragment");
309     }
310 
311     /**
312      * Callback for user agreeing to remove existing managed profile.
313      */
314     @Override
onRemoveProfileApproval(int existingManagedProfileUserId)315     public void onRemoveProfileApproval(int existingManagedProfileUserId) {
316         UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
317         userManager.removeUser(existingManagedProfileUserId);
318     }
319 
320     /**
321      * Callback for cancelled deletion of existing managed profile.
322      */
323     @Override
onRemoveProfileCancel()324     public void onRemoveProfileCancel() {
325         setResult(Activity.RESULT_CANCELED);
326         finish();
327     }
328 
329     /**
330      * When the user backs out of creating a managed profile, show a dialog to double check.
331      */
332     @Override
onBackPressed()333     public void onBackPressed() {
334         if (!mController.isProfileOwnerProvisioning()) {
335             super.onBackPressed();
336             return;
337         }
338         // TODO: Update strings for managed user case
339         new AlertDialog.Builder(this)
340                 .setTitle(R.string.work_profile_setup_later_title)
341                 .setMessage(R.string.work_profile_setup_later_message)
342                 .setCancelable(false)
343                 .setPositiveButton(R.string.work_profile_setup_stop,
344                         new DialogInterface.OnClickListener() {
345                             @Override
346                             public void onClick(DialogInterface dialog,int id) {
347                                 PreProvisioningActivity.this.setResult(
348                                         Activity.RESULT_CANCELED);
349                                 PreProvisioningActivity.this.finish();
350                             }
351                         })
352                 .setNegativeButton(R.string.work_profile_setup_continue,
353                         new DialogInterface.OnClickListener() {
354                             @Override
355                             public void onClick(DialogInterface dialog, int id) {
356                               // user chose to continue. Do nothing
357                             }
358                         })
359                 .show();
360     }
361 }
362