• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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.deviceinfo;
18 
19 import android.app.Activity;
20 import android.app.Fragment;
21 import android.content.ComponentName;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.pm.ResolveInfo;
25 import android.os.Build;
26 import android.os.UserHandle;
27 import android.os.UserManager;
28 import android.support.v7.preference.Preference;
29 import android.support.v7.preference.PreferenceScreen;
30 import android.text.BidiFormatter;
31 import android.text.TextUtils;
32 import android.util.Pair;
33 import android.widget.Toast;
34 
35 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
36 import com.android.settings.R;
37 import com.android.settings.Utils;
38 import com.android.settings.core.PreferenceControllerMixin;
39 import com.android.settings.overlay.FeatureFactory;
40 import com.android.settings.password.ChooseLockSettingsHelper;
41 import com.android.settingslib.RestrictedLockUtils;
42 import com.android.settingslib.core.AbstractPreferenceController;
43 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
44 import com.android.settingslib.core.lifecycle.Lifecycle;
45 import com.android.settingslib.core.lifecycle.LifecycleObserver;
46 import com.android.settingslib.core.lifecycle.events.OnResume;
47 import com.android.settingslib.development.DevelopmentSettingsEnabler;
48 
49 public class BuildNumberPreferenceController extends AbstractPreferenceController implements
50         PreferenceControllerMixin, LifecycleObserver, OnResume {
51 
52     static final int TAPS_TO_BE_A_DEVELOPER = 7;
53     static final int REQUEST_CONFIRM_PASSWORD_FOR_DEV_PREF = 100;
54 
55     private static final String KEY_BUILD_NUMBER = "build_number";
56 
57     private final Activity mActivity;
58     private final Fragment mFragment;
59     private final UserManager mUm;
60     private final MetricsFeatureProvider mMetricsFeatureProvider;
61 
62     private Toast mDevHitToast;
63     private RestrictedLockUtils.EnforcedAdmin mDebuggingFeaturesDisallowedAdmin;
64     private boolean mDebuggingFeaturesDisallowedBySystem;
65     private int mDevHitCountdown;
66     private boolean mProcessingLastDevHit;
67 
BuildNumberPreferenceController(Context context, Activity activity, Fragment fragment, Lifecycle lifecycle)68     public BuildNumberPreferenceController(Context context, Activity activity, Fragment fragment,
69             Lifecycle lifecycle) {
70         super(context);
71         mActivity = activity;
72         mFragment = fragment;
73         mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
74         mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
75         if (lifecycle != null) {
76             lifecycle.addObserver(this);
77         }
78     }
79 
80     @Override
displayPreference(PreferenceScreen screen)81     public void displayPreference(PreferenceScreen screen) {
82         super.displayPreference(screen);
83         final Preference preference = screen.findPreference(KEY_BUILD_NUMBER);
84         if (preference != null) {
85             try {
86                 preference.setSummary(BidiFormatter.getInstance().unicodeWrap(Build.DISPLAY));
87                 preference.setEnabled(true);
88             } catch (Exception e) {
89                 preference.setSummary(R.string.device_info_default);
90             }
91         }
92     }
93 
94     @Override
getPreferenceKey()95     public String getPreferenceKey() {
96         return KEY_BUILD_NUMBER;
97     }
98 
99     @Override
isAvailable()100     public boolean isAvailable() {
101         return true;
102     }
103 
104     @Override
onResume()105     public void onResume() {
106         mDebuggingFeaturesDisallowedAdmin = RestrictedLockUtils.checkIfRestrictionEnforced(
107                 mContext, UserManager.DISALLOW_DEBUGGING_FEATURES, UserHandle.myUserId());
108         mDebuggingFeaturesDisallowedBySystem = RestrictedLockUtils.hasBaseUserRestriction(
109                 mContext, UserManager.DISALLOW_DEBUGGING_FEATURES, UserHandle.myUserId());
110         mDevHitCountdown = DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)
111                 ? -1 : TAPS_TO_BE_A_DEVELOPER;
112         mDevHitToast = null;
113     }
114 
115     @Override
handlePreferenceTreeClick(Preference preference)116     public boolean handlePreferenceTreeClick(Preference preference) {
117         if (!TextUtils.equals(preference.getKey(), KEY_BUILD_NUMBER)) {
118             return false;
119         }
120         if (Utils.isMonkeyRunning()) {
121             return false;
122         }
123         // Don't enable developer options for secondary non-demo users.
124         if (!(mUm.isAdminUser() || mUm.isDemoUser())) {
125             mMetricsFeatureProvider.action(
126                     mContext, MetricsEvent.ACTION_SETTINGS_BUILD_NUMBER_PREF);
127             return false;
128         }
129 
130         // Don't enable developer options until device has been provisioned
131         if (!Utils.isDeviceProvisioned(mContext)) {
132             mMetricsFeatureProvider.action(
133                     mContext, MetricsEvent.ACTION_SETTINGS_BUILD_NUMBER_PREF);
134             return false;
135         }
136 
137         if (mUm.hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES)) {
138             if (mUm.isDemoUser()) {
139                 // Route to demo device owner to lift the debugging restriction.
140                 final ComponentName componentName = Utils.getDeviceOwnerComponent(mContext);
141                 if (componentName != null) {
142                     final Intent requestDebugFeatures = new Intent()
143                             .setPackage(componentName.getPackageName())
144                             .setAction("com.android.settings.action.REQUEST_DEBUG_FEATURES");
145                     final ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivity(
146                         requestDebugFeatures, 0);
147                     if (resolveInfo != null) {
148                         mContext.startActivity(requestDebugFeatures);
149                         return false;
150                     }
151                 }
152             }
153             if (mDebuggingFeaturesDisallowedAdmin != null &&
154                     !mDebuggingFeaturesDisallowedBySystem) {
155                 RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext,
156                         mDebuggingFeaturesDisallowedAdmin);
157             }
158             mMetricsFeatureProvider.action(
159                     mContext, MetricsEvent.ACTION_SETTINGS_BUILD_NUMBER_PREF);
160             return false;
161         }
162 
163         if (mDevHitCountdown > 0) {
164             mDevHitCountdown--;
165             if (mDevHitCountdown == 0 && !mProcessingLastDevHit) {
166                 // Add 1 count back, then start password confirmation flow.
167                 mDevHitCountdown++;
168                 final ChooseLockSettingsHelper helper =
169                         new ChooseLockSettingsHelper(mActivity, mFragment);
170                 mProcessingLastDevHit = helper.launchConfirmationActivity(
171                         REQUEST_CONFIRM_PASSWORD_FOR_DEV_PREF,
172                         mContext.getString(R.string.unlock_set_unlock_launch_picker_title));
173                 if (!mProcessingLastDevHit) {
174                     enableDevelopmentSettings();
175                 }
176                 mMetricsFeatureProvider.action(
177                         mContext, MetricsEvent.ACTION_SETTINGS_BUILD_NUMBER_PREF,
178                         Pair.create(MetricsEvent.FIELD_SETTINGS_BUILD_NUMBER_DEVELOPER_MODE_ENABLED,
179                                 mProcessingLastDevHit ? 0 : 1));
180             } else if (mDevHitCountdown > 0
181                     && mDevHitCountdown < (TAPS_TO_BE_A_DEVELOPER - 2)) {
182                 if (mDevHitToast != null) {
183                     mDevHitToast.cancel();
184                 }
185                 mDevHitToast = Toast.makeText(mContext,
186                         mContext.getResources().getQuantityString(
187                                 R.plurals.show_dev_countdown, mDevHitCountdown,
188                                 mDevHitCountdown),
189                         Toast.LENGTH_SHORT);
190                 mDevHitToast.show();
191             }
192             mMetricsFeatureProvider.action(
193                     mContext, MetricsEvent.ACTION_SETTINGS_BUILD_NUMBER_PREF,
194                     Pair.create(MetricsEvent.FIELD_SETTINGS_BUILD_NUMBER_DEVELOPER_MODE_ENABLED,
195                             0));
196         } else if (mDevHitCountdown < 0) {
197             if (mDevHitToast != null) {
198                 mDevHitToast.cancel();
199             }
200             mDevHitToast = Toast.makeText(mContext, R.string.show_dev_already,
201                     Toast.LENGTH_LONG);
202             mDevHitToast.show();
203             mMetricsFeatureProvider.action(
204                     mContext, MetricsEvent.ACTION_SETTINGS_BUILD_NUMBER_PREF,
205                     Pair.create(MetricsEvent.FIELD_SETTINGS_BUILD_NUMBER_DEVELOPER_MODE_ENABLED,
206                             1));
207         }
208         return true;
209     }
210 
211     /**
212      * Handles password confirmation result.
213      *
214      * @return if activity result is handled.
215      */
onActivityResult(int requestCode, int resultCode, Intent data)216     public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
217         if (requestCode != REQUEST_CONFIRM_PASSWORD_FOR_DEV_PREF) {
218             return false;
219         }
220         if (resultCode == Activity.RESULT_OK) {
221             enableDevelopmentSettings();
222         }
223         mProcessingLastDevHit = false;
224         return true;
225     }
226 
227     /**
228      * Enables development settings. Only call this after confirming password.
229      */
enableDevelopmentSettings()230     private void enableDevelopmentSettings() {
231         mDevHitCountdown = 0;
232         mProcessingLastDevHit = false;
233         DevelopmentSettingsEnabler.setDevelopmentSettingsEnabled(mContext, true);
234         if (mDevHitToast != null) {
235             mDevHitToast.cancel();
236         }
237         mDevHitToast = Toast.makeText(mContext, R.string.show_dev_on,
238                 Toast.LENGTH_LONG);
239         mDevHitToast.show();
240     }
241 }
242