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