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