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 package com.android.car.settings.enterprise; 17 18 import static com.android.car.settings.common.PreferenceController.AVAILABLE; 19 import static com.android.car.settings.common.PreferenceController.AVAILABLE_FOR_VIEWING; 20 import static com.android.car.settings.common.PreferenceController.DISABLED_FOR_PROFILE; 21 import static com.android.car.settings.enterprise.ActionDisabledByAdminDialogFragment.DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG; 22 23 import android.Manifest; 24 import android.annotation.Nullable; 25 import android.annotation.UserIdInt; 26 import android.app.admin.DeviceAdminInfo; 27 import android.app.admin.DevicePolicyManager; 28 import android.content.ComponentName; 29 import android.content.Context; 30 import android.content.Intent; 31 import android.content.pm.ActivityInfo; 32 import android.content.pm.PackageManager; 33 import android.os.Bundle; 34 import android.os.UserHandle; 35 import android.os.UserManager; 36 import android.widget.Toast; 37 38 import com.android.car.settings.R; 39 import com.android.car.settings.common.FragmentController; 40 import com.android.car.settings.common.Logger; 41 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 42 import com.android.settingslib.RestrictedLockUtilsInternal; 43 44 import org.xmlpull.v1.XmlPullParserException; 45 46 import java.io.IOException; 47 import java.util.List; 48 49 /** 50 * Generic helper methods for this package. 51 */ 52 public final class EnterpriseUtils { 53 54 private static final Logger LOG = new Logger(EnterpriseUtils.class); 55 // TODO: ideally, we should not create a special user restriction other than what are 56 // defined in UserManager. 57 public static final String DISABLED_INPUT_METHOD = "disabled-input-method"; 58 // TODO: same as for DISABLED_INPUT_METHOD 59 public static final String BLOCKED_UNINSTALL_APP = "blocked-uninstall-app"; 60 61 static final String[] CAMERA_PERMISSIONS = new String[] { 62 Manifest.permission.CAMERA 63 }; 64 static final String[] LOCATION_PERMISSIONS = new String[] { 65 Manifest.permission.ACCESS_COARSE_LOCATION, 66 Manifest.permission.ACCESS_FINE_LOCATION 67 }; 68 static final String[] MICROPHONE_PERMISSIONS = new String[] { 69 Manifest.permission.RECORD_AUDIO 70 }; 71 72 /** 73 * Gets the active admin for the given package. 74 */ 75 @Nullable getAdminWithinPackage(Context context, String packageName)76 public static ComponentName getAdminWithinPackage(Context context, String packageName) { 77 List<ComponentName> admins = context.getSystemService(DevicePolicyManager.class) 78 .getActiveAdmins(); 79 if (admins == null) { 80 LOG.v("getAdminWithinPackage(): no active admins on context"); 81 return null; 82 } 83 return admins.stream().filter(i -> i.getPackageName().equals(packageName)).findAny() 84 .orElse(null); 85 } 86 87 /** 88 * Gets the active admin info for the given admin . 89 */ 90 @Nullable getDeviceAdminInfo(Context context, ComponentName admin)91 public static DeviceAdminInfo getDeviceAdminInfo(Context context, ComponentName admin) { 92 LOG.d("getDeviceAdminInfo()(): " + admin.flattenToShortString()); 93 94 ActivityInfo ai; 95 try { 96 ai = context.getPackageManager().getReceiverInfo(admin, PackageManager.GET_META_DATA); 97 } catch (PackageManager.NameNotFoundException e) { 98 LOG.v("Unable to get activity info for " + admin.flattenToShortString() + ": " + e); 99 return null; 100 } 101 102 try { 103 return new DeviceAdminInfo(context, ai); 104 } catch (XmlPullParserException | IOException e) { 105 LOG.v("Unable to retrieve device policy for " + admin.flattenToShortString() + ": ", 106 e); 107 return null; 108 } 109 } 110 111 /** 112 * Checks whether current user has the flag {@link UserManager.FLAG_DEMO}. 113 */ isDemoUser(Context context)114 public static boolean isDemoUser(Context context) { 115 return UserManager.isDeviceInDemoMode(context) 116 && getUserManager(context).isDemoUser(); 117 } 118 119 /** 120 * Checks whether current user has the flag {@link UserManager.FLAG_ADMIN}. 121 */ isAdminUser(Context context)122 public static boolean isAdminUser(Context context) { 123 return getUserManager(context).isAdminUser(); 124 } 125 126 /** Returns the default availability status when a user is restricted by a given restriction */ getAvailabilityStatusRestricted(Context context, String restriction)127 public static int getAvailabilityStatusRestricted(Context context, String restriction) { 128 if (hasUserRestrictionByUm(context, restriction)) { 129 return DISABLED_FOR_PROFILE; 130 } 131 if (hasUserRestrictionByDpm(context, restriction)) { 132 return AVAILABLE_FOR_VIEWING; 133 } 134 return AVAILABLE; 135 } 136 137 /** 138 * Checks whether the restriction is set on the current user by device owner / profile owners 139 * but not by {@link UserManager}. 140 * 141 * <p>This includes restriction set on device owner but current user has affiliated profile 142 * owner. 143 */ hasUserRestrictionByDpm(Context context, String restriction)144 public static boolean hasUserRestrictionByDpm(Context context, String restriction) { 145 if (hasUserRestrictionByUm(context, restriction)) { 146 return false; 147 } 148 return getUserManager(context).hasUserRestriction(restriction); 149 } 150 151 /** 152 * Checks whether there are restrictions set via {@link UserManager} which doesn't include 153 * restrictions set by device owner / profile owners. 154 */ hasUserRestrictionByUm(Context context, String restriction)155 public static boolean hasUserRestrictionByUm(Context context, String restriction) { 156 return getUserManager(context) 157 .hasBaseUserRestriction(restriction, UserHandle.of(context.getUserId())); 158 } 159 160 /** Handles onClick() behavior for a disabled preference that has been user restricted */ onClickWhileDisabled(Context context, FragmentController fragmentController, String restriction)161 public static void onClickWhileDisabled(Context context, FragmentController fragmentController, 162 String restriction) { 163 if (hasUserRestrictionByDpm(context, restriction)) { 164 showActionDisabledByAdminDialog(context, fragmentController, restriction); 165 } else { 166 showActionUnavailableToast(context); 167 } 168 } 169 showActionDisabledByAdminDialog(Context context, FragmentController fragmentController, String restriction)170 private static void showActionDisabledByAdminDialog(Context context, 171 FragmentController fragmentController, String restriction) { 172 fragmentController.showDialog( 173 EnterpriseUtils.getActionDisabledByAdminDialog(context, restriction), 174 DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG); 175 } 176 showActionUnavailableToast(Context context)177 private static void showActionUnavailableToast(Context context) { 178 Toast.makeText(context, context.getString(R.string.action_unavailable), 179 Toast.LENGTH_LONG).show(); 180 LOG.d(context.getString(R.string.action_unavailable)); 181 } 182 183 /** 184 * Checks whether the device is managed. 185 */ isDeviceManaged(Context context)186 public static boolean isDeviceManaged(Context context) { 187 DevicePolicyManager dpm = getDevicePolicyManager(context); 188 return dpm.isDeviceManaged(); 189 } 190 191 /** 192 * Checks whether device owner is set on the device. 193 */ hasDeviceOwner(Context context)194 public static boolean hasDeviceOwner(Context context) { 195 DevicePolicyManager dpm = getDevicePolicyManager(context); 196 return dpm.isDeviceManaged() && getDeviceOwner(context) != null; 197 } 198 199 /** 200 * Gets device owner user id on the device. 201 */ 202 @UserIdInt getDeviceOwnerUserId(Context context)203 private static int getDeviceOwnerUserId(Context context) { 204 return getDevicePolicyManager(context).getDeviceOwnerUserId(); 205 } 206 207 /** 208 * Gets device owner component on the device. 209 */ 210 @Nullable getDeviceOwner(Context context)211 private static ComponentName getDeviceOwner(Context context) { 212 return getDevicePolicyManager(context).getDeviceOwnerComponentOnAnyUser(); 213 } 214 getUserManager(Context context)215 private static UserManager getUserManager(Context context) { 216 return context.getSystemService(UserManager.class); 217 } 218 getDevicePolicyManager(Context context)219 private static DevicePolicyManager getDevicePolicyManager(Context context) { 220 return context.getSystemService(DevicePolicyManager.class); 221 } 222 223 /** 224 * Gets an {@code ActionDisabledByAdminDialogFragment} for the target restriction to show on 225 * the current user. 226 */ getActionDisabledByAdminDialog( Context context, String restriction)227 public static ActionDisabledByAdminDialogFragment getActionDisabledByAdminDialog( 228 Context context, String restriction) { 229 return getActionDisabledByAdminDialog(context, restriction, /* restrictedPackage= */ null); 230 } 231 232 /** 233 * Gets an {@code ActionDisabledByAdminDialogFragment} when the input method is restricted for 234 * the current user. 235 */ getInputMethodDisabledByAdminDialog( Context context, String restriction)236 public static ActionDisabledByAdminDialogFragment getInputMethodDisabledByAdminDialog( 237 Context context, String restriction) { 238 return getActionDisabledByAdminDialog(context, restriction, /* restrictedPackage= */ null); 239 } 240 241 /** 242 * Gets an {@code ActionDisabledByAdminDialogFragment} for the target restriction to show on 243 * the current user with additional restricted package information. 244 */ getActionDisabledByAdminDialog( Context context, String restriction, @Nullable String restrictedPackage)245 public static ActionDisabledByAdminDialogFragment getActionDisabledByAdminDialog( 246 Context context, String restriction, @Nullable String restrictedPackage) { 247 int adminUser = hasDeviceOwner(context) 248 ? getDeviceOwnerUserId(context) 249 : context.getUserId(); 250 return ActionDisabledByAdminDialogFragment 251 .newInstance(restriction, restrictedPackage, adminUser); 252 } 253 254 /** 255 * Gets enforced admin information from Intent that started the 256 * {@code ActionDisabledByAdminDialogActivity}. 257 */ getEnforcedAdminFromIntent(Context context, Intent intent)258 public static EnforcedAdmin getEnforcedAdminFromIntent(Context context, Intent intent) { 259 EnforcedAdmin admin = new EnforcedAdmin(null, context.getUser()); 260 if (intent == null) { 261 return admin; 262 } 263 admin.component = intent.getParcelableExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN); 264 int userId = intent.getIntExtra(Intent.EXTRA_USER_ID, context.getUserId()); 265 266 Bundle adminDetails = null; 267 if (admin.component == null) { 268 DevicePolicyManager devicePolicyManager = getDevicePolicyManager(context); 269 admin.component = adminDetails.getParcelable(DevicePolicyManager.EXTRA_DEVICE_ADMIN); 270 } 271 272 if (intent.hasExtra(Intent.EXTRA_USER)) { 273 admin.user = intent.getParcelableExtra(Intent.EXTRA_USER); 274 } else { 275 if (adminDetails != null) { 276 userId = adminDetails.getInt(Intent.EXTRA_USER_ID, UserHandle.myUserId()); 277 } 278 if (userId == UserHandle.USER_NULL) { 279 admin.user = null; 280 } else { 281 admin.user = UserHandle.of(userId); 282 } 283 } 284 return admin; 285 } 286 287 /** 288 * Gets {@code RestrictedLockUtils.EnforcedAdmin} for the device policy that affects 289 * current user. 290 * 291 * @param context for current user 292 * @param adminUser which can be either profile owner on current user or device owner on 293 * headless system user 294 * @param restriction which can be user restriction or restriction policy defined 295 * in this class 296 * @param restrictedPackage is the target package that restriction policy is set 297 * @return {@code RestrictedLockUtils.EnforcedAdmin} 298 */ getEnforcedAdmin(Context context, @UserIdInt int adminUser, @Nullable String restriction, String restrictedPackage)299 public static EnforcedAdmin getEnforcedAdmin(Context context, @UserIdInt int adminUser, 300 @Nullable String restriction, String restrictedPackage) { 301 if (restriction == null) { 302 return null; 303 } 304 EnforcedAdmin admin = null; 305 if (hasUserRestrictionByDpm(context, restriction)) { 306 admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced( 307 context, restriction, context.getUserId()); 308 LOG.v("getEnforcedAdmin(): " + adminUser + " restriction: " + restriction 309 + " restrictedPackage: " + restrictedPackage); 310 311 if (admin.component == null && context.getUserId() != adminUser) { 312 // User restriction might be set on primary user which is user 0 as a device-wide 313 // policy. 314 admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced( 315 context, restriction, adminUser); 316 } 317 } else if (restriction.equals(DISABLED_INPUT_METHOD)) { 318 if (restrictedPackage == null) { 319 LOG.e("getEnforcedAdmin() for " + DISABLED_INPUT_METHOD 320 + " fails since restrictedPackage is null"); 321 return admin; 322 } 323 admin = RestrictedLockUtilsInternal.checkIfInputMethodDisallowed( 324 context, restrictedPackage, context.getUserId()); 325 } else if (restriction.equals(BLOCKED_UNINSTALL_APP)) { 326 admin = RestrictedLockUtilsInternal.checkIfUninstallBlocked( 327 context, restrictedPackage, context.getUserId()); 328 } 329 LOG.v("getEnforcedAdmin():" + admin); 330 return admin; 331 } 332 EnterpriseUtils()333 private EnterpriseUtils() { 334 throw new UnsupportedOperationException("Provides only static methods"); 335 } 336 } 337