DevelopmentSettings.java revision c5ec5be6e4e796bd44475c63d43d8806e522aaf1
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 android.app.ActivityManagerNative;
20import android.app.AlertDialog;
21import android.app.Dialog;
22import android.content.ContentResolver;
23import android.content.DialogInterface;
24import android.content.Intent;
25import android.os.BatteryManager;
26import android.os.Build;
27import android.os.Bundle;
28import android.os.IBinder;
29import android.os.Parcel;
30import android.os.RemoteException;
31import android.os.ServiceManager;
32import android.os.StrictMode;
33import android.os.SystemProperties;
34import android.preference.CheckBoxPreference;
35import android.preference.ListPreference;
36import android.preference.Preference;
37import android.preference.PreferenceFragment;
38import android.preference.PreferenceScreen;
39import android.preference.Preference.OnPreferenceChangeListener;
40import android.provider.Settings;
41import android.text.TextUtils;
42import android.view.IWindowManager;
43
44/*
45 * Displays preferences for application developers.
46 */
47public class DevelopmentSettings extends PreferenceFragment
48        implements DialogInterface.OnClickListener, DialogInterface.OnDismissListener,
49                OnPreferenceChangeListener {
50
51    private static final String ENABLE_ADB = "enable_adb";
52    private static final String KEEP_SCREEN_ON = "keep_screen_on";
53    private static final String ALLOW_MOCK_LOCATION = "allow_mock_location";
54    private static final String HDCP_CHECKING_KEY = "hdcp_checking";
55    private static final String HDCP_CHECKING_PROPERTY = "persist.sys.hdcp_checking";
56
57    private static final String STRICT_MODE_KEY = "strict_mode";
58    private static final String POINTER_LOCATION_KEY = "pointer_location";
59    private static final String SHOW_SCREEN_UPDATES_KEY = "show_screen_updates";
60    private static final String SHOW_CPU_USAGE_KEY = "show_cpu_usage";
61    private static final String WINDOW_ANIMATION_SCALE_KEY = "window_animation_scale";
62    private static final String TRANSITION_ANIMATION_SCALE_KEY = "transition_animation_scale";
63
64    private static final String IMMEDIATELY_DESTROY_ACTIVITIES_KEY
65            = "immediately_destroy_activities";
66    private static final String APP_PROCESS_LIMIT_KEY = "app_process_limit";
67
68    private IWindowManager mWindowManager;
69
70    private CheckBoxPreference mEnableAdb;
71    private CheckBoxPreference mKeepScreenOn;
72    private CheckBoxPreference mAllowMockLocation;
73
74    private CheckBoxPreference mStrictMode;
75    private CheckBoxPreference mPointerLocation;
76    private CheckBoxPreference mShowScreenUpdates;
77    private CheckBoxPreference mShowCpuUsage;
78    private ListPreference mWindowAnimationScale;
79    private ListPreference mTransitionAnimationScale;
80
81    private CheckBoxPreference mImmediatelyDestroyActivities;
82    private ListPreference mAppProcessLimit;
83
84    // To track whether Yes was clicked in the adb warning dialog
85    private boolean mOkClicked;
86
87    private Dialog mOkDialog;
88
89    @Override
90    public void onCreate(Bundle icicle) {
91        super.onCreate(icicle);
92
93        mWindowManager = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
94
95        addPreferencesFromResource(R.xml.development_prefs);
96
97        mEnableAdb = (CheckBoxPreference) findPreference(ENABLE_ADB);
98        mKeepScreenOn = (CheckBoxPreference) findPreference(KEEP_SCREEN_ON);
99        mAllowMockLocation = (CheckBoxPreference) findPreference(ALLOW_MOCK_LOCATION);
100
101        mStrictMode = (CheckBoxPreference) findPreference(STRICT_MODE_KEY);
102        mPointerLocation = (CheckBoxPreference) findPreference(POINTER_LOCATION_KEY);
103        mShowScreenUpdates = (CheckBoxPreference) findPreference(SHOW_SCREEN_UPDATES_KEY);
104        mShowCpuUsage = (CheckBoxPreference) findPreference(SHOW_CPU_USAGE_KEY);
105        mWindowAnimationScale = (ListPreference) findPreference(WINDOW_ANIMATION_SCALE_KEY);
106        mWindowAnimationScale.setOnPreferenceChangeListener(this);
107        mTransitionAnimationScale = (ListPreference) findPreference(TRANSITION_ANIMATION_SCALE_KEY);
108        mTransitionAnimationScale.setOnPreferenceChangeListener(this);
109
110        mImmediatelyDestroyActivities = (CheckBoxPreference) findPreference(
111                IMMEDIATELY_DESTROY_ACTIVITIES_KEY);
112        mAppProcessLimit = (ListPreference) findPreference(APP_PROCESS_LIMIT_KEY);
113        mAppProcessLimit.setOnPreferenceChangeListener(this);
114
115        removeHdcpOptionsForProduction();
116    }
117
118    private void removeHdcpOptionsForProduction() {
119        if ("user".equals(Build.TYPE)) {
120            Preference hdcpChecking = findPreference(HDCP_CHECKING_KEY);
121            if (hdcpChecking != null) {
122                // Remove the preference
123                getPreferenceScreen().removePreference(hdcpChecking);
124            }
125        }
126    }
127
128    @Override
129    public void onResume() {
130        super.onResume();
131
132        final ContentResolver cr = getActivity().getContentResolver();
133        mEnableAdb.setChecked(Settings.Secure.getInt(cr,
134                Settings.Secure.ADB_ENABLED, 0) != 0);
135        mKeepScreenOn.setChecked(Settings.System.getInt(cr,
136                Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0) != 0);
137        mAllowMockLocation.setChecked(Settings.Secure.getInt(cr,
138                Settings.Secure.ALLOW_MOCK_LOCATION, 0) != 0);
139        updateHdcpValues();
140        updateStrictModeVisualOptions();
141        updatePointerLocationOptions();
142        updateFlingerOptions();
143        updateCpuUsageOptions();
144        updateAnimationScaleOptions();
145        updateImmediatelyDestroyActivitiesOptions();
146        updateAppProcessLimitOptions();
147    }
148
149    private void updateHdcpValues() {
150        int index = 1; // Defaults to drm-only. Needs to match with R.array.hdcp_checking_values
151        ListPreference hdcpChecking = (ListPreference) findPreference(HDCP_CHECKING_KEY);
152        if (hdcpChecking != null) {
153            String currentValue = SystemProperties.get(HDCP_CHECKING_PROPERTY);
154            String[] values = getResources().getStringArray(R.array.hdcp_checking_values);
155            String[] summaries = getResources().getStringArray(R.array.hdcp_checking_summaries);
156            for (int i = 0; i < values.length; i++) {
157                if (currentValue.equals(values[i])) {
158                    index = i;
159                    break;
160                }
161            }
162            hdcpChecking.setValue(values[index]);
163            hdcpChecking.setSummary(summaries[index]);
164            hdcpChecking.setOnPreferenceChangeListener(this);
165        }
166    }
167
168    // Returns the current state of the system property that controls
169    // strictmode flashes.  One of:
170    //    0: not explicitly set one way or another
171    //    1: on
172    //    2: off
173    private int currentStrictModeActiveIndex() {
174        if (TextUtils.isEmpty(SystemProperties.get(StrictMode.VISUAL_PROPERTY))) {
175            return 0;
176        }
177        boolean enabled = SystemProperties.getBoolean(StrictMode.VISUAL_PROPERTY, false);
178        return enabled ? 1 : 2;
179    }
180
181    private void writeStrictModeVisualOptions() {
182        try {
183            mWindowManager.setStrictModeVisualIndicatorPreference(mStrictMode.isChecked()
184                    ? "1" : "");
185        } catch (RemoteException e) {
186        }
187    }
188
189    private void updateStrictModeVisualOptions() {
190        mStrictMode.setChecked(currentStrictModeActiveIndex() == 1);
191    }
192
193    private void writePointerLocationOptions() {
194        Settings.System.putInt(getActivity().getContentResolver(),
195                Settings.System.POINTER_LOCATION, mPointerLocation.isChecked() ? 1 : 0);
196    }
197
198    private void updatePointerLocationOptions() {
199        mPointerLocation.setChecked(Settings.System.getInt(getActivity().getContentResolver(),
200                Settings.System.POINTER_LOCATION, 0) != 0);
201    }
202
203    private void updateFlingerOptions() {
204        // magic communication with surface flinger.
205        try {
206            IBinder flinger = ServiceManager.getService("SurfaceFlinger");
207            if (flinger != null) {
208                Parcel data = Parcel.obtain();
209                Parcel reply = Parcel.obtain();
210                data.writeInterfaceToken("android.ui.ISurfaceComposer");
211                flinger.transact(1010, data, reply, 0);
212                @SuppressWarnings("unused")
213                int showCpu = reply.readInt();
214                @SuppressWarnings("unused")
215                int enableGL = reply.readInt();
216                int showUpdates = reply.readInt();
217                mShowScreenUpdates.setChecked(showUpdates != 0);
218                @SuppressWarnings("unused")
219                int showBackground = reply.readInt();
220                reply.recycle();
221                data.recycle();
222            }
223        } catch (RemoteException ex) {
224        }
225    }
226
227    private void writeFlingerOptions() {
228        try {
229            IBinder flinger = ServiceManager.getService("SurfaceFlinger");
230            if (flinger != null) {
231                Parcel data = Parcel.obtain();
232                data.writeInterfaceToken("android.ui.ISurfaceComposer");
233                data.writeInt(mShowScreenUpdates.isChecked() ? 1 : 0);
234                flinger.transact(1002, data, null, 0);
235                data.recycle();
236
237                updateFlingerOptions();
238            }
239        } catch (RemoteException ex) {
240        }
241    }
242
243    private void updateCpuUsageOptions() {
244        mShowCpuUsage.setChecked(Settings.System.getInt(getActivity().getContentResolver(),
245                Settings.System.SHOW_PROCESSES, 0) != 0);
246    }
247
248    private void writeCpuUsageOptions() {
249        boolean value = mShowCpuUsage.isChecked();
250        Settings.System.putInt(getActivity().getContentResolver(),
251                Settings.System.SHOW_PROCESSES, value ? 1 : 0);
252        Intent service = (new Intent())
253                .setClassName("com.android.systemui", "com.android.systemui.LoadAverageService");
254        if (value) {
255            getActivity().startService(service);
256        } else {
257            getActivity().stopService(service);
258        }
259    }
260
261    private void writeImmediatelyDestroyActivitiesOptions() {
262        try {
263            ActivityManagerNative.getDefault().setAlwaysFinish(
264                    mImmediatelyDestroyActivities.isChecked());
265        } catch (RemoteException ex) {
266        }
267    }
268
269    private void updateImmediatelyDestroyActivitiesOptions() {
270        mImmediatelyDestroyActivities.setChecked(Settings.System.getInt(
271            getActivity().getContentResolver(), Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0);
272    }
273
274    private void updateAnimationScaleValue(int which, ListPreference pref) {
275        try {
276            float scale = mWindowManager.getAnimationScale(which);
277            CharSequence[] values = pref.getEntryValues();
278            for (int i=0; i<values.length; i++) {
279                float val = Float.parseFloat(values[i].toString());
280                if (scale <= val) {
281                    pref.setValueIndex(i);
282                    pref.setSummary(pref.getEntries()[i]);
283                    return;
284                }
285            }
286            pref.setValueIndex(values.length-1);
287            pref.setSummary(pref.getEntries()[0]);
288        } catch (RemoteException e) {
289        }
290    }
291
292    private void updateAnimationScaleOptions() {
293        updateAnimationScaleValue(0, mWindowAnimationScale);
294        updateAnimationScaleValue(1, mTransitionAnimationScale);
295    }
296
297    private void writeAnimationScaleOption(int which, ListPreference pref, Object newValue) {
298        try {
299            float scale = Float.parseFloat(newValue.toString());
300            mWindowManager.setAnimationScale(which, scale);
301            updateAnimationScaleValue(which, pref);
302        } catch (RemoteException e) {
303        }
304    }
305
306    private void updateAppProcessLimitOptions() {
307        try {
308            int limit = ActivityManagerNative.getDefault().getProcessLimit();
309            CharSequence[] values = mAppProcessLimit.getEntryValues();
310            for (int i=0; i<values.length; i++) {
311                int val = Integer.parseInt(values[i].toString());
312                if (val >= limit) {
313                    mAppProcessLimit.setValueIndex(i);
314                    mAppProcessLimit.setSummary(mAppProcessLimit.getEntries()[i]);
315                    return;
316                }
317            }
318            mAppProcessLimit.setValueIndex(0);
319            mAppProcessLimit.setSummary(mAppProcessLimit.getEntries()[0]);
320        } catch (RemoteException e) {
321        }
322    }
323
324    private void writeAppProcessLimitOptions(Object newValue) {
325        try {
326            int limit = Integer.parseInt(newValue.toString());
327            ActivityManagerNative.getDefault().setProcessLimit(limit);
328            updateAppProcessLimitOptions();
329        } catch (RemoteException e) {
330        }
331    }
332
333    @Override
334    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
335
336        if (Utils.isMonkeyRunning()) {
337            return false;
338        }
339
340        if (preference == mEnableAdb) {
341            if (mEnableAdb.isChecked()) {
342                mOkClicked = false;
343                if (mOkDialog != null) dismissDialog();
344                mOkDialog = new AlertDialog.Builder(getActivity()).setMessage(
345                        getActivity().getResources().getString(R.string.adb_warning_message))
346                        .setTitle(R.string.adb_warning_title)
347                        .setIcon(android.R.drawable.ic_dialog_alert)
348                        .setPositiveButton(android.R.string.yes, this)
349                        .setNegativeButton(android.R.string.no, this)
350                        .show();
351                mOkDialog.setOnDismissListener(this);
352            } else {
353                Settings.Secure.putInt(getActivity().getContentResolver(),
354                        Settings.Secure.ADB_ENABLED, 0);
355            }
356        } else if (preference == mKeepScreenOn) {
357            Settings.System.putInt(getActivity().getContentResolver(),
358                    Settings.System.STAY_ON_WHILE_PLUGGED_IN,
359                    mKeepScreenOn.isChecked() ?
360                    (BatteryManager.BATTERY_PLUGGED_AC | BatteryManager.BATTERY_PLUGGED_USB) : 0);
361        } else if (preference == mAllowMockLocation) {
362            Settings.Secure.putInt(getActivity().getContentResolver(),
363                    Settings.Secure.ALLOW_MOCK_LOCATION,
364                    mAllowMockLocation.isChecked() ? 1 : 0);
365        } else if (preference == mStrictMode) {
366            writeStrictModeVisualOptions();
367        } else if (preference == mPointerLocation) {
368            writePointerLocationOptions();
369        } else if (preference == mShowScreenUpdates) {
370            writeFlingerOptions();
371        } else if (preference == mShowCpuUsage) {
372            writeCpuUsageOptions();
373        } else if (preference == mImmediatelyDestroyActivities) {
374            writeImmediatelyDestroyActivitiesOptions();
375        }
376
377        return false;
378    }
379
380    @Override
381    public boolean onPreferenceChange(Preference preference, Object newValue) {
382        if (HDCP_CHECKING_KEY.equals(preference.getKey())) {
383            SystemProperties.set(HDCP_CHECKING_PROPERTY, newValue.toString());
384            updateHdcpValues();
385            return true;
386        } else if (preference == mWindowAnimationScale) {
387            writeAnimationScaleOption(0, mWindowAnimationScale, newValue);
388            return true;
389        } else if (preference == mTransitionAnimationScale) {
390            writeAnimationScaleOption(1, mTransitionAnimationScale, newValue);
391            return true;
392        } else if (preference == mAppProcessLimit) {
393            writeAppProcessLimitOptions(newValue);
394            return true;
395        }
396        return false;
397    }
398
399    private void dismissDialog() {
400        if (mOkDialog == null) return;
401        mOkDialog.dismiss();
402        mOkDialog = null;
403    }
404
405    public void onClick(DialogInterface dialog, int which) {
406        if (which == DialogInterface.BUTTON_POSITIVE) {
407            mOkClicked = true;
408            Settings.Secure.putInt(getActivity().getContentResolver(),
409                    Settings.Secure.ADB_ENABLED, 1);
410        } else {
411            // Reset the toggle
412            mEnableAdb.setChecked(false);
413        }
414    }
415
416    public void onDismiss(DialogInterface dialog) {
417        // Assuming that onClick gets called first
418        if (!mOkClicked) {
419            mEnableAdb.setChecked(false);
420        }
421    }
422
423    @Override
424    public void onDestroy() {
425        dismissDialog();
426        super.onDestroy();
427    }
428}
429