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.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
     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
     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
     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
    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
    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
    146     public void requestWifiPick() {
    147         startActivityForResult(mUtils.getWifiPickIntent(), WIFI_REQUEST_CODE);
    148     }
    149 
    150     @Override
    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 
    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
    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
    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
    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 
    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
    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
    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
    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
    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
    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
    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
    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