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