• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.app.AlertDialog;
23 import android.content.BroadcastReceiver;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.content.RestrictionsManager;
28 import android.os.Bundle;
29 import android.os.PersistableBundle;
30 import android.os.UserHandle;
31 import android.os.UserManager;
32 import android.view.View;
33 import android.widget.TextView;
34 
35 import com.android.settings.enterprise.ActionDisabledByAdminDialogHelper;
36 import com.android.settings.R;
37 import com.android.settings.RestrictedSettingsFragment;
38 import 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
53  * {@link com.android.settingslib.core.AbstractPreferenceController} in this fragment.
54  */
55 public 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;
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     private AlertDialog mActionDisabledDialog;
90 
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      */
RestrictedDashboardFragment(String restrictionKey)97     public RestrictedDashboardFragment(String restrictionKey) {
98         mRestrictionKey = restrictionKey;
99     }
100 
101     @Override
onCreate(Bundle icicle)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
onActivityCreated(Bundle savedInstanceState)120     public void onActivityCreated(Bundle savedInstanceState) {
121         super.onActivityCreated(savedInstanceState);
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 
initEmptyTextView()209     protected TextView initEmptyTextView() {
210         TextView emptyView = (TextView) getActivity().findViewById(android.R.id.empty);
211         return emptyView;
212     }
213 
getRestrictionEnforcedAdmin()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 
getEmptyTextView()223     public TextView getEmptyTextView() {
224         return mEmptyTextView;
225     }
226 
227     @Override
onDataSetChanged()228     protected void onDataSetChanged() {
229         highlightPreferenceIfNeeded();
230         if (isUiRestrictedByOnlyAdmin()
231                 && (mActionDisabledDialog == null || !mActionDisabledDialog.isShowing())) {
232             final EnforcedAdmin admin = getRestrictionEnforcedAdmin();
233             mActionDisabledDialog = new ActionDisabledByAdminDialogHelper(getActivity())
234                     .prepareDialogBuilder(mRestrictionKey, admin)
235                     .setOnDismissListener(__ -> getActivity().finish())
236                     .show();
237             setEmptyView(new View(getContext()));
238         } else if (mEmptyTextView != null) {
239             setEmptyView(mEmptyTextView);
240         }
241         super.onDataSetChanged();
242     }
243 
setIfOnlyAvailableForAdmins(boolean onlyForAdmins)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      */
isUiRestricted()251     protected boolean isUiRestricted() {
252         return isRestrictedAndNotProviderProtected() || !hasChallengeSucceeded()
253                 || (!mIsAdminUser && mOnlyAvailableForAdmins);
254     }
255 
isUiRestrictedByOnlyAdmin()256     protected boolean isUiRestrictedByOnlyAdmin() {
257         return isUiRestricted() && !mUserManager.hasBaseUserRestriction(mRestrictionKey,
258                 UserHandle.of(UserHandle.myUserId())) && (mIsAdminUser || !mOnlyAvailableForAdmins);
259     }
260 }
261