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