1 /* 2 * Copyright (C) 2017 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.settings.dashboard; 18 19 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 20 21 import android.app.Activity; 22 import android.content.BroadcastReceiver; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.IntentFilter; 26 import android.content.RestrictionsManager; 27 import android.os.Bundle; 28 import android.os.PersistableBundle; 29 import android.os.UserHandle; 30 import android.os.UserManager; 31 import android.view.View; 32 import android.widget.TextView; 33 34 import com.android.settings.R; 35 import com.android.settings.RestrictedSettingsFragment; 36 import com.android.settings.ShowAdminSupportDetailsDialog; 37 import com.android.settingslib.RestrictedLockUtils; 38 39 /** 40 * Base class for settings screens that should be pin protected when in restricted mode or 41 * that will display an admin support message in case an admin has disabled the options. 42 * The constructor for this class will take the restriction key that this screen should be 43 * locked by. If {@link RestrictionsManager.hasRestrictionsProvider()} and 44 * {@link UserManager.hasUserRestriction()}, then the user will have to enter the restrictions 45 * pin before seeing the Settings screen. 46 * 47 * {@link RestrictionsManager.hasRestrictionsProvider()} returns true, pass in 48 * {@link RESTRICT_IF_OVERRIDABLE} to the constructor instead of a restrictions key. 49 * 50 * This fragment is a replacement of {@link RestrictedSettingsFragment} but extends 51 * from {@link DashboardFragment}, so we could also use 52 * {@link com.android.settingslib.core.AbstractPreferenceController} in this fragment. 53 */ 54 public abstract class RestrictedDashboardFragment extends DashboardFragment { 55 56 protected static final String RESTRICT_IF_OVERRIDABLE = "restrict_if_overridable"; 57 58 // No RestrictedSettingsFragment screens should use this number in startActivityForResult. 59 private static final int REQUEST_PIN_CHALLENGE = 12309; 60 61 private static final String KEY_CHALLENGE_SUCCEEDED = "chsc"; 62 private static final String KEY_CHALLENGE_REQUESTED = "chrq"; 63 64 // If the restriction PIN is entered correctly. 65 private boolean mChallengeSucceeded; 66 private boolean mChallengeRequested; 67 68 private UserManager mUserManager; 69 private RestrictionsManager mRestrictionsManager; 70 71 private final String mRestrictionKey; 72 private View mAdminSupportDetails; 73 private EnforcedAdmin mEnforcedAdmin; 74 private TextView mEmptyTextView; 75 76 private boolean mOnlyAvailableForAdmins = false; 77 private boolean mIsAdminUser; 78 79 // Receiver to clear pin status when the screen is turned off. 80 private BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() { 81 @Override 82 public void onReceive(Context context, Intent intent) { 83 if (!mChallengeRequested) { 84 mChallengeSucceeded = false; 85 mChallengeRequested = false; 86 } 87 } 88 }; 89 90 /** 91 * @param restrictionKey The restriction key to check before pin protecting 92 * this settings page. Pass in {@link RESTRICT_IF_OVERRIDABLE} if it should 93 * be protected whenever a restrictions provider is set. Pass in 94 * null if it should never be protected. 95 */ RestrictedDashboardFragment(String restrictionKey)96 public RestrictedDashboardFragment(String restrictionKey) { 97 mRestrictionKey = restrictionKey; 98 } 99 100 @Override onCreate(Bundle icicle)101 public void onCreate(Bundle icicle) { 102 super.onCreate(icicle); 103 104 mRestrictionsManager = (RestrictionsManager) getSystemService(Context.RESTRICTIONS_SERVICE); 105 mUserManager = (UserManager) getSystemService(Context.USER_SERVICE); 106 mIsAdminUser = mUserManager.isAdminUser(); 107 108 if (icicle != null) { 109 mChallengeSucceeded = icicle.getBoolean(KEY_CHALLENGE_SUCCEEDED, false); 110 mChallengeRequested = icicle.getBoolean(KEY_CHALLENGE_REQUESTED, false); 111 } 112 113 IntentFilter offFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF); 114 offFilter.addAction(Intent.ACTION_USER_PRESENT); 115 getActivity().registerReceiver(mScreenOffReceiver, offFilter); 116 } 117 118 @Override onActivityCreated(Bundle savedInstanceState)119 public void onActivityCreated(Bundle savedInstanceState) { 120 super.onActivityCreated(savedInstanceState); 121 mAdminSupportDetails = initAdminSupportDetailsView(); 122 mEmptyTextView = initEmptyTextView(); 123 } 124 125 @Override onSaveInstanceState(Bundle outState)126 public void onSaveInstanceState(Bundle outState) { 127 super.onSaveInstanceState(outState); 128 129 if (getActivity().isChangingConfigurations()) { 130 outState.putBoolean(KEY_CHALLENGE_REQUESTED, mChallengeRequested); 131 outState.putBoolean(KEY_CHALLENGE_SUCCEEDED, mChallengeSucceeded); 132 } 133 } 134 135 @Override onResume()136 public void onResume() { 137 super.onResume(); 138 139 if (shouldBeProviderProtected(mRestrictionKey)) { 140 ensurePin(); 141 } 142 } 143 144 @Override onDestroy()145 public void onDestroy() { 146 getActivity().unregisterReceiver(mScreenOffReceiver); 147 super.onDestroy(); 148 } 149 150 @Override onActivityResult(int requestCode, int resultCode, Intent data)151 public void onActivityResult(int requestCode, int resultCode, Intent data) { 152 if (requestCode == REQUEST_PIN_CHALLENGE) { 153 if (resultCode == Activity.RESULT_OK) { 154 mChallengeSucceeded = true; 155 mChallengeRequested = false; 156 } else { 157 mChallengeSucceeded = false; 158 } 159 return; 160 } 161 162 super.onActivityResult(requestCode, resultCode, data); 163 } 164 ensurePin()165 private void ensurePin() { 166 if (!mChallengeSucceeded && !mChallengeRequested 167 && mRestrictionsManager.hasRestrictionsProvider()) { 168 Intent intent = mRestrictionsManager.createLocalApprovalIntent(); 169 if (intent != null) { 170 mChallengeRequested = true; 171 mChallengeSucceeded = false; 172 PersistableBundle request = new PersistableBundle(); 173 request.putString(RestrictionsManager.REQUEST_KEY_MESSAGE, 174 getResources().getString(R.string.restr_pin_enter_admin_pin)); 175 intent.putExtra(RestrictionsManager.EXTRA_REQUEST_BUNDLE, request); 176 startActivityForResult(intent, REQUEST_PIN_CHALLENGE); 177 } 178 } 179 } 180 181 /** 182 * Returns true if this activity is restricted, but no restrictions provider has been set. 183 * Used to determine if the settings UI should disable UI. 184 */ isRestrictedAndNotProviderProtected()185 protected boolean isRestrictedAndNotProviderProtected() { 186 if (mRestrictionKey == null || RESTRICT_IF_OVERRIDABLE.equals(mRestrictionKey)) { 187 return false; 188 } 189 return mUserManager.hasUserRestriction(mRestrictionKey) 190 && !mRestrictionsManager.hasRestrictionsProvider(); 191 } 192 hasChallengeSucceeded()193 protected boolean hasChallengeSucceeded() { 194 return (mChallengeRequested && mChallengeSucceeded) || !mChallengeRequested; 195 } 196 197 /** 198 * Returns true if this restrictions key is locked down. 199 */ shouldBeProviderProtected(String restrictionKey)200 protected boolean shouldBeProviderProtected(String restrictionKey) { 201 if (restrictionKey == null) { 202 return false; 203 } 204 boolean restricted = RESTRICT_IF_OVERRIDABLE.equals(restrictionKey) 205 || mUserManager.hasUserRestriction(mRestrictionKey); 206 return restricted && mRestrictionsManager.hasRestrictionsProvider(); 207 } 208 initAdminSupportDetailsView()209 private View initAdminSupportDetailsView() { 210 return getActivity().findViewById(R.id.admin_support_details); 211 } 212 initEmptyTextView()213 protected TextView initEmptyTextView() { 214 TextView emptyView = (TextView) getActivity().findViewById(android.R.id.empty); 215 return emptyView; 216 } 217 getRestrictionEnforcedAdmin()218 public EnforcedAdmin getRestrictionEnforcedAdmin() { 219 mEnforcedAdmin = RestrictedLockUtils.checkIfRestrictionEnforced(getActivity(), 220 mRestrictionKey, UserHandle.myUserId()); 221 if (mEnforcedAdmin != null && mEnforcedAdmin.userId == UserHandle.USER_NULL) { 222 mEnforcedAdmin.userId = UserHandle.myUserId(); 223 } 224 return mEnforcedAdmin; 225 } 226 getEmptyTextView()227 public TextView getEmptyTextView() { 228 return mEmptyTextView; 229 } 230 231 @Override onDataSetChanged()232 protected void onDataSetChanged() { 233 highlightPreferenceIfNeeded(); 234 if (mAdminSupportDetails != null && isUiRestrictedByOnlyAdmin()) { 235 final EnforcedAdmin admin = getRestrictionEnforcedAdmin(); 236 ShowAdminSupportDetailsDialog.setAdminSupportDetails(getActivity(), 237 mAdminSupportDetails, admin, false); 238 setEmptyView(mAdminSupportDetails); 239 } else if (mEmptyTextView != null) { 240 setEmptyView(mEmptyTextView); 241 } 242 super.onDataSetChanged(); 243 } 244 setIfOnlyAvailableForAdmins(boolean onlyForAdmins)245 public void setIfOnlyAvailableForAdmins(boolean onlyForAdmins) { 246 mOnlyAvailableForAdmins = onlyForAdmins; 247 } 248 249 /** 250 * Returns whether restricted or actionable UI elements should be removed or disabled. 251 */ isUiRestricted()252 protected boolean isUiRestricted() { 253 return isRestrictedAndNotProviderProtected() || !hasChallengeSucceeded() 254 || (!mIsAdminUser && mOnlyAvailableForAdmins); 255 } 256 isUiRestrictedByOnlyAdmin()257 protected boolean isUiRestrictedByOnlyAdmin() { 258 return isUiRestricted() && !mUserManager.hasBaseUserRestriction(mRestrictionKey, 259 UserHandle.of(UserHandle.myUserId())) && (mIsAdminUser || !mOnlyAvailableForAdmins); 260 } 261 } 262