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