RestrictedSettingsFragment.java revision d6e493f6499c3be4a0a5af14eb433dec2ab725d3
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
17package com.android.settings;
18
19import java.util.HashSet;
20
21import android.app.Activity;
22import android.content.BroadcastReceiver;
23import android.content.Context;
24import android.content.Intent;
25import android.content.IntentFilter;
26import android.content.RestrictionsManager;
27import android.os.Bundle;
28import android.os.PersistableBundle;
29import android.os.UserManager;
30import android.preference.CheckBoxPreference;
31import android.preference.Preference;
32
33/**
34 * Base class for settings screens that should be pin protected when in restricted mode.
35 * The constructor for this class will take the restriction key that this screen should be
36 * locked by.  If {@link RestrictionsManager.hasRestrictionsProvider()} and
37 * {@link UserManager.hasUserRestriction()}, then the user will have to enter the restrictions
38 * pin before seeing the Settings screen.
39 *
40 * If this settings screen should be pin protected whenever
41 * {@link RestrictionsManager.hasRestrictionsProvider()} returns true, pass in
42 * {@link RESTRICT_IF_OVERRIDABLE} to the constructor instead of a restrictions key.
43 */
44public class RestrictedSettingsFragment extends SettingsPreferenceFragment {
45
46    protected static final String RESTRICT_IF_OVERRIDABLE = "restrict_if_overridable";
47
48    // No RestrictedSettingsFragment screens should use this number in startActivityForResult.
49    private static final int REQUEST_PIN_CHALLENGE = 12309;
50
51    private static final String KEY_CHALLENGE_SUCCEEDED = "chsc";
52    private static final String KEY_CHALLENGE_REQUESTED = "chrq";
53
54    // If the restriction PIN is entered correctly.
55    private boolean mChallengeSucceeded;
56    private boolean mChallengeRequested;
57
58    private UserManager mUserManager;
59    private RestrictionsManager mRestrictionsManager;
60
61    private final String mRestrictionKey;
62
63    // Receiver to clear pin status when the screen is turned off.
64    private BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() {
65        @Override
66        public void onReceive(Context context, Intent intent) {
67            if (!mChallengeRequested) {
68                mChallengeSucceeded = false;
69                mChallengeRequested = false;
70            }
71        }
72    };
73
74    /**
75     * @param restrictionKey The restriction key to check before pin protecting
76     *            this settings page. Pass in {@link RESTRICT_IF_OVERRIDABLE} if it should
77     *            be protected whenever a restrictions provider is set. Pass in
78     *            null if it should never be protected.
79     */
80    public RestrictedSettingsFragment(String restrictionKey) {
81        mRestrictionKey = restrictionKey;
82    }
83
84    @Override
85    public void onCreate(Bundle icicle) {
86        super.onCreate(icicle);
87
88        mRestrictionsManager = (RestrictionsManager) getSystemService(Context.RESTRICTIONS_SERVICE);
89        mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);
90
91        if (icicle != null) {
92            mChallengeSucceeded = icicle.getBoolean(KEY_CHALLENGE_SUCCEEDED, false);
93            mChallengeRequested = icicle.getBoolean(KEY_CHALLENGE_REQUESTED, false);
94        }
95
96        IntentFilter offFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
97        offFilter.addAction(Intent.ACTION_USER_PRESENT);
98        getActivity().registerReceiver(mScreenOffReceiver, offFilter);
99    }
100
101    @Override
102    public void onSaveInstanceState(Bundle outState) {
103        super.onSaveInstanceState(outState);
104
105        if (getActivity().isChangingConfigurations()) {
106            outState.putBoolean(KEY_CHALLENGE_REQUESTED, mChallengeRequested);
107            outState.putBoolean(KEY_CHALLENGE_SUCCEEDED, mChallengeSucceeded);
108        }
109    }
110
111    @Override
112    public void onResume() {
113        super.onResume();
114
115        if (shouldBeProviderProtected(mRestrictionKey)) {
116            ensurePin();
117        }
118    }
119
120    @Override
121    public void onDestroy() {
122        getActivity().unregisterReceiver(mScreenOffReceiver);
123        super.onDestroy();
124    }
125
126    @Override
127    public void onActivityResult(int requestCode, int resultCode, Intent data) {
128        if (requestCode == REQUEST_PIN_CHALLENGE) {
129            if (resultCode == Activity.RESULT_OK) {
130                mChallengeSucceeded = true;
131                mChallengeRequested = false;
132            } else {
133                mChallengeSucceeded = false;
134            }
135            return;
136        }
137
138        super.onActivityResult(requestCode, resultCode, data);
139    }
140
141    private void ensurePin() {
142        if (!mChallengeSucceeded && !mChallengeRequested
143                && mRestrictionsManager.hasRestrictionsProvider()) {
144            Intent intent = mRestrictionsManager.getLocalApprovalIntent();
145            if (intent != null) {
146                mChallengeRequested = true;
147                mChallengeSucceeded = false;
148                PersistableBundle request = new PersistableBundle();
149                request.putString(RestrictionsManager.REQUEST_KEY_MESSAGE,
150                        getResources().getString(R.string.restr_pin_enter_admin_pin));
151                intent.putExtra(RestrictionsManager.EXTRA_REQUEST_BUNDLE, request);
152                startActivityForResult(intent, REQUEST_PIN_CHALLENGE);
153            }
154        }
155    }
156
157    /**
158     * Returns true if this activity is restricted, but no restrictions provider has been set.
159     * Used to determine if the settings UI should disable UI.
160     */
161    protected boolean isRestrictedAndNotProviderProtected() {
162        if (mRestrictionKey == null || RESTRICT_IF_OVERRIDABLE.equals(mRestrictionKey)) {
163            return false;
164        }
165        return mUserManager.hasUserRestriction(mRestrictionKey)
166                && !mRestrictionsManager.hasRestrictionsProvider();
167    }
168
169    protected boolean hasChallengeSucceeded() {
170        return (mChallengeRequested && mChallengeSucceeded) || !mChallengeRequested;
171    }
172
173    /**
174     * Returns true if this restrictions key is locked down.
175     */
176    protected boolean shouldBeProviderProtected(String restrictionKey) {
177        if (restrictionKey == null) {
178            return false;
179        }
180        boolean restricted = RESTRICT_IF_OVERRIDABLE.equals(restrictionKey)
181                || mUserManager.hasUserRestriction(mRestrictionKey);
182        return restricted && mRestrictionsManager.hasRestrictionsProvider();
183    }
184
185    /**
186     * Returns whether restricted or actionable UI elements should be removed or disabled.
187     */
188    protected boolean isUiRestricted() {
189        return isRestrictedAndNotProviderProtected() || !hasChallengeSucceeded();
190    }
191}
192