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.app.admin.DeviceAdminInfo; 20 import android.app.admin.DeviceAdminReceiver; 21 import android.app.admin.DevicePolicyManager; 22 import android.car.drivingstate.CarUxRestrictions; 23 import android.content.ComponentName; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.pm.ActivityInfo; 27 import android.content.pm.PackageManager; 28 import android.content.pm.ResolveInfo; 29 import android.text.TextUtils; 30 31 import androidx.annotation.Nullable; 32 import androidx.preference.Preference; 33 import androidx.preference.PreferenceGroup; 34 35 import com.android.car.settings.R; 36 import com.android.car.settings.common.FragmentController; 37 import com.android.car.ui.preference.CarUiPreference; 38 39 import org.xmlpull.v1.XmlPullParserException; 40 41 import java.io.IOException; 42 import java.util.List; 43 44 /** 45 * Displays a list of device admin apps. 46 * <p>Before changing the value of a permission, the user is directed to a confirmation 47 * screen with more detailed information about the risks and potential effects. 48 */ 49 public abstract class DeviceAdminAppsPreferenceController 50 extends BaseEnterprisePreferenceController<PreferenceGroup> { 51 DeviceAdminAppsPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)52 public DeviceAdminAppsPreferenceController(Context context, String preferenceKey, 53 FragmentController fragmentController, CarUxRestrictions uxRestrictions) { 54 super(context, preferenceKey, fragmentController, uxRestrictions); 55 } 56 57 @Override getPreferenceType()58 protected Class<PreferenceGroup> getPreferenceType() { 59 return PreferenceGroup.class; 60 } 61 62 @Override updateState(PreferenceGroup preferenceGroup)63 protected void updateState(PreferenceGroup preferenceGroup) { 64 preferenceGroup.removeAll(); 65 66 // NOTE: Only considering the current user for now. Later we may need to support profiles. 67 List<ResolveInfo> receivers = mPm.queryBroadcastReceivers( 68 new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED), 69 PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS); 70 for (ResolveInfo resolveInfo : receivers) { 71 DeviceAdminInfo deviceAdminInfo = createDeviceAdminInfo(resolveInfo.activityInfo); 72 // Add only visible ones (note: active admins are added regardless of visibility) 73 if (deviceAdminInfo != null && deviceAdminInfo.isVisible()) { 74 if (!isIncluded(deviceAdminInfo.getComponent()) 75 || !deviceAdminInfo.getActivityInfo().applicationInfo.isInternal()) { 76 continue; 77 } 78 preferenceGroup.addPreference(createPreference(deviceAdminInfo)); 79 } 80 } 81 82 if (preferenceGroup.getPreferenceCount() == 0) { 83 preferenceGroup.addPreference(createEmptyListPreference()); 84 } 85 } 86 isIncluded(ComponentName componentName)87 protected abstract boolean isIncluded(ComponentName componentName); 88 isActivated(ComponentName componentName)89 protected boolean isActivated(ComponentName componentName) { 90 return mDpm.isAdminActive(componentName); 91 } 92 createEmptyListPreference()93 private Preference createEmptyListPreference() { 94 CarUiPreference preference = new CarUiPreference(getContext()); 95 preference.setTitle(R.string.device_admin_apps_list_empty); 96 preference.setSelectable(false); 97 98 return preference; 99 } 100 createPreference(DeviceAdminInfo deviceAdminInfo)101 private Preference createPreference(DeviceAdminInfo deviceAdminInfo) { 102 CarUiPreference preference = new CarUiPreference(getContext()); 103 preference.setTitle(deviceAdminInfo.loadLabel(mPm)); 104 preference.setIcon(deviceAdminInfo.loadIcon(mPm)); 105 CharSequence description = getDescription(deviceAdminInfo); 106 if (!TextUtils.isEmpty(description)) { 107 preference.setSummary(deviceAdminInfo.loadDescription(mPm)); 108 } 109 preference.setKey(deviceAdminInfo.getPackageName()); 110 ComponentName componentName = deviceAdminInfo.getComponent(); 111 preference.setEnabled(isEnabled(componentName)); 112 preference.setOnPreferenceClickListener(p -> launchDetailScreen(componentName)); 113 114 return preference; 115 } 116 isEnabled(ComponentName componentName)117 private boolean isEnabled(ComponentName componentName) { 118 return !mDpm.isRemovingAdmin(componentName, getContext().getUserId()); 119 } 120 launchDetailScreen(ComponentName componentName)121 private boolean launchDetailScreen(ComponentName componentName) { 122 Intent intent = new Intent(getContext(), DeviceAdminAddActivity.class) 123 .putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, componentName); 124 mLogger.d("Created intent " + intent + " for component: " + componentName); 125 getContext().startActivity(intent); 126 127 return true; 128 } 129 createDeviceAdminInfo(ActivityInfo ai)130 private @Nullable DeviceAdminInfo createDeviceAdminInfo(ActivityInfo ai) { 131 try { 132 return new DeviceAdminInfo(getContext(), ai); 133 } catch (XmlPullParserException | IOException e) { 134 mLogger.w("Skipping " + ai, e); 135 } 136 return null; 137 } 138 } 139