1 /* //device/tools/ddms/src/com/android/ddms/PrefsDialog.java
3 ** Copyright 2007, The Android Open Source Project
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
9 ** http://www.apache.org/licenses/LICENSE-2.0
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
18 package com.android.ddms;
20 import com.android.ddmlib.DdmConstants;
21 import com.android.ddmlib.DdmPreferences;
22 import com.android.ddmlib.Log;
23 import com.android.ddmlib.Log.LogLevel;
24 import com.android.ddmuilib.DdmUiPreferences;
25 import com.android.ddmuilib.PortFieldEditor;
26 import com.android.sdkstats.SdkStatsService;
28 import org.eclipse.jface.preference.BooleanFieldEditor;
29 import org.eclipse.jface.preference.DirectoryFieldEditor;
30 import org.eclipse.jface.preference.FieldEditorPreferencePage;
31 import org.eclipse.jface.preference.FontFieldEditor;
32 import org.eclipse.jface.preference.IntegerFieldEditor;
33 import org.eclipse.jface.preference.PreferenceDialog;
34 import org.eclipse.jface.preference.PreferenceManager;
35 import org.eclipse.jface.preference.PreferenceNode;
36 import org.eclipse.jface.preference.PreferencePage;
37 import org.eclipse.jface.preference.PreferenceStore;
38 import org.eclipse.jface.preference.RadioGroupFieldEditor;
39 import org.eclipse.jface.util.IPropertyChangeListener;
40 import org.eclipse.jface.util.PropertyChangeEvent;
41 import org.eclipse.swt.SWT;
42 import org.eclipse.swt.events.SelectionAdapter;
43 import org.eclipse.swt.events.SelectionEvent;
44 import org.eclipse.swt.graphics.FontData;
45 import org.eclipse.swt.graphics.Point;
46 import org.eclipse.swt.layout.GridData;
47 import org.eclipse.swt.layout.GridLayout;
48 import org.eclipse.swt.widgets.Composite;
49 import org.eclipse.swt.widgets.Control;
50 import org.eclipse.swt.widgets.Link;
51 import org.eclipse.swt.widgets.Shell;
54 import java.io.IOException;
59 public final class PrefsDialog {
62 private static PreferenceStore mPrefStore;
64 // public const values for storage
65 public final static String SHELL_X = "shellX"; //$NON-NLS-1$
66 public final static String SHELL_Y = "shellY"; //$NON-NLS-1$
67 public final static String SHELL_WIDTH = "shellWidth"; //$NON-NLS-1$
68 public final static String SHELL_HEIGHT = "shellHeight"; //$NON-NLS-1$
69 public final static String EXPLORER_SHELL_X = "explorerShellX"; //$NON-NLS-1$
70 public final static String EXPLORER_SHELL_Y = "explorerShellY"; //$NON-NLS-1$
71 public final static String EXPLORER_SHELL_WIDTH = "explorerShellWidth"; //$NON-NLS-1$
72 public final static String EXPLORER_SHELL_HEIGHT = "explorerShellHeight"; //$NON-NLS-1$
73 public final static String SHOW_NATIVE_HEAP = "native"; //$NON-NLS-1$
75 public final static String LOGCAT_COLUMN_MODE = "ddmsLogColumnMode"; //$NON-NLS-1$
76 public final static String LOGCAT_FONT = "ddmsLogFont"; //$NON-NLS-1$
78 public final static String LOGCAT_COLUMN_MODE_AUTO = "auto"; //$NON-NLS-1$
79 public final static String LOGCAT_COLUMN_MODE_MANUAL = "manual"; //$NON-NLS-1$
81 private final static String PREFS_DEBUG_PORT_BASE = "adbDebugBasePort"; //$NON-NLS-1$
82 private final static String PREFS_SELECTED_DEBUG_PORT = "debugSelectedPort"; //$NON-NLS-1$
83 private final static String PREFS_DEFAULT_THREAD_UPDATE = "defaultThreadUpdateEnabled"; //$NON-NLS-1$
84 private final static String PREFS_DEFAULT_HEAP_UPDATE = "defaultHeapUpdateEnabled"; //$NON-NLS-1$
85 private final static String PREFS_THREAD_REFRESH_INTERVAL = "threadStatusInterval"; //$NON-NLS-1$
86 private final static String PREFS_LOG_LEVEL = "ddmsLogLevel"; //$NON-NLS-1$
87 private final static String PREFS_TIMEOUT = "timeOut"; //$NON-NLS-1$
91 * Private constructor -- do not instantiate.
93 private PrefsDialog() {}
96 * Return the PreferenceStore that holds our values.
98 public static PreferenceStore getStore() {
103 * Save the prefs to the config file.
105 public static void save() {
109 catch (IOException ioe) {
110 Log.w("ddms", "Failed saving prefs file: " + ioe.getMessage());
115 * Do some one-time prep.
117 * The original plan was to let the individual classes define their
118 * own defaults, which we would get and then override with the config
119 * file. However, PreferencesStore.load() doesn't trigger the "changed"
120 * events, which means we have to pull the loaded config values out by
123 * So, we set the defaults, load the values from the config file, and
124 * then run through and manually export the values. Then we duplicate
125 * the second part later on for the "changed" events.
127 public static void init() {
128 assert mPrefStore == null;
130 mPrefStore = SdkStatsService.getPreferenceStore();
132 if (mPrefStore == null) {
133 // we have a serious issue here...
135 "failed to access both the user HOME directory and the system wide temp folder. Quitting.");
139 // configure default values
140 setDefaults(System.getProperty("user.home")); //$NON-NLS-1$
142 // listen for changes
143 mPrefStore.addPropertyChangeListener(new ChangeListener());
145 // Now we initialize the value of the preference, from the values in the store.
147 // First the ddm lib.
148 DdmPreferences.setDebugPortBase(mPrefStore.getInt(PREFS_DEBUG_PORT_BASE));
149 DdmPreferences.setSelectedDebugPort(mPrefStore.getInt(PREFS_SELECTED_DEBUG_PORT));
150 DdmPreferences.setLogLevel(mPrefStore.getString(PREFS_LOG_LEVEL));
151 DdmPreferences.setInitialThreadUpdate(mPrefStore.getBoolean(PREFS_DEFAULT_THREAD_UPDATE));
152 DdmPreferences.setInitialHeapUpdate(mPrefStore.getBoolean(PREFS_DEFAULT_HEAP_UPDATE));
153 DdmPreferences.setTimeOut(mPrefStore.getInt(PREFS_TIMEOUT));
155 // some static values
156 String out = System.getenv("ANDROID_PRODUCT_OUT"); //$NON-NLS-1$
157 DdmUiPreferences.setSymbolsLocation(out + File.separator + "symbols"); //$NON-NLS-1$
158 DdmUiPreferences.setAddr2LineLocation("arm-eabi-addr2line"); //$NON-NLS-1$
160 String traceview = System.getProperty("com.android.ddms.bindir"); //$NON-NLS-1$
161 if (traceview != null && traceview.length() != 0) {
162 traceview += File.separator + DdmConstants.FN_TRACEVIEW;
164 traceview = DdmConstants.FN_TRACEVIEW;
166 DdmUiPreferences.setTraceviewLocation(traceview);
169 DdmUiPreferences.setStore(mPrefStore);
170 DdmUiPreferences.setThreadRefreshInterval(mPrefStore.getInt(PREFS_THREAD_REFRESH_INTERVAL));
174 * Set default values for all preferences. These are either defined
175 * statically or are based on the values set by the class initializers
178 * The other threads (e.g. VMWatcherThread) haven't been created yet,
179 * so we want to use static values rather than reading fields from
180 * class.getInstance().
182 private static void setDefaults(String homeDir) {
183 mPrefStore.setDefault(PREFS_DEBUG_PORT_BASE, DdmPreferences.DEFAULT_DEBUG_PORT_BASE);
185 mPrefStore.setDefault(PREFS_SELECTED_DEBUG_PORT,
186 DdmPreferences.DEFAULT_SELECTED_DEBUG_PORT);
188 mPrefStore.setDefault(PREFS_DEFAULT_THREAD_UPDATE, true);
189 mPrefStore.setDefault(PREFS_DEFAULT_HEAP_UPDATE, false);
190 mPrefStore.setDefault(PREFS_THREAD_REFRESH_INTERVAL,
191 DdmUiPreferences.DEFAULT_THREAD_REFRESH_INTERVAL);
193 mPrefStore.setDefault("textSaveDir", homeDir); //$NON-NLS-1$
194 mPrefStore.setDefault("imageSaveDir", homeDir); //$NON-NLS-1$
196 mPrefStore.setDefault(PREFS_LOG_LEVEL, "info"); //$NON-NLS-1$
198 mPrefStore.setDefault(PREFS_TIMEOUT, DdmPreferences.DEFAULT_TIMEOUT);
200 // choose a default font for the text output
201 FontData fdat = new FontData("Courier", 10, SWT.NORMAL); //$NON-NLS-1$
202 mPrefStore.setDefault("textOutputFont", fdat.toString()); //$NON-NLS-1$
204 // layout information.
205 mPrefStore.setDefault(SHELL_X, 100);
206 mPrefStore.setDefault(SHELL_Y, 100);
207 mPrefStore.setDefault(SHELL_WIDTH, 800);
208 mPrefStore.setDefault(SHELL_HEIGHT, 600);
210 mPrefStore.setDefault(EXPLORER_SHELL_X, 50);
211 mPrefStore.setDefault(EXPLORER_SHELL_Y, 50);
213 mPrefStore.setDefault(SHOW_NATIVE_HEAP, false);
218 * Create a "listener" to take action when preferences change. These are
219 * required for ongoing activities that don't check prefs on each use.
221 * This is only invoked when something explicitly changes the value of
222 * a preference (e.g. not when the prefs file is loaded).
224 private static class ChangeListener implements IPropertyChangeListener {
225 public void propertyChange(PropertyChangeEvent event) {
226 String changed = event.getProperty();
228 if (changed.equals(PREFS_DEBUG_PORT_BASE)) {
229 DdmPreferences.setDebugPortBase(mPrefStore.getInt(PREFS_DEBUG_PORT_BASE));
230 } else if (changed.equals(PREFS_SELECTED_DEBUG_PORT)) {
231 DdmPreferences.setSelectedDebugPort(mPrefStore.getInt(PREFS_SELECTED_DEBUG_PORT));
232 } else if (changed.equals(PREFS_LOG_LEVEL)) {
233 DdmPreferences.setLogLevel((String)event.getNewValue());
234 } else if (changed.equals("textSaveDir")) {
235 mPrefStore.setValue("lastTextSaveDir",
236 (String) event.getNewValue());
237 } else if (changed.equals("imageSaveDir")) {
238 mPrefStore.setValue("lastImageSaveDir",
239 (String) event.getNewValue());
240 } else if (changed.equals(PREFS_TIMEOUT)) {
241 DdmPreferences.setTimeOut(mPrefStore.getInt(PREFS_TIMEOUT));
243 Log.v("ddms", "Preference change: " + event.getProperty()
244 + ": '" + event.getOldValue()
245 + "' --> '" + event.getNewValue() + "'");
252 * Create and display the dialog.
254 public static void run(Shell shell) {
255 assert mPrefStore != null;
257 PreferenceManager prefMgr = new PreferenceManager();
259 PreferenceNode node, subNode;
261 // this didn't work -- got NPE, possibly from class lookup:
262 //PreferenceNode app = new PreferenceNode("app", "Application", null,
263 // AppPrefs.class.getName());
265 node = new PreferenceNode("debugger", new DebuggerPrefs());
266 prefMgr.addToRoot(node);
268 subNode = new PreferenceNode("panel", new PanelPrefs());
269 //prefMgr.addTo(node.getId(), subNode);
270 prefMgr.addToRoot(subNode);
272 node = new PreferenceNode("LogCat", new LogCatPrefs());
273 prefMgr.addToRoot(node);
275 node = new PreferenceNode("misc", new MiscPrefs());
276 prefMgr.addToRoot(node);
278 node = new PreferenceNode("stats", new UsageStatsPrefs());
279 prefMgr.addToRoot(node);
281 PreferenceDialog dlg = new PreferenceDialog(shell, prefMgr);
282 dlg.setPreferenceStore(mPrefStore);
291 catch (IOException ioe) {
294 // discard the stuff we created
300 * "Debugger" prefs page.
302 private static class DebuggerPrefs extends FieldEditorPreferencePage {
307 public DebuggerPrefs() {
308 super(GRID); // use "grid" layout so edit boxes line up
309 setTitle("Debugger");
313 * Create field editors.
316 protected void createFieldEditors() {
317 IntegerFieldEditor ife;
319 ife = new PortFieldEditor(PREFS_DEBUG_PORT_BASE,
320 "Starting value for local port:", getFieldEditorParent());
323 ife = new PortFieldEditor(PREFS_SELECTED_DEBUG_PORT,
324 "Port of Selected VM:", getFieldEditorParent());
330 * "Panel" prefs page.
332 private static class PanelPrefs extends FieldEditorPreferencePage {
337 public PanelPrefs() {
338 super(FLAT); // use "flat" layout
339 setTitle("Info Panels");
343 * Create field editors.
346 protected void createFieldEditors() {
347 BooleanFieldEditor bfe;
348 IntegerFieldEditor ife;
350 bfe = new BooleanFieldEditor(PREFS_DEFAULT_THREAD_UPDATE,
351 "Thread updates enabled by default", getFieldEditorParent());
354 bfe = new BooleanFieldEditor(PREFS_DEFAULT_HEAP_UPDATE,
355 "Heap updates enabled by default", getFieldEditorParent());
358 ife = new IntegerFieldEditor(PREFS_THREAD_REFRESH_INTERVAL,
359 "Thread status interval (seconds):", getFieldEditorParent());
360 ife.setValidRange(1, 60);
366 * "logcat" prefs page.
368 private static class LogCatPrefs extends FieldEditorPreferencePage {
373 public LogCatPrefs() {
374 super(FLAT); // use "flat" layout
379 * Create field editors.
382 protected void createFieldEditors() {
383 RadioGroupFieldEditor rgfe;
385 rgfe = new RadioGroupFieldEditor(PrefsDialog.LOGCAT_COLUMN_MODE,
386 "Message Column Resizing Mode", 1, new String[][] {
387 { "Manual", PrefsDialog.LOGCAT_COLUMN_MODE_MANUAL },
388 { "Automatic", PrefsDialog.LOGCAT_COLUMN_MODE_AUTO },
390 getFieldEditorParent(), true);
393 FontFieldEditor ffe = new FontFieldEditor(PrefsDialog.LOGCAT_FONT, "Text output font:",
394 getFieldEditorParent());
402 private static class MiscPrefs extends FieldEditorPreferencePage {
408 super(FLAT); // use "flat" layout
413 * Create field editors.
416 protected void createFieldEditors() {
417 DirectoryFieldEditor dfe;
420 IntegerFieldEditor ife = new IntegerFieldEditor(PREFS_TIMEOUT,
421 "ADB connection time out (ms):", getFieldEditorParent());
424 dfe = new DirectoryFieldEditor("textSaveDir",
425 "Default text save dir:", getFieldEditorParent());
428 dfe = new DirectoryFieldEditor("imageSaveDir",
429 "Default image save dir:", getFieldEditorParent());
432 ffe = new FontFieldEditor("textOutputFont", "Text output font:",
433 getFieldEditorParent());
436 RadioGroupFieldEditor rgfe;
438 rgfe = new RadioGroupFieldEditor(PREFS_LOG_LEVEL,
439 "Logging Level", 1, new String[][] {
440 { "Verbose", LogLevel.VERBOSE.getStringValue() },
441 { "Debug", LogLevel.DEBUG.getStringValue() },
442 { "Info", LogLevel.INFO.getStringValue() },
443 { "Warning", LogLevel.WARN.getStringValue() },
444 { "Error", LogLevel.ERROR.getStringValue() },
445 { "Assert", LogLevel.ASSERT.getStringValue() },
447 getFieldEditorParent(), true);
453 * "Device" prefs page.
455 private static class UsageStatsPrefs extends PreferencePage {
457 private BooleanFieldEditor mOptInCheckbox;
458 private Composite mTop;
463 public UsageStatsPrefs() {
464 setTitle("Usage Stats");
468 protected Control createContents(Composite parent) {
469 mTop = new Composite(parent, SWT.NONE);
470 mTop.setLayout(new GridLayout(1, false));
471 mTop.setLayoutData(new GridData(GridData.FILL_BOTH));
473 Link text = new Link(mTop, SWT.WRAP);
474 text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
475 text.setText(SdkStatsService.BODY_TEXT);
477 text.addSelectionListener(new SelectionAdapter() {
479 public void widgetSelected(SelectionEvent event) {
480 SdkStatsService.openUrl(event.text);
484 mOptInCheckbox = new BooleanFieldEditor(SdkStatsService.PING_OPT_IN,
485 SdkStatsService.CHECKBOX_TEXT, mTop);
486 mOptInCheckbox.setPage(this);
487 mOptInCheckbox.setPreferenceStore(getPreferenceStore());
488 mOptInCheckbox.load();
494 protected Point doComputeSize() {
496 return mTop.computeSize(450, SWT.DEFAULT, true);
499 return super.doComputeSize();
503 protected void performDefaults() {
504 if (mOptInCheckbox != null) {
505 mOptInCheckbox.loadDefault();
507 super.performDefaults();
511 public void performApply() {
512 if (mOptInCheckbox != null) {
513 mOptInCheckbox.store();
515 super.performApply();
519 public boolean performOk() {
520 if (mOptInCheckbox != null) {
521 mOptInCheckbox.store();
523 return super.performOk();