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