• 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.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