/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tv.settings;
import android.content.Context;
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
import androidx.preference.Preference;
import androidx.preference.PreferenceGroup;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.RestrictedPreference;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
/**
* Adapter that wraps a regular Preference, and restricts the preference if user restrictions apply.
*
*
* If the user is restricted by an admin, the preference is replaced by a RestrictedPreference.
* Some state from the original preference is copied, such as title, summary, and visibility.
* The restricted preference shows an explanatory message dialog on click, and does not show a
* preview panel.
*
*
* If a base user restriction applies, the original preference is disabled.
*
*
* Updates to the preference should be made through {@link #updatePreference(Consumer)}, so that the
* restricted preference can be updated after changes, or the original preference can be kept
* disabled. Otherwise, {@link #updatePreference()} can be called after direct edits to
* the underlying preference.
*
* @param the type of the wrapped preference
*/
public class RestrictedPreferenceAdapter {
private final Context mContext;
private final T mOriginalPreference;
private final List mUserRestrictions;
private boolean mRestricted;
private EnforcedAdmin mEnforcingAdmin;
private RestrictedPreference mRestrictedPreference;
private boolean mIsApSaved;
public RestrictedPreferenceAdapter(Context context, T originalPreference,
List userRestrictions) {
this.mContext = context;
this.mOriginalPreference = originalPreference;
this.mUserRestrictions = userRestrictions;
this.mRestricted = isRestricted();
this.mEnforcingAdmin = isRestrictedByAdmin();
if (mEnforcingAdmin != null) {
mRestrictedPreference = new RestrictedPreference(mContext);
} else {
mRestrictedPreference = null;
}
}
public RestrictedPreferenceAdapter(Context context, T originalPreference,
String userRestriction) {
this(context, originalPreference, Collections.singletonList(userRestriction));
}
/**
* Create a RestrictedPreferenceAdapter from a preference.
*
* @param the type of the preference
* @param preference the preference to adapt
* @param userRestriction the user restriction to enforce for this preference
*/
public static RestrictedPreferenceAdapter adapt(T preference,
String userRestriction) {
RestrictedPreferenceAdapter adapter = new RestrictedPreferenceAdapter(
preference.getContext(), preference, userRestriction);
adapter.setup();
return adapter;
}
private void setup() {
if (mRestricted) {
mOriginalPreference.setEnabled(false);
if (mEnforcingAdmin != null) {
updateRestrictedPreference();
replacePreference();
}
}
}
/**
* Returns {@code true} if a restriction applies to this preference, {@code false} otherwise.
*/
public boolean isRestricted() {
if (mUserRestrictions == null) {
return false;
}
UserManager userManager = UserManager.get(mContext);
for (String userRestriction : mUserRestrictions) {
if (userManager.hasUserRestriction(userRestriction)) {
return true;
}
}
return false;
}
/**
* Returns {@code true} if given restriction applies to this preference,
* {@code false} otherwise.
*/
public boolean isRestricted(String restriction) {
UserManager userManager = UserManager.get(mContext);
return userManager.hasUserRestriction(restriction);
}
private EnforcedAdmin isRestrictedByAdmin() {
if (mUserRestrictions == null) {
return null;
}
for (String userRestriction : mUserRestrictions) {
EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced(mContext,
userRestriction, UserHandle.myUserId());
if (admin != null) {
return admin;
}
}
return null;
}
private void replacePreference() {
if (mRestrictedPreference == null) {
return;
}
final String key = mOriginalPreference.getKey();
if (TextUtils.isEmpty(key)) {
throw new IllegalArgumentException("Can't replace a preference without a key");
}
final PreferenceGroup screen = mOriginalPreference.getParent();
final int order = mOriginalPreference.getOrder();
mRestrictedPreference.setOrder(order);
screen.removePreference(mOriginalPreference);
screen.addPreference(mRestrictedPreference);
}
/** Set access point saved or not. */
public void setApSaved(boolean saved) {
mIsApSaved = saved;
}
/**
* Returns the preference to be inserted into the preference screen.
*
* If the preference is unrestricted, this returns the underlying original preference.
* If the preference is restricted, this returns the RestrictedPreference that replaces
* the original preference.
*/
public Preference getPreference() {
if (mRestrictedPreference != null && (isRestricted(UserManager.DISALLOW_CONFIG_WIFI)
|| (isRestricted(UserManager.DISALLOW_ADD_WIFI_CONFIG) && !mIsApSaved))) {
return mRestrictedPreference;
}
return mOriginalPreference;
}
/** Returns the original preference. */
public Preference getOriginalPreference() {
return mOriginalPreference;
}
/**
* Update the preference.
* The update function will be called with the adapted preference, changes will be reflected
* on the restricted preference.
*
* @param updateFn function that is passed the original preference to make updates to
*/
public void updatePreference(Consumer updateFn) {
updateFn.accept(mOriginalPreference);
updatePreference();
}
/**
* Update the preference.
* This copies some attributes from the original preference to the restricted preference.
* Call this after making direct changes to the original preference.
*/
public void updatePreference() {
mRestricted = isRestricted();
mEnforcingAdmin = isRestrictedByAdmin();
if (mEnforcingAdmin != null) {
if (mRestrictedPreference == null) {
mRestrictedPreference = new RestrictedPreference(mContext);
}
} else {
mRestrictedPreference = null;
}
if (mRestricted && isRestricted(UserManager.DISALLOW_CONFIG_WIFI)) {
mOriginalPreference.setEnabled(false);
} else {
mOriginalPreference.setEnabled(true);
}
updateRestrictedPreference();
}
private void updateRestrictedPreference() {
if (mRestrictedPreference == null) {
return;
}
mRestrictedPreference.setKey(mOriginalPreference.getKey());
mRestrictedPreference.setOrder(mOriginalPreference.getOrder());
mRestrictedPreference.setTitle(mOriginalPreference.getTitle());
mRestrictedPreference.setSummary(mOriginalPreference.getSummary());
mRestrictedPreference.setIcon(mOriginalPreference.getIcon());
mRestrictedPreference.setVisible(mOriginalPreference.isVisible());
mRestrictedPreference.setDisabledByAdmin(isRestrictedByAdmin());
}
}