blob: 8258678791ae1d847b37690348ec0c801cef83cd [file] [log] [blame]
jackqdyuleie407e672017-05-05 16:07:48 -07001/*
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
17package com.android.settings.dashboard;
18
19import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
20
21import android.app.Activity;
arangelov93081542017-10-27 13:51:28 +010022import android.app.AlertDialog;
jackqdyuleie407e672017-05-05 16:07:48 -070023import android.content.BroadcastReceiver;
24import android.content.Context;
25import android.content.Intent;
26import android.content.IntentFilter;
27import android.content.RestrictionsManager;
28import android.os.Bundle;
29import android.os.PersistableBundle;
30import android.os.UserHandle;
31import android.os.UserManager;
32import android.view.View;
33import android.widget.TextView;
34
35import com.android.settings.R;
36import com.android.settings.RestrictedSettingsFragment;
Fan Zhangc7162cd2018-06-18 15:21:41 -070037import com.android.settings.enterprise.ActionDisabledByAdminDialogHelper;
jackqdyuleie407e672017-05-05 16:07:48 -070038import com.android.settingslib.RestrictedLockUtils;
39
40/**
41 * Base class for settings screens that should be pin protected when in restricted mode or
42 * that will display an admin support message in case an admin has disabled the options.
43 * The constructor for this class will take the restriction key that this screen should be
44 * locked by. If {@link RestrictionsManager.hasRestrictionsProvider()} and
45 * {@link UserManager.hasUserRestriction()}, then the user will have to enter the restrictions
46 * pin before seeing the Settings screen.
47 *
48 * {@link RestrictionsManager.hasRestrictionsProvider()} returns true, pass in
49 * {@link RESTRICT_IF_OVERRIDABLE} to the constructor instead of a restrictions key.
50 *
51 * This fragment is a replacement of {@link RestrictedSettingsFragment} but extends
52 * from {@link DashboardFragment}, so we could also use
Tony Mantler1d583e12017-06-13 13:09:25 -070053 * {@link com.android.settingslib.core.AbstractPreferenceController} in this fragment.
jackqdyuleie407e672017-05-05 16:07:48 -070054 */
55public abstract class RestrictedDashboardFragment extends DashboardFragment {
56
57 protected static final String RESTRICT_IF_OVERRIDABLE = "restrict_if_overridable";
58
59 // No RestrictedSettingsFragment screens should use this number in startActivityForResult.
60 private static final int REQUEST_PIN_CHALLENGE = 12309;
61
62 private static final String KEY_CHALLENGE_SUCCEEDED = "chsc";
63 private static final String KEY_CHALLENGE_REQUESTED = "chrq";
64
65 // If the restriction PIN is entered correctly.
66 private boolean mChallengeSucceeded;
67 private boolean mChallengeRequested;
68
69 private UserManager mUserManager;
70 private RestrictionsManager mRestrictionsManager;
71
72 private final String mRestrictionKey;
jackqdyuleie407e672017-05-05 16:07:48 -070073 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 };
arangelov93081542017-10-27 13:51:28 +010089 private AlertDialog mActionDisabledDialog;
jackqdyuleie407e672017-05-05 16:07:48 -070090
91 /**
92 * @param restrictionKey The restriction key to check before pin protecting
93 * this settings page. Pass in {@link RESTRICT_IF_OVERRIDABLE} if it should
94 * be protected whenever a restrictions provider is set. Pass in
95 * null if it should never be protected.
96 */
97 public RestrictedDashboardFragment(String restrictionKey) {
98 mRestrictionKey = restrictionKey;
99 }
100
101 @Override
102 public void onCreate(Bundle icicle) {
103 super.onCreate(icicle);
104
105 mRestrictionsManager = (RestrictionsManager) getSystemService(Context.RESTRICTIONS_SERVICE);
106 mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);
107 mIsAdminUser = mUserManager.isAdminUser();
108
109 if (icicle != null) {
110 mChallengeSucceeded = icicle.getBoolean(KEY_CHALLENGE_SUCCEEDED, false);
111 mChallengeRequested = icicle.getBoolean(KEY_CHALLENGE_REQUESTED, false);
112 }
113
114 IntentFilter offFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
115 offFilter.addAction(Intent.ACTION_USER_PRESENT);
116 getActivity().registerReceiver(mScreenOffReceiver, offFilter);
117 }
118
119 @Override
120 public void onActivityCreated(Bundle savedInstanceState) {
121 super.onActivityCreated(savedInstanceState);
jackqdyuleie407e672017-05-05 16:07:48 -0700122 mEmptyTextView = initEmptyTextView();
123 }
124
125 @Override
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
136 public void onResume() {
137 super.onResume();
138
139 if (shouldBeProviderProtected(mRestrictionKey)) {
140 ensurePin();
141 }
142 }
143
144 @Override
145 public void onDestroy() {
146 getActivity().unregisterReceiver(mScreenOffReceiver);
147 super.onDestroy();
148 }
149
150 @Override
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
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 */
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
193 protected boolean hasChallengeSucceeded() {
194 return (mChallengeRequested && mChallengeSucceeded) || !mChallengeRequested;
195 }
196
197 /**
198 * Returns true if this restrictions key is locked down.
199 */
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
jackqdyuleie407e672017-05-05 16:07:48 -0700209 protected TextView initEmptyTextView() {
210 TextView emptyView = (TextView) getActivity().findViewById(android.R.id.empty);
211 return emptyView;
212 }
213
214 public EnforcedAdmin getRestrictionEnforcedAdmin() {
215 mEnforcedAdmin = RestrictedLockUtils.checkIfRestrictionEnforced(getActivity(),
216 mRestrictionKey, UserHandle.myUserId());
217 if (mEnforcedAdmin != null && mEnforcedAdmin.userId == UserHandle.USER_NULL) {
218 mEnforcedAdmin.userId = UserHandle.myUserId();
219 }
220 return mEnforcedAdmin;
221 }
222
223 public TextView getEmptyTextView() {
224 return mEmptyTextView;
225 }
226
227 @Override
228 protected void onDataSetChanged() {
229 highlightPreferenceIfNeeded();
arangelov93081542017-10-27 13:51:28 +0100230 if (isUiRestrictedByOnlyAdmin()
231 && (mActionDisabledDialog == null || !mActionDisabledDialog.isShowing())) {
jackqdyuleie407e672017-05-05 16:07:48 -0700232 final EnforcedAdmin admin = getRestrictionEnforcedAdmin();
arangelov93081542017-10-27 13:51:28 +0100233 mActionDisabledDialog = new ActionDisabledByAdminDialogHelper(getActivity())
234 .prepareDialogBuilder(mRestrictionKey, admin)
235 .setOnDismissListener(__ -> getActivity().finish())
236 .show();
237 setEmptyView(new View(getContext()));
jackqdyuleie407e672017-05-05 16:07:48 -0700238 } else if (mEmptyTextView != null) {
239 setEmptyView(mEmptyTextView);
240 }
241 super.onDataSetChanged();
242 }
243
244 public void setIfOnlyAvailableForAdmins(boolean onlyForAdmins) {
245 mOnlyAvailableForAdmins = onlyForAdmins;
246 }
247
248 /**
249 * Returns whether restricted or actionable UI elements should be removed or disabled.
250 */
251 protected boolean isUiRestricted() {
252 return isRestrictedAndNotProviderProtected() || !hasChallengeSucceeded()
253 || (!mIsAdminUser && mOnlyAvailableForAdmins);
254 }
255
256 protected boolean isUiRestrictedByOnlyAdmin() {
257 return isUiRestricted() && !mUserManager.hasBaseUserRestriction(mRestrictionKey,
258 UserHandle.of(UserHandle.myUserId())) && (mIsAdminUser || !mOnlyAvailableForAdmins);
259 }
260}