1 /* 2 * Copyright (C) 2021 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.car.settings.enterprise; 18 19 import android.annotation.Nullable; 20 import android.annotation.UserIdInt; 21 import android.app.Dialog; 22 import android.app.admin.DevicePolicyManager; 23 import android.content.ComponentName; 24 import android.content.Context; 25 import android.content.pm.ApplicationInfo; 26 import android.content.pm.PackageManager; 27 import android.graphics.drawable.Drawable; 28 import android.os.Bundle; 29 import android.os.Process; 30 import android.os.UserHandle; 31 import android.util.IconDrawableFactory; 32 33 import com.android.car.settings.R; 34 import com.android.car.settings.common.Logger; 35 import com.android.car.ui.AlertDialogBuilder; 36 import com.android.car.ui.preference.CarUiDialogFragment; 37 import com.android.settingslib.RestrictedLockUtils; 38 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 39 import com.android.settingslib.RestrictedLockUtilsInternal; 40 import com.android.settingslib.enterprise.ActionDisabledByAdminController; 41 import com.android.settingslib.enterprise.ActionDisabledByAdminControllerFactory; 42 43 /** 44 * Shows a dialog explaining that an action is not enabled due to restrictions imposed by an active 45 * device administrator. 46 */ 47 // TODO(b/186905050): add unit tests 48 // TODO(b/188836559): move most of this class' logic to settingslib 49 public final class ActionDisabledByAdminDialogFragment extends CarUiDialogFragment { 50 51 public static final String DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG = 52 "com.android.car.settings.applications.DisabledByAdminConfirmDialog"; 53 54 private static final String TAG = ActionDisabledByAdminDialogFragment.class.getSimpleName(); 55 private static final Logger LOG = new Logger(TAG); 56 57 private static final String EXTRA_RESTRICTION = TAG + "_restriction"; 58 private static final String EXTRA_USER_ID = TAG + "_userId"; 59 60 private String mRestriction; 61 62 @UserIdInt 63 private int mUserId; 64 65 private ActionDisabledByAdminController mActionDisabledByAdminController; 66 67 /** 68 * Gets the dialog for the given user and restriction. 69 */ newInstance(String restriction, @UserIdInt int userId)70 public static ActionDisabledByAdminDialogFragment newInstance(String restriction, 71 @UserIdInt int userId) { 72 ActionDisabledByAdminDialogFragment instance = new ActionDisabledByAdminDialogFragment(); 73 instance.mRestriction = restriction; 74 instance.mUserId = userId; 75 return instance; 76 } 77 78 @Override onCreateDialog(Bundle savedInstanceState)79 public Dialog onCreateDialog(Bundle savedInstanceState) { 80 if (savedInstanceState != null) { 81 mRestriction = savedInstanceState.getString(EXTRA_RESTRICTION); 82 mUserId = savedInstanceState.getInt(EXTRA_USER_ID); 83 } 84 return initialize(getContext()).create(); 85 } 86 87 @Override onSaveInstanceState(Bundle outState)88 public void onSaveInstanceState(Bundle outState) { 89 super.onSaveInstanceState(outState); 90 91 outState.putString(EXTRA_RESTRICTION, mRestriction); 92 outState.putInt(EXTRA_USER_ID, mUserId); 93 } 94 95 @Override onDialogClosed(boolean positiveResult)96 protected void onDialogClosed(boolean positiveResult) { 97 } 98 initialize(Context context)99 private AlertDialogBuilder initialize(Context context) { 100 EnforcedAdmin enforcedAdmin = RestrictedLockUtilsInternal 101 .checkIfRestrictionEnforced(context, mRestriction, mUserId); 102 103 AlertDialogBuilder builder = new AlertDialogBuilder(context) 104 .setPositiveButton(R.string.okay, /* listener= */ null); 105 mActionDisabledByAdminController = ActionDisabledByAdminControllerFactory 106 .createInstance(context, mRestriction, new DeviceAdminStringProviderImpl(context), 107 context.getUser()); 108 mActionDisabledByAdminController.initialize( 109 new ActionDisabledLearnMoreButtonLauncherImpl(builder)); 110 if (enforcedAdmin != null) { 111 mActionDisabledByAdminController.updateEnforcedAdmin(enforcedAdmin, mUserId); 112 mActionDisabledByAdminController.setupLearnMoreButton(context); 113 } 114 initializeDialogViews(context, builder, enforcedAdmin, 115 getEnforcementAdminUserId(enforcedAdmin)); 116 return builder; 117 } 118 119 // NOTE: methods below were copied from phone Settings 120 // (com.android.settings.enterprise.ActionDisabledByAdminDialogHelper), but adjusted to 121 // use a AlertDialogBuilder directly, instead of an Activity hosting a dialog. 122 getEnforcementAdminUserId(@ullable EnforcedAdmin admin)123 private static @UserIdInt int getEnforcementAdminUserId(@Nullable EnforcedAdmin admin) { 124 return admin == null || admin.user == null ? UserHandle.USER_NULL 125 : admin.user.getIdentifier(); 126 } 127 initializeDialogViews(Context context, AlertDialogBuilder builder, @Nullable EnforcedAdmin enforcedAdmin, @UserIdInt int userId)128 private void initializeDialogViews(Context context, AlertDialogBuilder builder, 129 @Nullable EnforcedAdmin enforcedAdmin, @UserIdInt int userId) { 130 ComponentName admin = null; 131 132 if (enforcedAdmin != null) { 133 admin = enforcedAdmin.component; 134 if (admin == null) { 135 return; 136 } 137 138 mActionDisabledByAdminController.updateEnforcedAdmin(enforcedAdmin, userId); 139 } 140 141 if (isNotCurrentUserOrProfile(context, admin, userId)) { 142 admin = null; 143 } 144 setAdminSupportIcon(context, builder, admin, userId); 145 setAdminSupportTitle(context, builder, mRestriction); 146 147 if (enforcedAdmin != null) { 148 setAdminSupportDetails(context, builder, enforcedAdmin); 149 } 150 } 151 isNotCurrentUserOrProfile(Context context, ComponentName admin, @UserIdInt int userId)152 private boolean isNotCurrentUserOrProfile(Context context, ComponentName admin, 153 @UserIdInt int userId) { 154 return !RestrictedLockUtilsInternal.isAdminInCurrentUserOrProfile(context, admin) 155 || !RestrictedLockUtils.isCurrentUserOrProfile(context, userId); 156 } 157 setAdminSupportIcon(Context context, AlertDialogBuilder builder, ComponentName admin, @UserIdInt int userId)158 private void setAdminSupportIcon(Context context, AlertDialogBuilder builder, 159 ComponentName admin, @UserIdInt int userId) { 160 if (isNotCurrentUserOrProfile(context, admin, userId)) { 161 builder.setIcon(context.getDrawable(com.android.internal.R.drawable.ic_info)); 162 } else { 163 Drawable badgedIcon = getBadgedIcon( 164 IconDrawableFactory.newInstance(context), 165 context.getPackageManager(), 166 admin.getPackageName(), 167 userId); 168 builder.setIcon(badgedIcon); 169 } 170 } 171 setAdminSupportTitle(Context context, AlertDialogBuilder builder, String restriction)172 private void setAdminSupportTitle(Context context, AlertDialogBuilder builder, 173 String restriction) { 174 builder.setTitle(mActionDisabledByAdminController.getAdminSupportTitle(restriction)); 175 } 176 setAdminSupportDetails(Context context, AlertDialogBuilder builder, @Nullable EnforcedAdmin enforcedAdmin)177 private void setAdminSupportDetails(Context context, AlertDialogBuilder builder, 178 @Nullable EnforcedAdmin enforcedAdmin) { 179 if (enforcedAdmin == null || enforcedAdmin.component == null) { 180 LOG.i("setAdminSupportDetails(): no admin on " + enforcedAdmin); 181 return; 182 } 183 CharSequence supportMessage = null; 184 if (!RestrictedLockUtilsInternal.isAdminInCurrentUserOrProfile(context, 185 enforcedAdmin.component) || !RestrictedLockUtils.isCurrentUserOrProfile( 186 context, getEnforcementAdminUserId(enforcedAdmin))) { 187 enforcedAdmin.component = null; 188 } else { 189 if (enforcedAdmin.user == null) { 190 enforcedAdmin.user = UserHandle.of(UserHandle.myUserId()); 191 } 192 if (UserHandle.isSameApp(Process.myUid(), Process.SYSTEM_UID)) { 193 supportMessage = context.getSystemService(DevicePolicyManager.class) 194 .getShortSupportMessageForUser(enforcedAdmin.component, 195 getEnforcementAdminUserId(enforcedAdmin)); 196 } 197 } 198 CharSequence supportContentString = 199 mActionDisabledByAdminController.getAdminSupportContentString( 200 context, supportMessage); 201 if (supportContentString != null) { 202 builder.setMessage(supportContentString); 203 } 204 } 205 206 // Copied from com.android.settings.Utils getBadgedIcon(IconDrawableFactory iconDrawableFactory, PackageManager packageManager, String packageName, int userId)207 private static Drawable getBadgedIcon(IconDrawableFactory iconDrawableFactory, 208 PackageManager packageManager, String packageName, int userId) { 209 try { 210 ApplicationInfo appInfo = packageManager.getApplicationInfoAsUser( 211 packageName, PackageManager.GET_META_DATA, userId); 212 return iconDrawableFactory.getBadgedIcon(appInfo, userId); 213 } catch (PackageManager.NameNotFoundException e) { 214 return packageManager.getDefaultActivityIcon(); 215 } 216 } 217 } 218