1 /* 2 * Copyright (C) 2016 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.settingslib; 18 19 import static android.app.admin.DevicePolicyResources.Strings.Settings.CONTROLLED_BY_ADMIN_SUMMARY; 20 21 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 22 23 import android.app.admin.DevicePolicyManager; 24 import android.content.Context; 25 import android.content.res.TypedArray; 26 import android.os.Build; 27 import android.os.UserHandle; 28 import android.text.TextUtils; 29 import android.util.AttributeSet; 30 import android.util.TypedValue; 31 import android.widget.TextView; 32 33 import androidx.annotation.RequiresApi; 34 import androidx.preference.Preference; 35 import androidx.preference.PreferenceViewHolder; 36 37 import com.android.settingslib.utils.BuildCompatUtils; 38 39 /** 40 * Helper class for managing settings preferences that can be disabled 41 * by device admins via user restrictions. 42 */ 43 public class RestrictedPreferenceHelper { 44 private final Context mContext; 45 private final Preference mPreference; 46 String packageName; 47 int uid; 48 49 private boolean mDisabledByAdmin; 50 private EnforcedAdmin mEnforcedAdmin; 51 private String mAttrUserRestriction = null; 52 private boolean mDisabledSummary = false; 53 54 private boolean mDisabledByAppOps; 55 RestrictedPreferenceHelper(Context context, Preference preference, AttributeSet attrs, String packageName, int uid)56 public RestrictedPreferenceHelper(Context context, Preference preference, 57 AttributeSet attrs, String packageName, int uid) { 58 mContext = context; 59 mPreference = preference; 60 this.packageName = packageName; 61 this.uid = uid; 62 63 if (attrs != null) { 64 final TypedArray attributes = context.obtainStyledAttributes(attrs, 65 R.styleable.RestrictedPreference); 66 final TypedValue userRestriction = 67 attributes.peekValue(R.styleable.RestrictedPreference_userRestriction); 68 CharSequence data = null; 69 if (userRestriction != null && userRestriction.type == TypedValue.TYPE_STRING) { 70 if (userRestriction.resourceId != 0) { 71 data = context.getText(userRestriction.resourceId); 72 } else { 73 data = userRestriction.string; 74 } 75 } 76 mAttrUserRestriction = data == null ? null : data.toString(); 77 // If the system has set the user restriction, then we shouldn't add the padlock. 78 if (RestrictedLockUtilsInternal.hasBaseUserRestriction(mContext, mAttrUserRestriction, 79 UserHandle.myUserId())) { 80 mAttrUserRestriction = null; 81 return; 82 } 83 84 final TypedValue useAdminDisabledSummary = 85 attributes.peekValue(R.styleable.RestrictedPreference_useAdminDisabledSummary); 86 if (useAdminDisabledSummary != null) { 87 mDisabledSummary = 88 (useAdminDisabledSummary.type == TypedValue.TYPE_INT_BOOLEAN 89 && useAdminDisabledSummary.data != 0); 90 } 91 } 92 } 93 RestrictedPreferenceHelper(Context context, Preference preference, AttributeSet attrs)94 public RestrictedPreferenceHelper(Context context, Preference preference, 95 AttributeSet attrs) { 96 this(context, preference, attrs, null, android.os.Process.INVALID_UID); 97 } 98 99 /** 100 * Modify PreferenceViewHolder to add padlock if restriction is disabled. 101 */ onBindViewHolder(PreferenceViewHolder holder)102 public void onBindViewHolder(PreferenceViewHolder holder) { 103 if (mDisabledByAdmin || mDisabledByAppOps) { 104 holder.itemView.setEnabled(true); 105 } 106 if (mDisabledSummary) { 107 final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary); 108 if (summaryView != null) { 109 final CharSequence disabledText = BuildCompatUtils.isAtLeastT() 110 ? getDisabledByAdminUpdatableString() 111 : mContext.getString(R.string.disabled_by_admin_summary_text); 112 if (mDisabledByAdmin) { 113 summaryView.setText(disabledText); 114 } else if (mDisabledByAppOps) { 115 summaryView.setText(R.string.disabled_by_app_ops_text); 116 } else if (TextUtils.equals(disabledText, summaryView.getText())) { 117 // It's previously set to disabled text, clear it. 118 summaryView.setText(null); 119 } 120 } 121 } 122 } 123 124 @RequiresApi(Build.VERSION_CODES.TIRAMISU) getDisabledByAdminUpdatableString()125 private String getDisabledByAdminUpdatableString() { 126 return mContext.getSystemService(DevicePolicyManager.class).getResources().getString( 127 CONTROLLED_BY_ADMIN_SUMMARY, 128 () -> mContext.getString(R.string.disabled_by_admin_summary_text)); 129 } 130 useAdminDisabledSummary(boolean useSummary)131 public void useAdminDisabledSummary(boolean useSummary) { 132 mDisabledSummary = useSummary; 133 } 134 135 /** 136 * Check if the preference is disabled if so handle the click by informing the user. 137 * 138 * @return true if the method handled the click. 139 */ 140 @SuppressWarnings("NewApi") performClick()141 public boolean performClick() { 142 if (mDisabledByAdmin) { 143 RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext, mEnforcedAdmin); 144 return true; 145 } 146 if (mDisabledByAppOps) { 147 RestrictedLockUtilsInternal.sendShowRestrictedSettingDialogIntent(mContext, packageName, 148 uid); 149 return true; 150 } 151 return false; 152 } 153 154 /** 155 * Disable / enable if we have been passed the restriction in the xml. 156 */ onAttachedToHierarchy()157 public void onAttachedToHierarchy() { 158 if (mAttrUserRestriction != null) { 159 checkRestrictionAndSetDisabled(mAttrUserRestriction, UserHandle.myUserId()); 160 } 161 } 162 163 /** 164 * Set the user restriction that is used to disable this preference. 165 * 166 * @param userRestriction constant from {@link android.os.UserManager} 167 * @param userId user to check the restriction for. 168 */ checkRestrictionAndSetDisabled(String userRestriction, int userId)169 public void checkRestrictionAndSetDisabled(String userRestriction, int userId) { 170 EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced(mContext, 171 userRestriction, userId); 172 setDisabledByAdmin(admin); 173 } 174 175 /** 176 * @return EnforcedAdmin if we have been passed the restriction in the xml. 177 */ checkRestrictionEnforced()178 public EnforcedAdmin checkRestrictionEnforced() { 179 if (mAttrUserRestriction == null) { 180 return null; 181 } 182 return RestrictedLockUtilsInternal.checkIfRestrictionEnforced(mContext, 183 mAttrUserRestriction, UserHandle.myUserId()); 184 } 185 186 /** 187 * Disable this preference based on the enforce admin. 188 * 189 * @param admin details of the admin who enforced the restriction. If it is 190 * {@code null}, then this preference will be enabled. Otherwise, it will be disabled. 191 * Only gray out the preference which is not {@link RestrictedTopLevelPreference}. 192 * @return true if the disabled state was changed. 193 */ setDisabledByAdmin(EnforcedAdmin admin)194 public boolean setDisabledByAdmin(EnforcedAdmin admin) { 195 final boolean disabled = (admin != null ? true : false); 196 mEnforcedAdmin = admin; 197 boolean changed = false; 198 if (mDisabledByAdmin != disabled) { 199 mDisabledByAdmin = disabled; 200 changed = true; 201 updateDisabledState(); 202 } 203 204 return changed; 205 } 206 setDisabledByAppOps(boolean disabled)207 public boolean setDisabledByAppOps(boolean disabled) { 208 boolean changed = false; 209 if (mDisabledByAppOps != disabled) { 210 mDisabledByAppOps = disabled; 211 changed = true; 212 updateDisabledState(); 213 } 214 215 return changed; 216 } 217 isDisabledByAdmin()218 public boolean isDisabledByAdmin() { 219 return mDisabledByAdmin; 220 } 221 isDisabledByAppOps()222 public boolean isDisabledByAppOps() { 223 return mDisabledByAppOps; 224 } 225 updatePackageDetails(String packageName, int uid)226 public void updatePackageDetails(String packageName, int uid) { 227 this.packageName = packageName; 228 this.uid = uid; 229 } 230 updateDisabledState()231 private void updateDisabledState() { 232 if (!(mPreference instanceof RestrictedTopLevelPreference)) { 233 mPreference.setEnabled(!(mDisabledByAdmin || mDisabledByAppOps)); 234 } 235 236 if (mPreference instanceof PrimarySwitchPreference) { 237 ((PrimarySwitchPreference) mPreference) 238 .setSwitchEnabled(!(mDisabledByAdmin || mDisabledByAppOps)); 239 } 240 } 241 } 242