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 */ 16package com.android.managedprovisioning; 17 18import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE; 19import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME; 20 21import android.app.Notification; 22import android.app.NotificationManager; 23import android.app.PendingIntent; 24import android.content.BroadcastReceiver; 25import android.content.ComponentName; 26import android.content.Context; 27import android.content.Intent; 28import 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 */ 34public 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