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.tv.settings; 18 19 import android.content.Context; 20 import android.os.UserHandle; 21 import android.os.UserManager; 22 import android.text.TextUtils; 23 24 import androidx.preference.Preference; 25 import androidx.preference.PreferenceGroup; 26 27 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 28 import com.android.settingslib.RestrictedLockUtilsInternal; 29 import com.android.settingslib.RestrictedPreference; 30 31 import java.util.Collections; 32 import java.util.List; 33 import java.util.function.Consumer; 34 35 /** 36 * Adapter that wraps a regular Preference, and restricts the preference if user restrictions apply. 37 * 38 * <p> 39 * If the user is restricted by an admin, the preference is replaced by a RestrictedPreference. 40 * Some state from the original preference is copied, such as title, summary, and visibility. 41 * The restricted preference shows an explanatory message dialog on click, and does not show a 42 * preview panel. 43 * 44 * <p> 45 * If a base user restriction applies, the original preference is disabled. 46 * 47 * <p> 48 * Updates to the preference should be made through {@link #updatePreference(Consumer)}, so that the 49 * restricted preference can be updated after changes, or the original preference can be kept 50 * disabled. Otherwise, {@link #updatePreference()} can be called after direct edits to 51 * the underlying preference. 52 * 53 * @param <T> the type of the wrapped preference 54 */ 55 public class RestrictedPreferenceAdapter<T extends Preference> { 56 private final Context mContext; 57 private final T mOriginalPreference; 58 private final List<String> mUserRestrictions; 59 private boolean mRestricted; 60 private EnforcedAdmin mEnforcingAdmin; 61 private RestrictedPreference mRestrictedPreference; 62 private boolean mIsApSaved; 63 RestrictedPreferenceAdapter(Context context, T originalPreference, List<String> userRestrictions)64 public RestrictedPreferenceAdapter(Context context, T originalPreference, 65 List<String> userRestrictions) { 66 this.mContext = context; 67 this.mOriginalPreference = originalPreference; 68 this.mUserRestrictions = userRestrictions; 69 70 this.mRestricted = isRestricted(); 71 this.mEnforcingAdmin = isRestrictedByAdmin(); 72 73 if (mEnforcingAdmin != null) { 74 mRestrictedPreference = new RestrictedPreference(mContext); 75 } else { 76 mRestrictedPreference = null; 77 } 78 } 79 RestrictedPreferenceAdapter(Context context, T originalPreference, String userRestriction)80 public RestrictedPreferenceAdapter(Context context, T originalPreference, 81 String userRestriction) { 82 this(context, originalPreference, Collections.singletonList(userRestriction)); 83 } 84 85 /** 86 * Create a RestrictedPreferenceAdapter from a preference. 87 * 88 * @param <T> the type of the preference 89 * @param preference the preference to adapt 90 * @param userRestriction the user restriction to enforce for this preference 91 */ adapt(T preference, String userRestriction)92 public static <T extends Preference> RestrictedPreferenceAdapter<T> adapt(T preference, 93 String userRestriction) { 94 RestrictedPreferenceAdapter<T> adapter = new RestrictedPreferenceAdapter<T>( 95 preference.getContext(), preference, userRestriction); 96 adapter.setup(); 97 return adapter; 98 } 99 setup()100 private void setup() { 101 if (mRestricted) { 102 mOriginalPreference.setEnabled(false); 103 104 if (mEnforcingAdmin != null) { 105 updateRestrictedPreference(); 106 replacePreference(); 107 } 108 } 109 } 110 111 /** 112 * Returns {@code true} if a restriction applies to this preference, {@code false} otherwise. 113 */ isRestricted()114 public boolean isRestricted() { 115 if (mUserRestrictions == null) { 116 return false; 117 } 118 119 UserManager userManager = UserManager.get(mContext); 120 for (String userRestriction : mUserRestrictions) { 121 if (userManager.hasUserRestriction(userRestriction)) { 122 return true; 123 } 124 } 125 126 return false; 127 } 128 129 /** 130 * Returns {@code true} if given restriction applies to this preference, 131 * {@code false} otherwise. 132 */ isRestricted(String restriction)133 public boolean isRestricted(String restriction) { 134 UserManager userManager = UserManager.get(mContext); 135 return userManager.hasUserRestriction(restriction); 136 } 137 isRestrictedByAdmin()138 private EnforcedAdmin isRestrictedByAdmin() { 139 if (mUserRestrictions == null) { 140 return null; 141 } 142 143 for (String userRestriction : mUserRestrictions) { 144 EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced(mContext, 145 userRestriction, UserHandle.myUserId()); 146 if (admin != null) { 147 return admin; 148 } 149 } 150 return null; 151 } 152 replacePreference()153 private void replacePreference() { 154 if (mRestrictedPreference == null) { 155 return; 156 } 157 158 final String key = mOriginalPreference.getKey(); 159 if (TextUtils.isEmpty(key)) { 160 throw new IllegalArgumentException("Can't replace a preference without a key"); 161 } 162 final PreferenceGroup screen = mOriginalPreference.getParent(); 163 final int order = mOriginalPreference.getOrder(); 164 mRestrictedPreference.setOrder(order); 165 screen.removePreference(mOriginalPreference); 166 screen.addPreference(mRestrictedPreference); 167 } 168 169 /** Set access point saved or not. */ setApSaved(boolean saved)170 public void setApSaved(boolean saved) { 171 mIsApSaved = saved; 172 } 173 174 /** 175 * Returns the preference to be inserted into the preference screen. 176 * 177 * If the preference is unrestricted, this returns the underlying original preference. 178 * If the preference is restricted, this returns the RestrictedPreference that replaces 179 * the original preference. 180 */ getPreference()181 public Preference getPreference() { 182 if (mRestrictedPreference != null && (isRestricted(UserManager.DISALLOW_CONFIG_WIFI) 183 || (isRestricted(UserManager.DISALLOW_ADD_WIFI_CONFIG) && !mIsApSaved))) { 184 return mRestrictedPreference; 185 } 186 187 return mOriginalPreference; 188 } 189 190 /** Returns the original preference. */ getOriginalPreference()191 public Preference getOriginalPreference() { 192 return mOriginalPreference; 193 } 194 195 /** 196 * Update the preference. 197 * The update function will be called with the adapted preference, changes will be reflected 198 * on the restricted preference. 199 * 200 * @param updateFn function that is passed the original preference to make updates to 201 */ updatePreference(Consumer<T> updateFn)202 public void updatePreference(Consumer<T> updateFn) { 203 updateFn.accept(mOriginalPreference); 204 updatePreference(); 205 } 206 207 /** 208 * Update the preference. 209 * This copies some attributes from the original preference to the restricted preference. 210 * Call this after making direct changes to the original preference. 211 */ updatePreference()212 public void updatePreference() { 213 mRestricted = isRestricted(); 214 mEnforcingAdmin = isRestrictedByAdmin(); 215 if (mEnforcingAdmin != null) { 216 if (mRestrictedPreference == null) { 217 mRestrictedPreference = new RestrictedPreference(mContext); 218 } 219 } else { 220 mRestrictedPreference = null; 221 } 222 if (mRestricted && isRestricted(UserManager.DISALLOW_CONFIG_WIFI)) { 223 mOriginalPreference.setEnabled(false); 224 } else { 225 mOriginalPreference.setEnabled(true); 226 } 227 updateRestrictedPreference(); 228 } 229 updateRestrictedPreference()230 private void updateRestrictedPreference() { 231 if (mRestrictedPreference == null) { 232 return; 233 } 234 mRestrictedPreference.setKey(mOriginalPreference.getKey()); 235 mRestrictedPreference.setOrder(mOriginalPreference.getOrder()); 236 mRestrictedPreference.setTitle(mOriginalPreference.getTitle()); 237 mRestrictedPreference.setSummary(mOriginalPreference.getSummary()); 238 mRestrictedPreference.setIcon(mOriginalPreference.getIcon()); 239 mRestrictedPreference.setVisible(mOriginalPreference.isVisible()); 240 mRestrictedPreference.setDisabledByAdmin(isRestrictedByAdmin()); 241 } 242 } 243