Home | History | Annotate | Download | only in managedprovisioning
      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 package com.android.managedprovisioning;
     17 
     18 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE;
     19 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME;
     20 
     21 import android.app.Notification;
     22 import android.app.NotificationManager;
     23 import android.app.PendingIntent;
     24 import android.content.BroadcastReceiver;
     25 import android.content.ComponentName;
     26 import android.content.Context;
     27 import android.content.Intent;
     28 import android.os.Bundle;
     29 
     30 /**
     31  * Class that handles the resuming process that takes place after a reboot for encryption
     32  * during the provisioning process.
     33  */
     34 public class BootReminder extends BroadcastReceiver {
     35     private static final int NOTIFY_ID = 1;
     36 
     37     /*
     38      * Profile owner parameters that are stored in the IntentStore for resuming provisioning.
     39      */
     40     private static final String PROFILE_OWNER_PREFERENCES_NAME =
     41             "profile-owner-provisioning-resume";
     42 
     43     private static final String[] PROFILE_OWNER_STRING_EXTRAS = {
     44         // Key for the device admin package name
     45         EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME
     46     };
     47 
     48     private static final String[] PROFILE_OWNER_PERSISTABLE_BUNDLE_EXTRAS = {
     49         // Key for the admin extras bundle
     50         EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE
     51     };
     52 
     53     private static final ComponentName PROFILE_OWNER_INTENT_TARGET =
     54             ManagedProvisioningActivity.ALIAS_NO_CHECK_CALLER;
     55 
     56     /*
     57      * Device owner parameters that are stored in the IntentStore for resuming provisioning.
     58      */
     59     private static final String DEVICE_OWNER_PREFERENCES_NAME =
     60             "device-owner-provisioning-resume";
     61 
     62     private static final ComponentName DEVICE_OWNER_INTENT_TARGET =
     63             new ComponentName("com.android.managedprovisioning",
     64                     "com.android.managedprovisioning.DeviceOwnerProvisioningActivity");
     65 
     66     @Override
     67     public void onReceive(Context context, Intent intent) {
     68         if (android.content.Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
     69 
     70             // Resume profile owner provisioning if applicable.
     71             IntentStore profileOwnerIntentStore = getProfileOwnerIntentStore(context);
     72             final Intent resumeProfileOwnerPrvIntent = profileOwnerIntentStore.load();
     73             if (resumeProfileOwnerPrvIntent != null) {
     74                 if (EncryptDeviceActivity.isDeviceEncrypted()) {
     75                     // Show reminder notification and then forget about it for next boot
     76                     profileOwnerIntentStore.clear();
     77                     setNotification(context, resumeProfileOwnerPrvIntent);
     78                 }
     79             }
     80 
     81             // Resume device owner provisioning if applicable.
     82             IntentStore deviceOwnerIntentStore = getDeviceOwnerIntentStore(context);
     83             Intent resumeDeviceOwnerPrvIntent = deviceOwnerIntentStore.load();
     84             if (resumeDeviceOwnerPrvIntent != null) {
     85                 deviceOwnerIntentStore.clear();
     86                 resumeDeviceOwnerPrvIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
     87                 context.startActivity(resumeDeviceOwnerPrvIntent);
     88             }
     89         }
     90     }
     91 
     92     /**
     93      * Schedule a provisioning reminder notification for the next reboot.
     94      *
     95      * {@code extras} should be a Bundle containing the
     96      * {@link EncryptDeviceActivity.EXTRA_RESUME_TARGET}.
     97      * This field has only two supported values {@link EncryptDeviceActivity.TARGET_PROFILE_OWNER}
     98      * and {@link EncryptDeviceActivity.TARGET_DEVICE_OWNER}
     99      *
    100      * <p> In case of TARGET_PROFILE_OWNER {@code extras} should further contain a value for at
    101      * least the key: {@link EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}, a {@link String} which
    102      * specifies the package to set as profile owner.
    103      *
    104      * <p>
    105      * See {@link MessageParser} for the TARGET_DEVICE_OWNER case.
    106      * </ul>
    107      *
    108      * <p> These fields will be persisted and restored to the provisioner after rebooting. Any other
    109      * key/value pairs will be ignored.
    110      */
    111     public static void setProvisioningReminder(Context context, Bundle extras) {
    112         IntentStore intentStore;
    113         String resumeTarget = extras.getString(EncryptDeviceActivity.EXTRA_RESUME_TARGET, null);
    114         if (resumeTarget == null) {
    115             return;
    116         }
    117         if (resumeTarget.equals(EncryptDeviceActivity.TARGET_PROFILE_OWNER)) {
    118             intentStore = getProfileOwnerIntentStore(context);
    119         } else if (resumeTarget.equals(EncryptDeviceActivity.TARGET_DEVICE_OWNER)) {
    120             intentStore = getDeviceOwnerIntentStore(context);
    121         } else {
    122             ProvisionLogger.loge("Unknown resume target for bootreminder.");
    123             return;
    124         }
    125         intentStore.save(extras);
    126     }
    127 
    128     /**
    129      * Cancel all active provisioning reminders.
    130      */
    131     public static void cancelProvisioningReminder(Context context) {
    132         getProfileOwnerIntentStore(context).clear();
    133         getDeviceOwnerIntentStore(context).clear();
    134         setNotification(context, null);
    135     }
    136 
    137     private static IntentStore getProfileOwnerIntentStore(Context context) {
    138         return new IntentStore(context,PROFILE_OWNER_INTENT_TARGET, PROFILE_OWNER_PREFERENCES_NAME)
    139                 .setStringKeys(PROFILE_OWNER_STRING_EXTRAS)
    140                 .setPersistableBundleKeys(PROFILE_OWNER_PERSISTABLE_BUNDLE_EXTRAS);
    141     }
    142 
    143     private static IntentStore getDeviceOwnerIntentStore(Context context) {
    144         return new IntentStore(context, DEVICE_OWNER_INTENT_TARGET, DEVICE_OWNER_PREFERENCES_NAME)
    145                 .setStringKeys(MessageParser.DEVICE_OWNER_STRING_EXTRAS)
    146                 .setLongKeys(MessageParser.DEVICE_OWNER_LONG_EXTRAS)
    147                 .setIntKeys(MessageParser.DEVICE_OWNER_INT_EXTRAS)
    148                 .setBooleanKeys(MessageParser.DEVICE_OWNER_BOOLEAN_EXTRAS)
    149                 .setPersistableBundleKeys(MessageParser.DEVICE_OWNER_PERSISTABLE_BUNDLE_EXTRAS);
    150     }
    151 
    152     /** Create and show the provisioning reminder notification. */
    153     private static void setNotification(Context context, Intent intent) {
    154         final NotificationManager notificationManager = (NotificationManager)
    155                 context.getSystemService(Context.NOTIFICATION_SERVICE);
    156         if (intent == null) {
    157             notificationManager.cancel(NOTIFY_ID);
    158             return;
    159         }
    160         final PendingIntent resumePendingIntent = PendingIntent.getActivity(
    161                 context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    162         final Notification.Builder notify = new Notification.Builder(context)
    163                 .setContentIntent(resumePendingIntent)
    164                 .setContentTitle(context.getString(R.string.continue_provisioning_notify_title))
    165                 .setContentText(context.getString(R.string.continue_provisioning_notify_text))
    166                 .setSmallIcon(com.android.internal.R.drawable.ic_corp_statusbar_icon)
    167                 .setVisibility(Notification.VISIBILITY_PUBLIC)
    168                 .setColor(context.getResources().getColor(
    169                         com.android.internal.R.color.system_notification_accent_color))
    170                 .setAutoCancel(true);
    171         notificationManager.notify(NOTIFY_ID, notify.build());
    172     }
    173 }
    174