1/*
2 * Copyright (C) 2008 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 static android.Manifest.permission.READ_EXTERNAL_STORAGE;
20
21import android.app.ActionBar;
22import android.app.Activity;
23import android.app.ActivityManagerNative;
24import android.app.ActivityThread;
25import android.app.AlertDialog;
26import android.app.Dialog;
27import android.app.DialogFragment;
28import android.app.admin.DevicePolicyManager;
29import android.app.backup.IBackupManager;
30import android.content.ContentResolver;
31import android.content.Context;
32import android.content.DialogInterface;
33import android.content.DialogInterface.OnClickListener;
34import android.content.Intent;
35import android.content.pm.ApplicationInfo;
36import android.content.pm.PackageManager;
37import android.content.pm.ResolveInfo;
38import android.os.AsyncTask;
39import android.os.BatteryManager;
40import android.os.Build;
41import android.os.Bundle;
42import android.os.IBinder;
43import android.os.Parcel;
44import android.os.RemoteException;
45import android.os.ServiceManager;
46import android.os.StrictMode;
47import android.os.SystemProperties;
48import android.os.Trace;
49import android.preference.CheckBoxPreference;
50import android.preference.ListPreference;
51import android.preference.MultiCheckPreference;
52import android.preference.Preference;
53import android.preference.Preference.OnPreferenceChangeListener;
54import android.preference.PreferenceFragment;
55import android.preference.PreferenceGroup;
56import android.preference.PreferenceScreen;
57import android.provider.Settings;
58import android.text.TextUtils;
59import android.util.Log;
60import android.view.Gravity;
61import android.view.HardwareRenderer;
62import android.view.IWindowManager;
63import android.view.View;
64import android.widget.CompoundButton;
65import android.widget.Switch;
66
67import java.util.ArrayList;
68import java.util.HashSet;
69import java.util.List;
70
71/*
72 * Displays preferences for application developers.
73 */
74public class DevelopmentSettings extends PreferenceFragment
75        implements DialogInterface.OnClickListener, DialogInterface.OnDismissListener,
76                OnPreferenceChangeListener, CompoundButton.OnCheckedChangeListener {
77
78    /**
79     * Preference file were development settings prefs are stored.
80     */
81    public static final String PREF_FILE = "development";
82
83    /**
84     * Whether to show the development settings to the user.  Default is false.
85     */
86    public static final String PREF_SHOW = "show";
87
88    private static final String ENABLE_ADB = "enable_adb";
89    private static final String KEEP_SCREEN_ON = "keep_screen_on";
90    private static final String ALLOW_MOCK_LOCATION = "allow_mock_location";
91    private static final String HDCP_CHECKING_KEY = "hdcp_checking";
92    private static final String HDCP_CHECKING_PROPERTY = "persist.sys.hdcp_checking";
93    private static final String ENFORCE_READ_EXTERNAL = "enforce_read_external";
94    private static final String LOCAL_BACKUP_PASSWORD = "local_backup_password";
95    private static final String HARDWARE_UI_PROPERTY = "persist.sys.ui.hw";
96    private static final String MSAA_PROPERTY = "debug.egl.force_msaa";
97    private static final String BUGREPORT = "bugreport";
98    private static final String BUGREPORT_IN_POWER_KEY = "bugreport_in_power";
99    private static final String OPENGL_TRACES_PROPERTY = "debug.egl.trace";
100
101    private static final String DEBUG_APP_KEY = "debug_app";
102    private static final String WAIT_FOR_DEBUGGER_KEY = "wait_for_debugger";
103    private static final String VERIFY_APPS_OVER_USB_KEY = "verify_apps_over_usb";
104    private static final String STRICT_MODE_KEY = "strict_mode";
105    private static final String POINTER_LOCATION_KEY = "pointer_location";
106    private static final String SHOW_TOUCHES_KEY = "show_touches";
107    private static final String SHOW_SCREEN_UPDATES_KEY = "show_screen_updates";
108    private static final String DISABLE_OVERLAYS_KEY = "disable_overlays";
109    private static final String SHOW_CPU_USAGE_KEY = "show_cpu_usage";
110    private static final String FORCE_HARDWARE_UI_KEY = "force_hw_ui";
111    private static final String FORCE_MSAA_KEY = "force_msaa";
112    private static final String TRACK_FRAME_TIME_KEY = "track_frame_time";
113    private static final String SHOW_HW_SCREEN_UPDATES_KEY = "show_hw_screen_udpates";
114    private static final String SHOW_HW_LAYERS_UPDATES_KEY = "show_hw_layers_udpates";
115    private static final String SHOW_HW_OVERDRAW_KEY = "show_hw_overdraw";
116    private static final String DEBUG_LAYOUT_KEY = "debug_layout";
117    private static final String WINDOW_ANIMATION_SCALE_KEY = "window_animation_scale";
118    private static final String TRANSITION_ANIMATION_SCALE_KEY = "transition_animation_scale";
119    private static final String ANIMATOR_DURATION_SCALE_KEY = "animator_duration_scale";
120    private static final String OVERLAY_DISPLAY_DEVICES_KEY = "overlay_display_devices";
121    private static final String DEBUG_DEBUGGING_CATEGORY_KEY = "debug_debugging_category";
122    private static final String OPENGL_TRACES_KEY = "enable_opengl_traces";
123
124    private static final String ENABLE_TRACES_KEY = "enable_traces";
125
126    private static final String IMMEDIATELY_DESTROY_ACTIVITIES_KEY
127            = "immediately_destroy_activities";
128    private static final String APP_PROCESS_LIMIT_KEY = "app_process_limit";
129
130    private static final String SHOW_ALL_ANRS_KEY = "show_all_anrs";
131
132    private static final String TAG_CONFIRM_ENFORCE = "confirm_enforce";
133
134    private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
135
136    private static final int RESULT_DEBUG_APP = 1000;
137
138    private IWindowManager mWindowManager;
139    private IBackupManager mBackupManager;
140    private DevicePolicyManager mDpm;
141
142    private Switch mEnabledSwitch;
143    private boolean mLastEnabledState;
144    private boolean mHaveDebugSettings;
145    private boolean mDontPokeProperties;
146
147    private CheckBoxPreference mEnableAdb;
148    private Preference mBugreport;
149    private CheckBoxPreference mBugreportInPower;
150    private CheckBoxPreference mKeepScreenOn;
151    private CheckBoxPreference mEnforceReadExternal;
152    private CheckBoxPreference mAllowMockLocation;
153    private PreferenceScreen mPassword;
154
155    private String mDebugApp;
156    private Preference mDebugAppPref;
157    private CheckBoxPreference mWaitForDebugger;
158    private CheckBoxPreference mVerifyAppsOverUsb;
159
160    private CheckBoxPreference mStrictMode;
161    private CheckBoxPreference mPointerLocation;
162    private CheckBoxPreference mShowTouches;
163    private CheckBoxPreference mShowScreenUpdates;
164    private CheckBoxPreference mDisableOverlays;
165    private CheckBoxPreference mShowCpuUsage;
166    private CheckBoxPreference mForceHardwareUi;
167    private CheckBoxPreference mForceMsaa;
168    private CheckBoxPreference mTrackFrameTime;
169    private CheckBoxPreference mShowHwScreenUpdates;
170    private CheckBoxPreference mShowHwLayersUpdates;
171    private CheckBoxPreference mShowHwOverdraw;
172    private CheckBoxPreference mDebugLayout;
173    private ListPreference mWindowAnimationScale;
174    private ListPreference mTransitionAnimationScale;
175    private ListPreference mAnimatorDurationScale;
176    private ListPreference mOverlayDisplayDevices;
177    private ListPreference mOpenGLTraces;
178    private MultiCheckPreference mEnableTracesPref;
179
180    private CheckBoxPreference mImmediatelyDestroyActivities;
181    private ListPreference mAppProcessLimit;
182
183    private CheckBoxPreference mShowAllANRs;
184
185    private final ArrayList<Preference> mAllPrefs = new ArrayList<Preference>();
186    private final ArrayList<CheckBoxPreference> mResetCbPrefs
187            = new ArrayList<CheckBoxPreference>();
188
189    private final HashSet<Preference> mDisabledPrefs = new HashSet<Preference>();
190
191    // To track whether a confirmation dialog was clicked.
192    private boolean mDialogClicked;
193    private Dialog mEnableDialog;
194    private Dialog mAdbDialog;
195
196    @Override
197    public void onCreate(Bundle icicle) {
198        super.onCreate(icicle);
199
200        mWindowManager = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
201        mBackupManager = IBackupManager.Stub.asInterface(
202                ServiceManager.getService(Context.BACKUP_SERVICE));
203        mDpm = (DevicePolicyManager)getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE);
204
205        addPreferencesFromResource(R.xml.development_prefs);
206
207        mEnableAdb = findAndInitCheckboxPref(ENABLE_ADB);
208        mBugreport = findPreference(BUGREPORT);
209        mBugreportInPower = findAndInitCheckboxPref(BUGREPORT_IN_POWER_KEY);
210        mKeepScreenOn = findAndInitCheckboxPref(KEEP_SCREEN_ON);
211        mEnforceReadExternal = findAndInitCheckboxPref(ENFORCE_READ_EXTERNAL);
212        mAllowMockLocation = findAndInitCheckboxPref(ALLOW_MOCK_LOCATION);
213        mPassword = (PreferenceScreen) findPreference(LOCAL_BACKUP_PASSWORD);
214        mAllPrefs.add(mPassword);
215
216        mDebugAppPref = findPreference(DEBUG_APP_KEY);
217        mAllPrefs.add(mDebugAppPref);
218        mWaitForDebugger = findAndInitCheckboxPref(WAIT_FOR_DEBUGGER_KEY);
219        mVerifyAppsOverUsb = findAndInitCheckboxPref(VERIFY_APPS_OVER_USB_KEY);
220        if (!showVerifierSetting()) {
221            PreferenceGroup debugDebuggingCategory = (PreferenceGroup)
222                    findPreference(DEBUG_DEBUGGING_CATEGORY_KEY);
223            if (debugDebuggingCategory != null) {
224                debugDebuggingCategory.removePreference(mVerifyAppsOverUsb);
225            } else {
226                mVerifyAppsOverUsb.setEnabled(false);
227            }
228        }
229        mStrictMode = findAndInitCheckboxPref(STRICT_MODE_KEY);
230        mPointerLocation = findAndInitCheckboxPref(POINTER_LOCATION_KEY);
231        mShowTouches = findAndInitCheckboxPref(SHOW_TOUCHES_KEY);
232        mShowScreenUpdates = findAndInitCheckboxPref(SHOW_SCREEN_UPDATES_KEY);
233        mDisableOverlays = findAndInitCheckboxPref(DISABLE_OVERLAYS_KEY);
234        mShowCpuUsage = findAndInitCheckboxPref(SHOW_CPU_USAGE_KEY);
235        mForceHardwareUi = findAndInitCheckboxPref(FORCE_HARDWARE_UI_KEY);
236        mForceMsaa = findAndInitCheckboxPref(FORCE_MSAA_KEY);
237        mTrackFrameTime = findAndInitCheckboxPref(TRACK_FRAME_TIME_KEY);
238        mShowHwScreenUpdates = findAndInitCheckboxPref(SHOW_HW_SCREEN_UPDATES_KEY);
239        mShowHwLayersUpdates = findAndInitCheckboxPref(SHOW_HW_LAYERS_UPDATES_KEY);
240        mShowHwOverdraw = findAndInitCheckboxPref(SHOW_HW_OVERDRAW_KEY);
241        mDebugLayout = findAndInitCheckboxPref(DEBUG_LAYOUT_KEY);
242        mWindowAnimationScale = (ListPreference) findPreference(WINDOW_ANIMATION_SCALE_KEY);
243        mAllPrefs.add(mWindowAnimationScale);
244        mWindowAnimationScale.setOnPreferenceChangeListener(this);
245        mTransitionAnimationScale = (ListPreference) findPreference(TRANSITION_ANIMATION_SCALE_KEY);
246        mAllPrefs.add(mTransitionAnimationScale);
247        mTransitionAnimationScale.setOnPreferenceChangeListener(this);
248        mAnimatorDurationScale = (ListPreference) findPreference(ANIMATOR_DURATION_SCALE_KEY);
249        mAllPrefs.add(mAnimatorDurationScale);
250        mAnimatorDurationScale.setOnPreferenceChangeListener(this);
251        mOverlayDisplayDevices = (ListPreference) findPreference(OVERLAY_DISPLAY_DEVICES_KEY);
252        mAllPrefs.add(mOverlayDisplayDevices);
253        mOverlayDisplayDevices.setOnPreferenceChangeListener(this);
254        mOpenGLTraces = (ListPreference) findPreference(OPENGL_TRACES_KEY);
255        mAllPrefs.add(mOpenGLTraces);
256        mOpenGLTraces.setOnPreferenceChangeListener(this);
257        mEnableTracesPref = (MultiCheckPreference)findPreference(ENABLE_TRACES_KEY);
258        String[] traceValues = new String[Trace.TRACE_TAGS.length];
259        for (int i=Trace.TRACE_FLAGS_START_BIT; i<traceValues.length; i++) {
260            traceValues[i] = Integer.toString(1<<i);
261        }
262        mEnableTracesPref.setEntries(Trace.TRACE_TAGS);
263        mEnableTracesPref.setEntryValues(traceValues);
264        mAllPrefs.add(mEnableTracesPref);
265        mEnableTracesPref.setOnPreferenceChangeListener(this);
266
267        mImmediatelyDestroyActivities = (CheckBoxPreference) findPreference(
268                IMMEDIATELY_DESTROY_ACTIVITIES_KEY);
269        mAllPrefs.add(mImmediatelyDestroyActivities);
270        mResetCbPrefs.add(mImmediatelyDestroyActivities);
271        mAppProcessLimit = (ListPreference) findPreference(APP_PROCESS_LIMIT_KEY);
272        mAllPrefs.add(mAppProcessLimit);
273        mAppProcessLimit.setOnPreferenceChangeListener(this);
274
275        mShowAllANRs = (CheckBoxPreference) findPreference(
276                SHOW_ALL_ANRS_KEY);
277        mAllPrefs.add(mShowAllANRs);
278        mResetCbPrefs.add(mShowAllANRs);
279
280        Preference hdcpChecking = findPreference(HDCP_CHECKING_KEY);
281        if (hdcpChecking != null) {
282            mAllPrefs.add(hdcpChecking);
283        }
284        removeHdcpOptionsForProduction();
285    }
286
287    private CheckBoxPreference findAndInitCheckboxPref(String key) {
288        CheckBoxPreference pref = (CheckBoxPreference) findPreference(key);
289        if (pref == null) {
290            throw new IllegalArgumentException("Cannot find preference with key = " + key);
291        }
292        mAllPrefs.add(pref);
293        mResetCbPrefs.add(pref);
294        return pref;
295    }
296
297    @Override
298    public void onActivityCreated(Bundle savedInstanceState) {
299        super.onActivityCreated(savedInstanceState);
300
301        final Activity activity = getActivity();
302        mEnabledSwitch = new Switch(activity);
303
304        final int padding = activity.getResources().getDimensionPixelSize(
305                R.dimen.action_bar_switch_padding);
306        mEnabledSwitch.setPadding(0, 0, padding, 0);
307        mEnabledSwitch.setOnCheckedChangeListener(this);
308    }
309
310    @Override
311    public void onStart() {
312        super.onStart();
313        final Activity activity = getActivity();
314        activity.getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
315                ActionBar.DISPLAY_SHOW_CUSTOM);
316        activity.getActionBar().setCustomView(mEnabledSwitch, new ActionBar.LayoutParams(
317                ActionBar.LayoutParams.WRAP_CONTENT,
318                ActionBar.LayoutParams.WRAP_CONTENT,
319                Gravity.CENTER_VERTICAL | Gravity.END));
320    }
321
322    @Override
323    public void onStop() {
324        super.onStop();
325        final Activity activity = getActivity();
326        activity.getActionBar().setDisplayOptions(0, ActionBar.DISPLAY_SHOW_CUSTOM);
327        activity.getActionBar().setCustomView(null);
328    }
329
330    private void removeHdcpOptionsForProduction() {
331        if ("user".equals(Build.TYPE)) {
332            Preference hdcpChecking = findPreference(HDCP_CHECKING_KEY);
333            if (hdcpChecking != null) {
334                // Remove the preference
335                getPreferenceScreen().removePreference(hdcpChecking);
336                mAllPrefs.remove(hdcpChecking);
337            }
338        }
339    }
340
341    private void setPrefsEnabledState(boolean enabled) {
342        for (int i = 0; i < mAllPrefs.size(); i++) {
343            Preference pref = mAllPrefs.get(i);
344            pref.setEnabled(enabled && !mDisabledPrefs.contains(pref));
345        }
346        updateAllOptions();
347    }
348
349    @Override
350    public void onResume() {
351        super.onResume();
352
353        if (mDpm.getMaximumTimeToLock(null) > 0) {
354            // A DeviceAdmin has specified a maximum time until the device
355            // will lock...  in this case we can't allow the user to turn
356            // on "stay awake when plugged in" because that would defeat the
357            // restriction.
358            mDisabledPrefs.add(mKeepScreenOn);
359        } else {
360            mDisabledPrefs.remove(mKeepScreenOn);
361        }
362
363        final ContentResolver cr = getActivity().getContentResolver();
364        mLastEnabledState = Settings.Global.getInt(cr,
365                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0;
366        mEnabledSwitch.setChecked(mLastEnabledState);
367        setPrefsEnabledState(mLastEnabledState);
368
369        if (mHaveDebugSettings && !mLastEnabledState) {
370            // Overall debugging is disabled, but there are some debug
371            // settings that are enabled.  This is an invalid state.  Switch
372            // to debug settings being enabled, so the user knows there is
373            // stuff enabled and can turn it all off if they want.
374            Settings.Global.putInt(getActivity().getContentResolver(),
375                    Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
376            mLastEnabledState = true;
377            mEnabledSwitch.setChecked(mLastEnabledState);
378            setPrefsEnabledState(mLastEnabledState);
379        }
380    }
381
382    void updateCheckBox(CheckBoxPreference checkBox, boolean value) {
383        checkBox.setChecked(value);
384        mHaveDebugSettings |= value;
385    }
386
387    private void updateAllOptions() {
388        final Context context = getActivity();
389        final ContentResolver cr = context.getContentResolver();
390        mHaveDebugSettings = false;
391        updateCheckBox(mEnableAdb, Settings.Global.getInt(cr,
392                Settings.Global.ADB_ENABLED, 0) != 0);
393        updateCheckBox(mBugreportInPower, Settings.Secure.getInt(cr,
394                Settings.Secure.BUGREPORT_IN_POWER_MENU, 0) != 0);
395        updateCheckBox(mKeepScreenOn, Settings.Global.getInt(cr,
396                Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0) != 0);
397        updateCheckBox(mEnforceReadExternal, isPermissionEnforced(READ_EXTERNAL_STORAGE));
398        updateCheckBox(mAllowMockLocation, Settings.Secure.getInt(cr,
399                Settings.Secure.ALLOW_MOCK_LOCATION, 0) != 0);
400        updateHdcpValues();
401        updatePasswordSummary();
402        updateDebuggerOptions();
403        updateStrictModeVisualOptions();
404        updatePointerLocationOptions();
405        updateShowTouchesOptions();
406        updateFlingerOptions();
407        updateCpuUsageOptions();
408        updateHardwareUiOptions();
409        updateMsaaOptions();
410        updateTrackFrameTimeOptions();
411        updateShowHwScreenUpdatesOptions();
412        updateShowHwLayersUpdatesOptions();
413        updateShowHwOverdrawOptions();
414        updateDebugLayoutOptions();
415        updateAnimationScaleOptions();
416        updateOverlayDisplayDevicesOptions();
417        updateOpenGLTracesOptions();
418        updateEnableTracesOptions();
419        updateImmediatelyDestroyActivitiesOptions();
420        updateAppProcessLimitOptions();
421        updateShowAllANRsOptions();
422        updateVerifyAppsOverUsbOptions();
423        updateBugreportOptions();
424    }
425
426    private void resetDangerousOptions() {
427        mDontPokeProperties = true;
428        for (int i=0; i<mResetCbPrefs.size(); i++) {
429            CheckBoxPreference cb = mResetCbPrefs.get(i);
430            if (cb.isChecked()) {
431                cb.setChecked(false);
432                onPreferenceTreeClick(null, cb);
433            }
434        }
435        resetDebuggerOptions();
436        writeAnimationScaleOption(0, mWindowAnimationScale, null);
437        writeAnimationScaleOption(1, mTransitionAnimationScale, null);
438        writeAnimationScaleOption(2, mAnimatorDurationScale, null);
439        writeOverlayDisplayDevicesOptions(null);
440        writeEnableTracesOptions(0);
441        writeAppProcessLimitOptions(null);
442        mHaveDebugSettings = false;
443        updateAllOptions();
444        mDontPokeProperties = false;
445        pokeSystemProperties();
446    }
447
448    private void updateHdcpValues() {
449        int index = 1; // Defaults to drm-only. Needs to match with R.array.hdcp_checking_values
450        ListPreference hdcpChecking = (ListPreference) findPreference(HDCP_CHECKING_KEY);
451        if (hdcpChecking != null) {
452            String currentValue = SystemProperties.get(HDCP_CHECKING_PROPERTY);
453            String[] values = getResources().getStringArray(R.array.hdcp_checking_values);
454            String[] summaries = getResources().getStringArray(R.array.hdcp_checking_summaries);
455            for (int i = 0; i < values.length; i++) {
456                if (currentValue.equals(values[i])) {
457                    index = i;
458                    break;
459                }
460            }
461            hdcpChecking.setValue(values[index]);
462            hdcpChecking.setSummary(summaries[index]);
463            hdcpChecking.setOnPreferenceChangeListener(this);
464        }
465    }
466
467    private void updatePasswordSummary() {
468        try {
469            if (mBackupManager.hasBackupPassword()) {
470                mPassword.setSummary(R.string.local_backup_password_summary_change);
471            } else {
472                mPassword.setSummary(R.string.local_backup_password_summary_none);
473            }
474        } catch (RemoteException e) {
475            // Not much we can do here
476        }
477    }
478
479    private void writeDebuggerOptions() {
480        try {
481            ActivityManagerNative.getDefault().setDebugApp(
482                mDebugApp, mWaitForDebugger.isChecked(), true);
483        } catch (RemoteException ex) {
484        }
485    }
486
487    private static void resetDebuggerOptions() {
488        try {
489            ActivityManagerNative.getDefault().setDebugApp(
490                    null, false, true);
491        } catch (RemoteException ex) {
492        }
493    }
494
495    private void updateDebuggerOptions() {
496        mDebugApp = Settings.Global.getString(
497                getActivity().getContentResolver(), Settings.Global.DEBUG_APP);
498        updateCheckBox(mWaitForDebugger, Settings.Global.getInt(
499                getActivity().getContentResolver(), Settings.Global.WAIT_FOR_DEBUGGER, 0) != 0);
500        if (mDebugApp != null && mDebugApp.length() > 0) {
501            String label;
502            try {
503                ApplicationInfo ai = getActivity().getPackageManager().getApplicationInfo(mDebugApp,
504                        PackageManager.GET_DISABLED_COMPONENTS);
505                CharSequence lab = getActivity().getPackageManager().getApplicationLabel(ai);
506                label = lab != null ? lab.toString() : mDebugApp;
507            } catch (PackageManager.NameNotFoundException e) {
508                label = mDebugApp;
509            }
510            mDebugAppPref.setSummary(getResources().getString(R.string.debug_app_set, label));
511            mWaitForDebugger.setEnabled(true);
512            mHaveDebugSettings = true;
513        } else {
514            mDebugAppPref.setSummary(getResources().getString(R.string.debug_app_not_set));
515            mWaitForDebugger.setEnabled(false);
516        }
517    }
518
519    private void updateVerifyAppsOverUsbOptions() {
520        updateCheckBox(mVerifyAppsOverUsb, Settings.Global.getInt(getActivity().getContentResolver(),
521                Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, 1) != 0);
522        mVerifyAppsOverUsb.setEnabled(enableVerifierSetting());
523    }
524
525    private void writeVerifyAppsOverUsbOptions() {
526        Settings.Global.putInt(getActivity().getContentResolver(),
527              Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, mVerifyAppsOverUsb.isChecked() ? 1 : 0);
528    }
529
530    private boolean enableVerifierSetting() {
531        final ContentResolver cr = getActivity().getContentResolver();
532        if (Settings.Global.getInt(cr, Settings.Global.ADB_ENABLED, 0) == 0) {
533            return false;
534        }
535        if (Settings.Global.getInt(cr, Settings.Global.PACKAGE_VERIFIER_ENABLE, 1) == 0) {
536            return false;
537        } else {
538            final PackageManager pm = getActivity().getPackageManager();
539            final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
540            verification.setType(PACKAGE_MIME_TYPE);
541            verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
542            final List<ResolveInfo> receivers = pm.queryBroadcastReceivers(verification, 0);
543            if (receivers.size() == 0) {
544                return false;
545            }
546        }
547        return true;
548    }
549
550    private boolean showVerifierSetting() {
551        return Settings.Global.getInt(getActivity().getContentResolver(),
552                Settings.Global.PACKAGE_VERIFIER_SETTING_VISIBLE, 1) > 0;
553    }
554
555    private void updateBugreportOptions() {
556        if ("user".equals(Build.TYPE)) {
557            final ContentResolver resolver = getActivity().getContentResolver();
558            final boolean adbEnabled = Settings.Global.getInt(
559                    resolver, Settings.Global.ADB_ENABLED, 0) != 0;
560            if (adbEnabled) {
561                mBugreport.setEnabled(true);
562                mBugreportInPower.setEnabled(true);
563            } else {
564                mBugreport.setEnabled(false);
565                mBugreportInPower.setEnabled(false);
566                mBugreportInPower.setChecked(false);
567                Settings.Secure.putInt(resolver, Settings.Secure.BUGREPORT_IN_POWER_MENU, 0);
568            }
569        } else {
570            mBugreportInPower.setEnabled(true);
571        }
572    }
573
574    // Returns the current state of the system property that controls
575    // strictmode flashes.  One of:
576    //    0: not explicitly set one way or another
577    //    1: on
578    //    2: off
579    private static int currentStrictModeActiveIndex() {
580        if (TextUtils.isEmpty(SystemProperties.get(StrictMode.VISUAL_PROPERTY))) {
581            return 0;
582        }
583        boolean enabled = SystemProperties.getBoolean(StrictMode.VISUAL_PROPERTY, false);
584        return enabled ? 1 : 2;
585    }
586
587    private void writeStrictModeVisualOptions() {
588        try {
589            mWindowManager.setStrictModeVisualIndicatorPreference(mStrictMode.isChecked()
590                    ? "1" : "");
591        } catch (RemoteException e) {
592        }
593    }
594
595    private void updateStrictModeVisualOptions() {
596        updateCheckBox(mStrictMode, currentStrictModeActiveIndex() == 1);
597    }
598
599    private void writePointerLocationOptions() {
600        Settings.System.putInt(getActivity().getContentResolver(),
601                Settings.System.POINTER_LOCATION, mPointerLocation.isChecked() ? 1 : 0);
602    }
603
604    private void updatePointerLocationOptions() {
605        updateCheckBox(mPointerLocation, Settings.System.getInt(getActivity().getContentResolver(),
606                Settings.System.POINTER_LOCATION, 0) != 0);
607    }
608
609    private void writeShowTouchesOptions() {
610        Settings.System.putInt(getActivity().getContentResolver(),
611                Settings.System.SHOW_TOUCHES, mShowTouches.isChecked() ? 1 : 0);
612    }
613
614    private void updateShowTouchesOptions() {
615        updateCheckBox(mShowTouches, Settings.System.getInt(getActivity().getContentResolver(),
616                Settings.System.SHOW_TOUCHES, 0) != 0);
617    }
618
619    private void updateFlingerOptions() {
620        // magic communication with surface flinger.
621        try {
622            IBinder flinger = ServiceManager.getService("SurfaceFlinger");
623            if (flinger != null) {
624                Parcel data = Parcel.obtain();
625                Parcel reply = Parcel.obtain();
626                data.writeInterfaceToken("android.ui.ISurfaceComposer");
627                flinger.transact(1010, data, reply, 0);
628                @SuppressWarnings("unused")
629                int showCpu = reply.readInt();
630                @SuppressWarnings("unused")
631                int enableGL = reply.readInt();
632                int showUpdates = reply.readInt();
633                updateCheckBox(mShowScreenUpdates, showUpdates != 0);
634                @SuppressWarnings("unused")
635                int showBackground = reply.readInt();
636                int disableOverlays = reply.readInt();
637                updateCheckBox(mDisableOverlays, disableOverlays != 0);
638                reply.recycle();
639                data.recycle();
640            }
641        } catch (RemoteException ex) {
642        }
643    }
644
645    private void writeShowUpdatesOption() {
646        try {
647            IBinder flinger = ServiceManager.getService("SurfaceFlinger");
648            if (flinger != null) {
649                Parcel data = Parcel.obtain();
650                data.writeInterfaceToken("android.ui.ISurfaceComposer");
651                final int showUpdates = mShowScreenUpdates.isChecked() ? 1 : 0;
652                data.writeInt(showUpdates);
653                flinger.transact(1002, data, null, 0);
654                data.recycle();
655
656                updateFlingerOptions();
657            }
658        } catch (RemoteException ex) {
659        }
660    }
661
662    private void writeDisableOverlaysOption() {
663        try {
664            IBinder flinger = ServiceManager.getService("SurfaceFlinger");
665            if (flinger != null) {
666                Parcel data = Parcel.obtain();
667                data.writeInterfaceToken("android.ui.ISurfaceComposer");
668                final int disableOverlays = mDisableOverlays.isChecked() ? 1 : 0;
669                data.writeInt(disableOverlays);
670                flinger.transact(1008, data, null, 0);
671                data.recycle();
672
673                updateFlingerOptions();
674            }
675        } catch (RemoteException ex) {
676        }
677    }
678
679    private void updateHardwareUiOptions() {
680        updateCheckBox(mForceHardwareUi, SystemProperties.getBoolean(HARDWARE_UI_PROPERTY, false));
681    }
682
683    private void writeHardwareUiOptions() {
684        SystemProperties.set(HARDWARE_UI_PROPERTY, mForceHardwareUi.isChecked() ? "true" : "false");
685        pokeSystemProperties();
686    }
687
688    private void updateMsaaOptions() {
689        updateCheckBox(mForceMsaa, SystemProperties.getBoolean(MSAA_PROPERTY, false));
690    }
691
692    private void writeMsaaOptions() {
693        SystemProperties.set(MSAA_PROPERTY, mForceMsaa.isChecked() ? "true" : "false");
694        pokeSystemProperties();
695    }
696
697    private void updateTrackFrameTimeOptions() {
698        updateCheckBox(mTrackFrameTime,
699                SystemProperties.getBoolean(HardwareRenderer.PROFILE_PROPERTY, false));
700    }
701
702    private void writeTrackFrameTimeOptions() {
703        SystemProperties.set(HardwareRenderer.PROFILE_PROPERTY,
704                mTrackFrameTime.isChecked() ? "true" : "false");
705        pokeSystemProperties();
706    }
707
708    private void updateShowHwScreenUpdatesOptions() {
709        updateCheckBox(mShowHwScreenUpdates,
710                SystemProperties.getBoolean(HardwareRenderer.DEBUG_DIRTY_REGIONS_PROPERTY, false));
711    }
712
713    private void writeShowHwScreenUpdatesOptions() {
714        SystemProperties.set(HardwareRenderer.DEBUG_DIRTY_REGIONS_PROPERTY,
715                mShowHwScreenUpdates.isChecked() ? "true" : null);
716        pokeSystemProperties();
717    }
718
719    private void updateShowHwLayersUpdatesOptions() {
720        updateCheckBox(mShowHwLayersUpdates, SystemProperties.getBoolean(
721                HardwareRenderer.DEBUG_SHOW_LAYERS_UPDATES_PROPERTY, false));
722    }
723
724    private void writeShowHwLayersUpdatesOptions() {
725        SystemProperties.set(HardwareRenderer.DEBUG_SHOW_LAYERS_UPDATES_PROPERTY,
726                mShowHwLayersUpdates.isChecked() ? "true" : null);
727        pokeSystemProperties();
728    }
729
730    private void updateShowHwOverdrawOptions() {
731        updateCheckBox(mShowHwOverdraw, SystemProperties.getBoolean(
732                HardwareRenderer.DEBUG_SHOW_OVERDRAW_PROPERTY, false));
733    }
734
735    private void writeShowHwOverdrawOptions() {
736        SystemProperties.set(HardwareRenderer.DEBUG_SHOW_OVERDRAW_PROPERTY,
737                mShowHwOverdraw.isChecked() ? "true" : null);
738        pokeSystemProperties();
739    }
740
741    private void updateDebugLayoutOptions() {
742        updateCheckBox(mDebugLayout,
743                SystemProperties.getBoolean(View.DEBUG_LAYOUT_PROPERTY, false));
744    }
745
746    private void writeDebugLayoutOptions() {
747        SystemProperties.set(View.DEBUG_LAYOUT_PROPERTY,
748                mDebugLayout.isChecked() ? "true" : "false");
749        pokeSystemProperties();
750    }
751
752    private void updateCpuUsageOptions() {
753        updateCheckBox(mShowCpuUsage, Settings.Global.getInt(getActivity().getContentResolver(),
754                Settings.Global.SHOW_PROCESSES, 0) != 0);
755    }
756
757    private void writeCpuUsageOptions() {
758        boolean value = mShowCpuUsage.isChecked();
759        Settings.Global.putInt(getActivity().getContentResolver(),
760                Settings.Global.SHOW_PROCESSES, value ? 1 : 0);
761        Intent service = (new Intent())
762                .setClassName("com.android.systemui", "com.android.systemui.LoadAverageService");
763        if (value) {
764            getActivity().startService(service);
765        } else {
766            getActivity().stopService(service);
767        }
768    }
769
770    private void writeImmediatelyDestroyActivitiesOptions() {
771        try {
772            ActivityManagerNative.getDefault().setAlwaysFinish(
773                    mImmediatelyDestroyActivities.isChecked());
774        } catch (RemoteException ex) {
775        }
776    }
777
778    private void updateImmediatelyDestroyActivitiesOptions() {
779        updateCheckBox(mImmediatelyDestroyActivities, Settings.Global.getInt(
780            getActivity().getContentResolver(), Settings.Global.ALWAYS_FINISH_ACTIVITIES, 0) != 0);
781    }
782
783    private void updateAnimationScaleValue(int which, ListPreference pref) {
784        try {
785            float scale = mWindowManager.getAnimationScale(which);
786            if (scale != 1) {
787                mHaveDebugSettings = true;
788            }
789            CharSequence[] values = pref.getEntryValues();
790            for (int i=0; i<values.length; i++) {
791                float val = Float.parseFloat(values[i].toString());
792                if (scale <= val) {
793                    pref.setValueIndex(i);
794                    pref.setSummary(pref.getEntries()[i]);
795                    return;
796                }
797            }
798            pref.setValueIndex(values.length-1);
799            pref.setSummary(pref.getEntries()[0]);
800        } catch (RemoteException e) {
801        }
802    }
803
804    private void updateAnimationScaleOptions() {
805        updateAnimationScaleValue(0, mWindowAnimationScale);
806        updateAnimationScaleValue(1, mTransitionAnimationScale);
807        updateAnimationScaleValue(2, mAnimatorDurationScale);
808    }
809
810    private void writeAnimationScaleOption(int which, ListPreference pref, Object newValue) {
811        try {
812            float scale = newValue != null ? Float.parseFloat(newValue.toString()) : 1;
813            mWindowManager.setAnimationScale(which, scale);
814            updateAnimationScaleValue(which, pref);
815        } catch (RemoteException e) {
816        }
817    }
818
819    private void updateOverlayDisplayDevicesOptions() {
820        String value = Settings.Global.getString(getActivity().getContentResolver(),
821                Settings.Global.OVERLAY_DISPLAY_DEVICES);
822        if (value == null) {
823            value = "";
824        }
825
826        CharSequence[] values = mOverlayDisplayDevices.getEntryValues();
827        for (int i = 0; i < values.length; i++) {
828            if (value.contentEquals(values[i])) {
829                mOverlayDisplayDevices.setValueIndex(i);
830                mOverlayDisplayDevices.setSummary(mOverlayDisplayDevices.getEntries()[i]);
831                return;
832            }
833        }
834        mOverlayDisplayDevices.setValueIndex(0);
835        mOverlayDisplayDevices.setSummary(mOverlayDisplayDevices.getEntries()[0]);
836    }
837
838    private void writeOverlayDisplayDevicesOptions(Object newValue) {
839        Settings.Global.putString(getActivity().getContentResolver(),
840                Settings.Global.OVERLAY_DISPLAY_DEVICES, (String)newValue);
841        updateOverlayDisplayDevicesOptions();
842    }
843
844    private void updateOpenGLTracesOptions() {
845        String value = SystemProperties.get(OPENGL_TRACES_PROPERTY);
846        if (value == null) {
847            value = "";
848        }
849
850        CharSequence[] values = mOpenGLTraces.getEntryValues();
851        for (int i = 0; i < values.length; i++) {
852            if (value.contentEquals(values[i])) {
853                mOpenGLTraces.setValueIndex(i);
854                mOpenGLTraces.setSummary(mOpenGLTraces.getEntries()[i]);
855                return;
856            }
857        }
858        mOpenGLTraces.setValueIndex(0);
859        mOpenGLTraces.setSummary(mOpenGLTraces.getEntries()[0]);
860    }
861
862    private void writeOpenGLTracesOptions(Object newValue) {
863        SystemProperties.set(OPENGL_TRACES_PROPERTY, newValue == null ? "" : newValue.toString());
864        pokeSystemProperties();
865        updateOpenGLTracesOptions();
866    }
867
868    private void updateAppProcessLimitOptions() {
869        try {
870            int limit = ActivityManagerNative.getDefault().getProcessLimit();
871            CharSequence[] values = mAppProcessLimit.getEntryValues();
872            for (int i=0; i<values.length; i++) {
873                int val = Integer.parseInt(values[i].toString());
874                if (val >= limit) {
875                    if (i != 0) {
876                        mHaveDebugSettings = true;
877                    }
878                    mAppProcessLimit.setValueIndex(i);
879                    mAppProcessLimit.setSummary(mAppProcessLimit.getEntries()[i]);
880                    return;
881                }
882            }
883            mAppProcessLimit.setValueIndex(0);
884            mAppProcessLimit.setSummary(mAppProcessLimit.getEntries()[0]);
885        } catch (RemoteException e) {
886        }
887    }
888
889    private void writeAppProcessLimitOptions(Object newValue) {
890        try {
891            int limit = newValue != null ? Integer.parseInt(newValue.toString()) : -1;
892            ActivityManagerNative.getDefault().setProcessLimit(limit);
893            updateAppProcessLimitOptions();
894        } catch (RemoteException e) {
895        }
896    }
897
898    private void writeShowAllANRsOptions() {
899        Settings.Secure.putInt(getActivity().getContentResolver(),
900                Settings.Secure.ANR_SHOW_BACKGROUND,
901                mShowAllANRs.isChecked() ? 1 : 0);
902    }
903
904    private void updateShowAllANRsOptions() {
905        updateCheckBox(mShowAllANRs, Settings.Secure.getInt(
906            getActivity().getContentResolver(), Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0);
907    }
908
909    private void updateEnableTracesOptions() {
910        long flags = SystemProperties.getLong(Trace.PROPERTY_TRACE_TAG_ENABLEFLAGS, 0);
911        String[] values = mEnableTracesPref.getEntryValues();
912        int numSet = 0;
913        for (int i=Trace.TRACE_FLAGS_START_BIT; i<values.length; i++) {
914            boolean set = (flags&(1<<i)) != 0;
915            mEnableTracesPref.setValue(i-Trace.TRACE_FLAGS_START_BIT, set);
916            if (set) {
917                numSet++;
918            }
919        }
920        if (numSet == 0) {
921            mEnableTracesPref.setSummary(R.string.enable_traces_summary_none);
922        } else if (numSet == values.length) {
923            mHaveDebugSettings = true;
924            mEnableTracesPref.setSummary(R.string.enable_traces_summary_all);
925        } else {
926            mHaveDebugSettings = true;
927            mEnableTracesPref.setSummary(getString(R.string.enable_traces_summary_num, numSet));
928        }
929    }
930
931    private void writeEnableTracesOptions() {
932        long value = 0;
933        String[] values = mEnableTracesPref.getEntryValues();
934        for (int i=Trace.TRACE_FLAGS_START_BIT; i<values.length; i++) {
935            if (mEnableTracesPref.getValue(i-Trace.TRACE_FLAGS_START_BIT)) {
936                value |= 1<<i;
937            }
938        }
939        writeEnableTracesOptions(value);
940        // Make sure summary is updated.
941        updateEnableTracesOptions();
942    }
943
944    private void writeEnableTracesOptions(long value) {
945        SystemProperties.set(Trace.PROPERTY_TRACE_TAG_ENABLEFLAGS,
946                "0x" + Long.toString(value, 16));
947        pokeSystemProperties();
948    }
949
950    @Override
951    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
952        if (buttonView == mEnabledSwitch) {
953            if (isChecked != mLastEnabledState) {
954                if (isChecked) {
955                    mDialogClicked = false;
956                    if (mEnableDialog != null) dismissDialogs();
957                    mEnableDialog = new AlertDialog.Builder(getActivity()).setMessage(
958                            getActivity().getResources().getString(
959                                    R.string.dev_settings_warning_message))
960                            .setTitle(R.string.dev_settings_warning_title)
961                            .setIconAttribute(android.R.attr.alertDialogIcon)
962                            .setPositiveButton(android.R.string.yes, this)
963                            .setNegativeButton(android.R.string.no, this)
964                            .show();
965                    mEnableDialog.setOnDismissListener(this);
966                } else {
967                    resetDangerousOptions();
968                    Settings.Global.putInt(getActivity().getContentResolver(),
969                            Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0);
970                    mLastEnabledState = isChecked;
971                    setPrefsEnabledState(mLastEnabledState);
972                }
973            }
974        }
975    }
976
977    @Override
978    public void onActivityResult(int requestCode, int resultCode, Intent data) {
979        if (requestCode == RESULT_DEBUG_APP) {
980            if (resultCode == Activity.RESULT_OK) {
981                mDebugApp = data.getAction();
982                writeDebuggerOptions();
983                updateDebuggerOptions();
984            }
985        } else {
986            super.onActivityResult(requestCode, resultCode, data);
987        }
988    }
989
990    @Override
991    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
992
993        if (Utils.isMonkeyRunning()) {
994            return false;
995        }
996
997        if (preference == mEnableAdb) {
998            if (mEnableAdb.isChecked()) {
999                mDialogClicked = false;
1000                if (mAdbDialog != null) dismissDialogs();
1001                mAdbDialog = new AlertDialog.Builder(getActivity()).setMessage(
1002                        getActivity().getResources().getString(R.string.adb_warning_message))
1003                        .setTitle(R.string.adb_warning_title)
1004                        .setIconAttribute(android.R.attr.alertDialogIcon)
1005                        .setPositiveButton(android.R.string.yes, this)
1006                        .setNegativeButton(android.R.string.no, this)
1007                        .show();
1008                mAdbDialog.setOnDismissListener(this);
1009            } else {
1010                Settings.Global.putInt(getActivity().getContentResolver(),
1011                        Settings.Global.ADB_ENABLED, 0);
1012                mVerifyAppsOverUsb.setEnabled(false);
1013                mVerifyAppsOverUsb.setChecked(false);
1014                updateBugreportOptions();
1015            }
1016        } else if (preference == mBugreportInPower) {
1017            Settings.Secure.putInt(getActivity().getContentResolver(),
1018                    Settings.Secure.BUGREPORT_IN_POWER_MENU,
1019                    mBugreportInPower.isChecked() ? 1 : 0);
1020        } else if (preference == mKeepScreenOn) {
1021            Settings.Global.putInt(getActivity().getContentResolver(),
1022                    Settings.Global.STAY_ON_WHILE_PLUGGED_IN,
1023                    mKeepScreenOn.isChecked() ?
1024                    (BatteryManager.BATTERY_PLUGGED_AC | BatteryManager.BATTERY_PLUGGED_USB) : 0);
1025        } else if (preference == mEnforceReadExternal) {
1026            if (mEnforceReadExternal.isChecked()) {
1027                ConfirmEnforceFragment.show(this);
1028            } else {
1029                setPermissionEnforced(getActivity(), READ_EXTERNAL_STORAGE, false);
1030            }
1031        } else if (preference == mAllowMockLocation) {
1032            Settings.Secure.putInt(getActivity().getContentResolver(),
1033                    Settings.Secure.ALLOW_MOCK_LOCATION,
1034                    mAllowMockLocation.isChecked() ? 1 : 0);
1035        } else if (preference == mDebugAppPref) {
1036            startActivityForResult(new Intent(getActivity(), AppPicker.class), RESULT_DEBUG_APP);
1037        } else if (preference == mWaitForDebugger) {
1038            writeDebuggerOptions();
1039        } else if (preference == mVerifyAppsOverUsb) {
1040            writeVerifyAppsOverUsbOptions();
1041        } else if (preference == mStrictMode) {
1042            writeStrictModeVisualOptions();
1043        } else if (preference == mPointerLocation) {
1044            writePointerLocationOptions();
1045        } else if (preference == mShowTouches) {
1046            writeShowTouchesOptions();
1047        } else if (preference == mShowScreenUpdates) {
1048            writeShowUpdatesOption();
1049        } else if (preference == mDisableOverlays) {
1050            writeDisableOverlaysOption();
1051        } else if (preference == mShowCpuUsage) {
1052            writeCpuUsageOptions();
1053        } else if (preference == mImmediatelyDestroyActivities) {
1054            writeImmediatelyDestroyActivitiesOptions();
1055        } else if (preference == mShowAllANRs) {
1056            writeShowAllANRsOptions();
1057        } else if (preference == mForceHardwareUi) {
1058            writeHardwareUiOptions();
1059        } else if (preference == mForceMsaa) {
1060            writeMsaaOptions();
1061        } else if (preference == mTrackFrameTime) {
1062            writeTrackFrameTimeOptions();
1063        } else if (preference == mShowHwScreenUpdates) {
1064            writeShowHwScreenUpdatesOptions();
1065        } else if (preference == mShowHwLayersUpdates) {
1066            writeShowHwLayersUpdatesOptions();
1067        } else if (preference == mShowHwOverdraw) {
1068            writeShowHwOverdrawOptions();
1069        } else if (preference == mDebugLayout) {
1070            writeDebugLayoutOptions();
1071        }
1072
1073        return false;
1074    }
1075
1076    @Override
1077    public boolean onPreferenceChange(Preference preference, Object newValue) {
1078        if (HDCP_CHECKING_KEY.equals(preference.getKey())) {
1079            SystemProperties.set(HDCP_CHECKING_PROPERTY, newValue.toString());
1080            updateHdcpValues();
1081            pokeSystemProperties();
1082            return true;
1083        } else if (preference == mWindowAnimationScale) {
1084            writeAnimationScaleOption(0, mWindowAnimationScale, newValue);
1085            return true;
1086        } else if (preference == mTransitionAnimationScale) {
1087            writeAnimationScaleOption(1, mTransitionAnimationScale, newValue);
1088            return true;
1089        } else if (preference == mAnimatorDurationScale) {
1090            writeAnimationScaleOption(2, mAnimatorDurationScale, newValue);
1091            return true;
1092        } else if (preference == mOverlayDisplayDevices) {
1093            writeOverlayDisplayDevicesOptions(newValue);
1094            return true;
1095        } else if (preference == mOpenGLTraces) {
1096            writeOpenGLTracesOptions(newValue);
1097            return true;
1098        } else if (preference == mEnableTracesPref) {
1099            writeEnableTracesOptions();
1100            return true;
1101        } else if (preference == mAppProcessLimit) {
1102            writeAppProcessLimitOptions(newValue);
1103            return true;
1104        }
1105        return false;
1106    }
1107
1108    private void dismissDialogs() {
1109        if (mAdbDialog != null) {
1110            mAdbDialog.dismiss();
1111            mAdbDialog = null;
1112        }
1113        if (mEnableDialog != null) {
1114            mEnableDialog.dismiss();
1115            mEnableDialog = null;
1116        }
1117    }
1118
1119    public void onClick(DialogInterface dialog, int which) {
1120        if (dialog == mAdbDialog) {
1121            if (which == DialogInterface.BUTTON_POSITIVE) {
1122                mDialogClicked = true;
1123                Settings.Global.putInt(getActivity().getContentResolver(),
1124                        Settings.Global.ADB_ENABLED, 1);
1125                mVerifyAppsOverUsb.setEnabled(true);
1126                updateVerifyAppsOverUsbOptions();
1127                updateBugreportOptions();
1128            } else {
1129                // Reset the toggle
1130                mEnableAdb.setChecked(false);
1131            }
1132        } else if (dialog == mEnableDialog) {
1133            if (which == DialogInterface.BUTTON_POSITIVE) {
1134                mDialogClicked = true;
1135                Settings.Global.putInt(getActivity().getContentResolver(),
1136                        Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
1137                mLastEnabledState = true;
1138                setPrefsEnabledState(mLastEnabledState);
1139            } else {
1140                // Reset the toggle
1141                mEnabledSwitch.setChecked(false);
1142            }
1143        }
1144    }
1145
1146    public void onDismiss(DialogInterface dialog) {
1147        // Assuming that onClick gets called first
1148        if (dialog == mAdbDialog) {
1149            if (!mDialogClicked) {
1150                mEnableAdb.setChecked(false);
1151            }
1152            mAdbDialog = null;
1153        } else if (dialog == mEnableDialog) {
1154            if (!mDialogClicked) {
1155                mEnabledSwitch.setChecked(false);
1156            }
1157            mEnableDialog = null;
1158        }
1159    }
1160
1161    @Override
1162    public void onDestroy() {
1163        dismissDialogs();
1164        super.onDestroy();
1165    }
1166
1167    void pokeSystemProperties() {
1168        if (!mDontPokeProperties) {
1169            //noinspection unchecked
1170            (new SystemPropPoker()).execute();
1171        }
1172    }
1173
1174    static class SystemPropPoker extends AsyncTask<Void, Void, Void> {
1175        @Override
1176        protected Void doInBackground(Void... params) {
1177            String[] services;
1178            try {
1179                services = ServiceManager.listServices();
1180            } catch (RemoteException e) {
1181                return null;
1182            }
1183            for (String service : services) {
1184                IBinder obj = ServiceManager.checkService(service);
1185                if (obj != null) {
1186                    Parcel data = Parcel.obtain();
1187                    try {
1188                        obj.transact(IBinder.SYSPROPS_TRANSACTION, data, null, 0);
1189                    } catch (RemoteException e) {
1190                    } catch (Exception e) {
1191                        Log.i("DevSettings", "Somone wrote a bad service '" + service
1192                                + "' that doesn't like to be poked: " + e);
1193                    }
1194                    data.recycle();
1195                }
1196            }
1197            return null;
1198        }
1199    }
1200
1201    /**
1202     * Dialog to confirm enforcement of {@link android.Manifest.permission#READ_EXTERNAL_STORAGE}.
1203     */
1204    public static class ConfirmEnforceFragment extends DialogFragment {
1205        public static void show(DevelopmentSettings parent) {
1206            final ConfirmEnforceFragment dialog = new ConfirmEnforceFragment();
1207            dialog.setTargetFragment(parent, 0);
1208            dialog.show(parent.getFragmentManager(), TAG_CONFIRM_ENFORCE);
1209        }
1210
1211        @Override
1212        public Dialog onCreateDialog(Bundle savedInstanceState) {
1213            final Context context = getActivity();
1214
1215            final AlertDialog.Builder builder = new AlertDialog.Builder(context);
1216            builder.setTitle(R.string.enforce_read_external_confirm_title);
1217            builder.setMessage(R.string.enforce_read_external_confirm_message);
1218
1219            builder.setPositiveButton(android.R.string.ok, new OnClickListener() {
1220                @Override
1221                public void onClick(DialogInterface dialog, int which) {
1222                    setPermissionEnforced(context, READ_EXTERNAL_STORAGE, true);
1223                    ((DevelopmentSettings) getTargetFragment()).updateAllOptions();
1224                }
1225            });
1226            builder.setNegativeButton(android.R.string.cancel, new OnClickListener() {
1227                @Override
1228                public void onClick(DialogInterface dialog, int which) {
1229                    ((DevelopmentSettings) getTargetFragment()).updateAllOptions();
1230                }
1231            });
1232
1233            return builder.create();
1234        }
1235    }
1236
1237    private static boolean isPermissionEnforced(String permission) {
1238        try {
1239            return ActivityThread.getPackageManager().isPermissionEnforced(permission);
1240        } catch (RemoteException e) {
1241            throw new RuntimeException("Problem talking with PackageManager", e);
1242        }
1243    }
1244
1245    private static void setPermissionEnforced(
1246            Context context, String permission, boolean enforced) {
1247        try {
1248            // TODO: offload to background thread
1249            ActivityThread.getPackageManager()
1250                    .setPermissionEnforced(READ_EXTERNAL_STORAGE, enforced);
1251        } catch (RemoteException e) {
1252            throw new RuntimeException("Problem talking with PackageManager", e);
1253        }
1254    }
1255}
1256