Merge "Extract DDMS PreferenceStore."
diff --git a/ddms/app/src/com/android/ddms/Main.java b/ddms/app/src/com/android/ddms/Main.java
index b538ba9..14ef910 100644
--- a/ddms/app/src/com/android/ddms/Main.java
+++ b/ddms/app/src/com/android/ddms/Main.java
@@ -76,14 +76,13 @@
// if this is the first time using ddms or adt, open up the stats service
// opt out dialog, and request user for permissions.
- if (!SdkStatsService.pingPermissionsSet()) {
- SdkStatsService.getUserPermissionForPing(new Shell(Display.getDefault()));
- }
+ SdkStatsService stats = new SdkStatsService();
+ stats.checkUserPermissionForPing(new Shell(Display.getDefault()));
// the "ping" argument means to check in with the server and exit
// the application name and version number must also be supplied
if (args.length >= 3 && args[0].equals("ping")) {
- SdkStatsService.ping(args[1], args[2]);
+ stats.ping(args[1], args[2]);
return;
} else if (args.length > 0) {
Log.e("ddms", "Unknown argument: " + args[0]);
@@ -101,7 +100,8 @@
// we're past the point where ddms can be called just to send a ping, so we can
// ping for ddms itself.
- ping(ddmsParentLocation);
+ ping(stats, ddmsParentLocation);
+ stats = null;
DebugPortManager.setProvider(DebugPortProvider.getInstance());
@@ -131,7 +131,7 @@
return System.getProperty("os.name").startsWith("Mac OS"); //$NON-NLS-1$ //$NON-NLS-2$
}
- private static void ping(String ddmsParentLocation) {
+ private static void ping(SdkStatsService stats, String ddmsParentLocation) {
Properties p = new Properties();
try{
File sourceProp;
@@ -143,7 +143,7 @@
p.load(new FileInputStream(sourceProp));
sRevision = p.getProperty("Pkg.Revision"); //$NON-NLS-1$
if (sRevision != null && sRevision.length() > 0) {
- SdkStatsService.ping("ddms", sRevision); //$NON-NLS-1$
+ stats.ping("ddms", sRevision); //$NON-NLS-1$
}
} catch (FileNotFoundException e) {
// couldn't find the file? don't ping.
diff --git a/ddms/app/src/com/android/ddms/PrefsDialog.java b/ddms/app/src/com/android/ddms/PrefsDialog.java
index 4745ed7..0669d7c 100644
--- a/ddms/app/src/com/android/ddms/PrefsDialog.java
+++ b/ddms/app/src/com/android/ddms/PrefsDialog.java
@@ -1,19 +1,18 @@
-/* //device/tools/ddms/src/com/android/ddms/PrefsDialog.java
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.android.ddms;
@@ -25,8 +24,8 @@
import com.android.ddmuilib.PortFieldEditor;
import com.android.ddmuilib.logcat.LogCatMessageList;
import com.android.ddmuilib.logcat.LogCatPanel;
+import com.android.sdkstats.DdmsPreferenceStore;
import com.android.sdkstats.SdkStatsPermissionDialog;
-import com.android.sdkstats.SdkStatsService;
import org.eclipse.jface.preference.BooleanFieldEditor;
import org.eclipse.jface.preference.DirectoryFieldEditor;
@@ -63,9 +62,6 @@
*/
public final class PrefsDialog {
- // Preference store.
- private static PreferenceStore mPrefStore;
-
// public const values for storage
public final static String SHELL_X = "shellX"; //$NON-NLS-1$
public final static String SHELL_Y = "shellY"; //$NON-NLS-1$
@@ -94,6 +90,8 @@
private final static String PREFS_USE_ADBHOST = "useAdbHost"; //$NON-NLS-1$
private final static String PREFS_ADBHOST_VALUE = "adbHostValue"; //$NON-NLS-1$
+ // Preference store.
+ private static DdmsPreferenceStore mStore = new DdmsPreferenceStore();
/**
* Private constructor -- do not instantiate.
@@ -102,17 +100,23 @@
/**
* Return the PreferenceStore that holds our values.
+ *
+ * @deprecated Callers should use {@link DdmsPreferenceStore} directly.
*/
+ @Deprecated
public static PreferenceStore getStore() {
- return mPrefStore;
+ return mStore.getPreferenceStore();
}
/**
* Save the prefs to the config file.
+ *
+ * @deprecated Callers should use {@link DdmsPreferenceStore} directly.
*/
+ @Deprecated
public static void save() {
try {
- mPrefStore.save();
+ mStore.getPreferenceStore().save();
}
catch (IOException ioe) {
Log.w("ddms", "Failed saving prefs file: " + ioe.getMessage());
@@ -133,11 +137,9 @@
* the second part later on for the "changed" events.
*/
public static void init() {
- assert mPrefStore == null;
+ PreferenceStore prefStore = mStore.getPreferenceStore();
- mPrefStore = SdkStatsService.getPreferenceStore();
-
- if (mPrefStore == null) {
+ if (prefStore == null) {
// we have a serious issue here...
Log.e("ddms",
"failed to access both the user HOME directory and the system wide temp folder. Quitting.");
@@ -148,20 +150,20 @@
setDefaults(System.getProperty("user.home")); //$NON-NLS-1$
// listen for changes
- mPrefStore.addPropertyChangeListener(new ChangeListener());
+ prefStore.addPropertyChangeListener(new ChangeListener());
// Now we initialize the value of the preference, from the values in the store.
// First the ddm lib.
- DdmPreferences.setDebugPortBase(mPrefStore.getInt(PREFS_DEBUG_PORT_BASE));
- DdmPreferences.setSelectedDebugPort(mPrefStore.getInt(PREFS_SELECTED_DEBUG_PORT));
- DdmPreferences.setLogLevel(mPrefStore.getString(PREFS_LOG_LEVEL));
- DdmPreferences.setInitialThreadUpdate(mPrefStore.getBoolean(PREFS_DEFAULT_THREAD_UPDATE));
- DdmPreferences.setInitialHeapUpdate(mPrefStore.getBoolean(PREFS_DEFAULT_HEAP_UPDATE));
- DdmPreferences.setTimeOut(mPrefStore.getInt(PREFS_TIMEOUT));
- DdmPreferences.setProfilerBufferSizeMb(mPrefStore.getInt(PREFS_PROFILER_BUFFER_SIZE_MB));
- DdmPreferences.setUseAdbHost(mPrefStore.getBoolean(PREFS_USE_ADBHOST));
- DdmPreferences.setAdbHostValue(mPrefStore.getString(PREFS_ADBHOST_VALUE));
+ DdmPreferences.setDebugPortBase(prefStore.getInt(PREFS_DEBUG_PORT_BASE));
+ DdmPreferences.setSelectedDebugPort(prefStore.getInt(PREFS_SELECTED_DEBUG_PORT));
+ DdmPreferences.setLogLevel(prefStore.getString(PREFS_LOG_LEVEL));
+ DdmPreferences.setInitialThreadUpdate(prefStore.getBoolean(PREFS_DEFAULT_THREAD_UPDATE));
+ DdmPreferences.setInitialHeapUpdate(prefStore.getBoolean(PREFS_DEFAULT_HEAP_UPDATE));
+ DdmPreferences.setTimeOut(prefStore.getInt(PREFS_TIMEOUT));
+ DdmPreferences.setProfilerBufferSizeMb(prefStore.getInt(PREFS_PROFILER_BUFFER_SIZE_MB));
+ DdmPreferences.setUseAdbHost(prefStore.getBoolean(PREFS_USE_ADBHOST));
+ DdmPreferences.setAdbHostValue(prefStore.getString(PREFS_ADBHOST_VALUE));
// some static values
String out = System.getenv("ANDROID_PRODUCT_OUT"); //$NON-NLS-1$
@@ -177,8 +179,8 @@
DdmUiPreferences.setTraceviewLocation(traceview);
// Now the ddmui lib
- DdmUiPreferences.setStore(mPrefStore);
- DdmUiPreferences.setThreadRefreshInterval(mPrefStore.getInt(PREFS_THREAD_REFRESH_INTERVAL));
+ DdmUiPreferences.setStore(prefStore);
+ DdmUiPreferences.setThreadRefreshInterval(prefStore.getInt(PREFS_THREAD_REFRESH_INTERVAL));
}
/*
@@ -191,42 +193,44 @@
* class.getInstance().
*/
private static void setDefaults(String homeDir) {
- mPrefStore.setDefault(PREFS_DEBUG_PORT_BASE, DdmPreferences.DEFAULT_DEBUG_PORT_BASE);
+ PreferenceStore prefStore = mStore.getPreferenceStore();
- mPrefStore.setDefault(PREFS_SELECTED_DEBUG_PORT,
+ prefStore.setDefault(PREFS_DEBUG_PORT_BASE, DdmPreferences.DEFAULT_DEBUG_PORT_BASE);
+
+ prefStore.setDefault(PREFS_SELECTED_DEBUG_PORT,
DdmPreferences.DEFAULT_SELECTED_DEBUG_PORT);
- mPrefStore.setDefault(PREFS_USE_ADBHOST, DdmPreferences.DEFAULT_USE_ADBHOST);
- mPrefStore.setDefault(PREFS_ADBHOST_VALUE, DdmPreferences.DEFAULT_ADBHOST_VALUE);
+ prefStore.setDefault(PREFS_USE_ADBHOST, DdmPreferences.DEFAULT_USE_ADBHOST);
+ prefStore.setDefault(PREFS_ADBHOST_VALUE, DdmPreferences.DEFAULT_ADBHOST_VALUE);
- mPrefStore.setDefault(PREFS_DEFAULT_THREAD_UPDATE, true);
- mPrefStore.setDefault(PREFS_DEFAULT_HEAP_UPDATE, false);
- mPrefStore.setDefault(PREFS_THREAD_REFRESH_INTERVAL,
+ prefStore.setDefault(PREFS_DEFAULT_THREAD_UPDATE, true);
+ prefStore.setDefault(PREFS_DEFAULT_HEAP_UPDATE, false);
+ prefStore.setDefault(PREFS_THREAD_REFRESH_INTERVAL,
DdmUiPreferences.DEFAULT_THREAD_REFRESH_INTERVAL);
- mPrefStore.setDefault("textSaveDir", homeDir); //$NON-NLS-1$
- mPrefStore.setDefault("imageSaveDir", homeDir); //$NON-NLS-1$
+ prefStore.setDefault("textSaveDir", homeDir); //$NON-NLS-1$
+ prefStore.setDefault("imageSaveDir", homeDir); //$NON-NLS-1$
- mPrefStore.setDefault(PREFS_LOG_LEVEL, "info"); //$NON-NLS-1$
+ prefStore.setDefault(PREFS_LOG_LEVEL, "info"); //$NON-NLS-1$
- mPrefStore.setDefault(PREFS_TIMEOUT, DdmPreferences.DEFAULT_TIMEOUT);
- mPrefStore.setDefault(PREFS_PROFILER_BUFFER_SIZE_MB,
+ prefStore.setDefault(PREFS_TIMEOUT, DdmPreferences.DEFAULT_TIMEOUT);
+ prefStore.setDefault(PREFS_PROFILER_BUFFER_SIZE_MB,
DdmPreferences.DEFAULT_PROFILER_BUFFER_SIZE_MB);
// choose a default font for the text output
FontData fdat = new FontData("Courier", 10, SWT.NORMAL); //$NON-NLS-1$
- mPrefStore.setDefault("textOutputFont", fdat.toString()); //$NON-NLS-1$
+ prefStore.setDefault("textOutputFont", fdat.toString()); //$NON-NLS-1$
// layout information.
- mPrefStore.setDefault(SHELL_X, 100);
- mPrefStore.setDefault(SHELL_Y, 100);
- mPrefStore.setDefault(SHELL_WIDTH, 800);
- mPrefStore.setDefault(SHELL_HEIGHT, 600);
+ prefStore.setDefault(SHELL_X, 100);
+ prefStore.setDefault(SHELL_Y, 100);
+ prefStore.setDefault(SHELL_WIDTH, 800);
+ prefStore.setDefault(SHELL_HEIGHT, 600);
- mPrefStore.setDefault(EXPLORER_SHELL_X, 50);
- mPrefStore.setDefault(EXPLORER_SHELL_Y, 50);
+ prefStore.setDefault(EXPLORER_SHELL_X, 50);
+ prefStore.setDefault(EXPLORER_SHELL_Y, 50);
- mPrefStore.setDefault(SHOW_NATIVE_HEAP, false);
+ prefStore.setDefault(SHOW_NATIVE_HEAP, false);
}
@@ -240,28 +244,29 @@
private static class ChangeListener implements IPropertyChangeListener {
public void propertyChange(PropertyChangeEvent event) {
String changed = event.getProperty();
+ PreferenceStore prefStore = mStore.getPreferenceStore();
if (changed.equals(PREFS_DEBUG_PORT_BASE)) {
- DdmPreferences.setDebugPortBase(mPrefStore.getInt(PREFS_DEBUG_PORT_BASE));
+ DdmPreferences.setDebugPortBase(prefStore.getInt(PREFS_DEBUG_PORT_BASE));
} else if (changed.equals(PREFS_SELECTED_DEBUG_PORT)) {
- DdmPreferences.setSelectedDebugPort(mPrefStore.getInt(PREFS_SELECTED_DEBUG_PORT));
+ DdmPreferences.setSelectedDebugPort(prefStore.getInt(PREFS_SELECTED_DEBUG_PORT));
} else if (changed.equals(PREFS_LOG_LEVEL)) {
DdmPreferences.setLogLevel((String)event.getNewValue());
} else if (changed.equals("textSaveDir")) {
- mPrefStore.setValue("lastTextSaveDir",
+ prefStore.setValue("lastTextSaveDir",
(String) event.getNewValue());
} else if (changed.equals("imageSaveDir")) {
- mPrefStore.setValue("lastImageSaveDir",
+ prefStore.setValue("lastImageSaveDir",
(String) event.getNewValue());
} else if (changed.equals(PREFS_TIMEOUT)) {
- DdmPreferences.setTimeOut(mPrefStore.getInt(PREFS_TIMEOUT));
+ DdmPreferences.setTimeOut(prefStore.getInt(PREFS_TIMEOUT));
} else if (changed.equals(PREFS_PROFILER_BUFFER_SIZE_MB)) {
DdmPreferences.setProfilerBufferSizeMb(
- mPrefStore.getInt(PREFS_PROFILER_BUFFER_SIZE_MB));
+ prefStore.getInt(PREFS_PROFILER_BUFFER_SIZE_MB));
} else if (changed.equals(PREFS_USE_ADBHOST)) {
- DdmPreferences.setUseAdbHost(mPrefStore.getBoolean(PREFS_USE_ADBHOST));
+ DdmPreferences.setUseAdbHost(prefStore.getBoolean(PREFS_USE_ADBHOST));
} else if (changed.equals(PREFS_ADBHOST_VALUE)) {
- DdmPreferences.setAdbHostValue(mPrefStore.getString(PREFS_ADBHOST_VALUE));
+ DdmPreferences.setAdbHostValue(prefStore.getString(PREFS_ADBHOST_VALUE));
} else {
Log.v("ddms", "Preference change: " + event.getProperty()
+ ": '" + event.getOldValue()
@@ -275,7 +280,8 @@
* Create and display the dialog.
*/
public static void run(Shell shell) {
- assert mPrefStore != null;
+ PreferenceStore prefStore = mStore.getPreferenceStore();
+ assert prefStore != null;
PreferenceManager prefMgr = new PreferenceManager();
@@ -302,7 +308,7 @@
prefMgr.addToRoot(node);
PreferenceDialog dlg = new PreferenceDialog(shell, prefMgr);
- dlg.setPreferenceStore(mPrefStore);
+ dlg.setPreferenceStore(prefStore);
// run it
try {
@@ -313,7 +319,7 @@
// save prefs
try {
- mPrefStore.save();
+ prefStore.save();
}
catch (IOException ioe) {
}
@@ -549,7 +555,7 @@
}
});
- mOptInCheckbox = new BooleanFieldEditor(SdkStatsService.PING_OPT_IN,
+ mOptInCheckbox = new BooleanFieldEditor(DdmsPreferenceStore.PING_OPT_IN,
SdkStatsPermissionDialog.CHECKBOX_TEXT, mTop);
mOptInCheckbox.setPage(this);
mOptInCheckbox.setPreferenceStore(getPreferenceStore());
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/AndroidPreferencePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/AndroidPreferencePage.java
index 7fb2294..c67afdb 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/AndroidPreferencePage.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/AndroidPreferencePage.java
@@ -232,9 +232,8 @@
/* When the ADT preferences page is made visible, display the dialog to obtain
* permissions for the ping service. */
- if (!SdkStatsService.pingPermissionsSet()) {
- Shell parent = getShell();
- SdkStatsService.getUserPermissionForPing(parent);
- }
+ SdkStatsService stats = new SdkStatsService();
+ Shell parent = getShell();
+ stats.checkUserPermissionForPing(parent);
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/UsagePreferencePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/UsagePreferencePage.java
index 6c07fe9..a333bc5 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/UsagePreferencePage.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/UsagePreferencePage.java
@@ -16,6 +16,7 @@
package com.android.ide.eclipse.adt.internal.preferences;
+import com.android.sdkstats.DdmsPreferenceStore;
import com.android.sdkstats.SdkStatsPermissionDialog;
import com.android.sdkstats.SdkStatsService;
@@ -40,6 +41,7 @@
private static final int WRAP_WIDTH_PX = 200;
private BooleanFieldEditor mOptInCheckBox;
+ private DdmsPreferenceStore mStore = new DdmsPreferenceStore();
public UsagePreferencePage() {
}
@@ -73,10 +75,10 @@
}
});
- mOptInCheckBox = new BooleanFieldEditor(SdkStatsService.PING_OPT_IN,
+ mOptInCheckBox = new BooleanFieldEditor(DdmsPreferenceStore.PING_OPT_IN,
SdkStatsPermissionDialog.CHECKBOX_TEXT, top);
mOptInCheckBox.setPage(this);
- mOptInCheckBox.setPreferenceStore(SdkStatsService.getPreferenceStore());
+ mOptInCheckBox.setPreferenceStore(mStore.getPreferenceStore());
mOptInCheckBox.load();
return top;
@@ -119,14 +121,6 @@
}
private void save() {
- try {
- PreferenceStore store = SdkStatsService.getPreferenceStore();
- if (store != null) {
- store.setValue(SdkStatsService.PING_OPT_IN, mOptInCheckBox.getBooleanValue());
- store.save();
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
+ mStore.setPingOptIn(mOptInCheckBox.getBooleanValue());
}
}
diff --git a/sdkstats/src/com/android/sdkstats/DdmsPreferenceStore.java b/sdkstats/src/com/android/sdkstats/DdmsPreferenceStore.java
new file mode 100755
index 0000000..8875eb6
--- /dev/null
+++ b/sdkstats/src/com/android/sdkstats/DdmsPreferenceStore.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.sdkstats;
+
+import com.android.prefs.AndroidLocation;
+import com.android.prefs.AndroidLocation.AndroidLocationException;
+
+import org.eclipse.jface.preference.PreferenceStore;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Random;
+
+/** Utility class to send "ping" usage reports to the server. */
+public class DdmsPreferenceStore {
+
+ public final static String PING_OPT_IN = "pingOptIn"; //$NON-NLS-1$
+ private final static String PING_TIME = "pingTime"; //$NON-NLS-1$
+ private final static String PING_ID = "pingId"; //$NON-NLS-1$
+ private final static String ADT_STARTUP_WIZARD = "adtStrtWzd"; //$NON-NLS-1$
+ private final static String LAST_SDK_PATH = "lastSdkPath"; //$NON-NLS-1$
+
+ /**
+ * Lock for the preference store.
+ */
+ private static volatile Object[] sLock = new Object[0];
+ /**
+ * PreferenceStore for DDMS. Creation and usage must be synchronized on sLock.
+ * Don't use it directly, instead retrieve it via {@link #getPreferenceStore()}.
+ */
+ private static volatile PreferenceStore sPrefStore;
+
+ public DdmsPreferenceStore() {
+ }
+
+ /**
+ * Returns the DDMS {@link PreferenceStore}.
+ * This keeps a static reference on the store, so consequent calls will
+ * return always the same store.
+ */
+ public PreferenceStore getPreferenceStore() {
+ synchronized(sLock) {
+ if (sPrefStore == null) {
+ // get the location of the preferences
+ String homeDir = null;
+ try {
+ homeDir = AndroidLocation.getFolder();
+ } catch (AndroidLocationException e1) {
+ // pass, we'll do a dummy store since homeDir is null
+ }
+
+ if (homeDir == null) {
+ sPrefStore = new PreferenceStore();
+ return sPrefStore;
+ }
+
+ assert homeDir != null;
+
+ String rcFileName = homeDir + "ddms.cfg"; //$NON-NLS-1$
+
+ // also look for an old pref file in the previous location
+ String oldPrefPath = System.getProperty("user.home") //$NON-NLS-1$
+ + File.separator + ".ddmsrc"; //$NON-NLS-1$
+ File oldPrefFile = new File(oldPrefPath);
+ if (oldPrefFile.isFile()) {
+ try {
+ PreferenceStore oldStore = new PreferenceStore(oldPrefPath);
+ oldStore.load();
+
+ oldStore.save(new FileOutputStream(rcFileName), ""); //$NON-NLS-1$
+ oldPrefFile.delete();
+
+ PreferenceStore newStore = new PreferenceStore(rcFileName);
+ newStore.load();
+ sPrefStore = newStore;
+ } catch (IOException e) {
+ // create a new empty store.
+ sPrefStore = new PreferenceStore(rcFileName);
+ }
+ } else {
+ sPrefStore = new PreferenceStore(rcFileName);
+
+ try {
+ sPrefStore.load();
+ } catch (IOException e) {
+ System.err.println("Error Loading DDMS Preferences");
+ }
+ }
+ }
+
+ assert sPrefStore != null;
+ return sPrefStore;
+ }
+ }
+
+ /**
+ * Save the prefs to the config file.
+ */
+ public void save() {
+ PreferenceStore prefs = getPreferenceStore();
+ synchronized(sLock) {
+ try {
+ prefs.save();
+ }
+ catch (IOException ioe) {
+ // FIXME com.android.dmmlib.Log.w("ddms", "Failed saving prefs file: " + ioe.getMessage());
+ }
+ }
+ }
+
+ // ---- Utility methods to access some specifis prefs ----
+
+ /**
+ * Indicates whether the ping ID is set.
+ * This should be true when {@link #isPingOptIn()} is true.
+ *
+ * @return true if a ping ID is set, which means the user gave permission
+ * to use the ping service.
+ */
+ public boolean hasPingId() {
+ PreferenceStore prefs = getPreferenceStore();
+ synchronized(sLock) {
+ return prefs != null && prefs.contains(PING_ID);
+ }
+ }
+
+ /**
+ * Retrieves the current ping ID, if set.
+ * To know if the ping ID is set, use {@link #hasPingId()}.
+ * The value returned is 0L if there's no store or no ping ID set in the store.
+ */
+ public long getPingId() {
+ PreferenceStore prefs = getPreferenceStore();
+ synchronized(sLock) {
+ return prefs == null ? 0L : prefs.getLong(PING_ID);
+ }
+ }
+
+ /**
+ * Generates a new random ping ID and saves it in the preference store.
+ *
+ * @return The new ping ID.
+ */
+ public long generateNewPingId() {
+ PreferenceStore prefs = getPreferenceStore();
+
+ Random rnd = new Random();
+ long id = rnd.nextLong();
+
+ // Let's try to be conservative and avoid 0L as an ID.
+ // (ideally it would be nice to keep 0L as a special reserved value,
+ // to both have a default value and detect when variables aren't set
+ // properly. It's too late to enforce this, but we can still avoid
+ // generating new ones like this.)
+ for (int i = 0; id == 0L && i < 10; i++) {
+ id = rnd.nextLong();
+ }
+
+ synchronized(sLock) {
+ prefs.setValue(PING_ID, id);
+ try {
+ prefs.save();
+ } catch (IOException e) {
+ /* ignore exceptions while saving preferences */
+ }
+ }
+
+ return id;
+ }
+
+ /**
+ * Returns the "ping opt in" value from the preference store.
+ * This would be true if there's a valid preference store and
+ * the user opted for sending ping statistics.
+ */
+ public boolean isPingOptIn() {
+ PreferenceStore prefs = getPreferenceStore();
+ synchronized(sLock) {
+ return prefs != null && prefs.contains(PING_OPT_IN);
+ }
+ }
+
+ /**
+ * Saves the "ping opt in" value in the preference store.
+ *
+ * @param optIn The new user opt-in value.
+ */
+ public void setPingOptIn(boolean optIn) {
+ PreferenceStore prefs = getPreferenceStore();
+
+ synchronized(sLock) {
+ prefs.setValue(PING_OPT_IN, optIn);
+ try {
+ prefs.save();
+ } catch (IOException e) {
+ /* ignore exceptions while saving preferences */
+ }
+ }
+ }
+
+ /**
+ * Retrieves the ping time for the given app from the preference store.
+ * Callers should use {@link System#currentTimeMillis()} for time stamps.
+ *
+ * @param app The app name identifier.
+ * @return 0L if we don't have a preference store or there was no time
+ * recorded in the store for the requested app. Otherwise the time stamp
+ * from the store.
+ */
+ public long getPingTime(String app) {
+ PreferenceStore prefs = getPreferenceStore();
+ String timePref = PING_TIME + "." + app; //$NON-NLS-1$
+ synchronized(sLock) {
+ return prefs == null ? 0 : prefs.getLong(timePref);
+ }
+ }
+
+ /**
+ * Sets the ping time for the given app from the preference store.
+ * Callers should use {@link System#currentTimeMillis()} for time stamps.
+ *
+ * @param app The app name identifier.
+ * @param timeStamp The time stamp from the store.
+ * 0L is a sepcial value that should not be used.
+ */
+ public void setPingTime(String app, long timeStamp) {
+ PreferenceStore prefs = getPreferenceStore();
+ String timePref = PING_TIME + "." + app; //$NON-NLS-1$
+ synchronized(sLock) {
+ prefs.setValue(timePref, timeStamp);
+ try {
+ prefs.save();
+ } catch (IOException ioe) {
+ /* ignore exceptions while saving preferences */
+ }
+ }
+ }
+
+ /**
+ * True if there's a valid preference store and the ADT startup
+ * wizard has been shown once.
+ */
+ public boolean wasAdtStartupWizardShown() {
+ PreferenceStore prefs = getPreferenceStore();
+ synchronized(sLock) {
+ return prefs == null ? false : prefs.getBoolean(ADT_STARTUP_WIZARD);
+ }
+ }
+
+ /**
+ * Sets whether the ADT startup wizard has been shown.
+ */
+ public void setAdtStartupWizardShown(boolean shown) {
+ PreferenceStore prefs = getPreferenceStore();
+ synchronized(sLock) {
+ prefs.setValue(ADT_STARTUP_WIZARD, shown);
+ try {
+ prefs.save();
+ } catch (IOException ioe) {
+ /* ignore exceptions while saving preferences */
+ }
+ }
+ }
+
+ /**
+ * Retrieves the last SDK OS path.
+ * <p/>
+ * This is just an information value, the path may not exist, may not
+ * even be on an existing file system and/or may not point to an SDK
+ * anymore.
+ *
+ * @return The last SDK OS path from the preference store, or null if
+ * there is no store or an empty string if it is not defined.
+ */
+ public String getLastSdkPath() {
+ PreferenceStore prefs = getPreferenceStore();
+ synchronized(sLock) {
+ return prefs == null ? null : prefs.getString(LAST_SDK_PATH);
+ }
+ }
+
+ /**
+ * Sets the last SDK OS path.
+ *
+ * @param osSdkPath The SDK OS Path. Can be null or empty.
+ */
+ public void setLastSdkPath(String osSdkPath) {
+ PreferenceStore prefs = getPreferenceStore();
+ synchronized(sLock) {
+ prefs.setValue(LAST_SDK_PATH, osSdkPath);
+ try {
+ prefs.save();
+ } catch (IOException ioe) {
+ /* ignore exceptions while saving preferences */
+ }
+ }
+ }
+}
diff --git a/sdkstats/src/com/android/sdkstats/SdkStatsService.java b/sdkstats/src/com/android/sdkstats/SdkStatsService.java
index 25a7d97..b1b8c47 100644
--- a/sdkstats/src/com/android/sdkstats/SdkStatsService.java
+++ b/sdkstats/src/com/android/sdkstats/SdkStatsService.java
@@ -16,20 +16,13 @@
package com.android.sdkstats;
-import com.android.prefs.AndroidLocation;
-import com.android.prefs.AndroidLocation.AndroidLocationException;
-
-import org.eclipse.jface.preference.PreferenceStore;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
-import java.io.File;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
-import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -39,11 +32,10 @@
/** Minimum interval between ping, in milliseconds. */
private static final long PING_INTERVAL_MSEC = 86400 * 1000; // 1 day
- public final static String PING_OPT_IN = "pingOptIn"; //$NON-NLS-1$
- public final static String PING_TIME = "pingTime"; //$NON-NLS-1$
- public final static String PING_ID = "pingId"; //$NON-NLS-1$
+ private DdmsPreferenceStore mStore = new DdmsPreferenceStore();
- private static PreferenceStore sPrefStore;
+ public SdkStatsService() {
+ }
/**
* Send a "ping" to the Google toolbar server, if enough time has
@@ -58,19 +50,8 @@
* @param app name to report in the ping
* @param version to report in the ping
*/
- public static void ping(final String app, final String version) {
- doPing(app, version, getPreferenceStore());
- }
-
- /**
- * Find out if user has already set permissions for the ping service.
- * @return true if user has already set the permissions for the ping service. This could've
- * happened only if the user has already viewed the dialog displayed by
- * {@link #getUserPermissionForPing(Shell)}.
- */
- public static boolean pingPermissionsSet() {
- PreferenceStore prefs = getPreferenceStore();
- return prefs != null && prefs.contains(PING_ID);
+ public void ping(String app, String version) {
+ doPing(app, version);
}
/**
@@ -80,108 +61,60 @@
* Once the dialog has been shown, it sets a preference internally indicating that the user has
* viewed this dialog. This setting can be queried using {@link #pingPermissionsSet()}.
*/
- public static void getUserPermissionForPing(Shell parent) {
- PreferenceStore prefs = getPreferenceStore();
- getUserPermissionForPing(prefs, parent);
-
- // First time: make up a new ID. TODO: Use something more random?
- prefs.setValue(PING_ID, new Random().nextLong());
- try {
- prefs.save();
- } catch (IOException e) {
- /* ignore exceptions while saving preferences */
+ public void checkUserPermissionForPing(Shell parent) {
+ if (!mStore.hasPingId()) {
+ askUserPermissionForPing(parent);
+ mStore.generateNewPingId();
}
}
/**
- * Returns the DDMS {@link PreferenceStore}.
+ * Prompt the user for whether they want to opt out of reporting, and save the user
+ * input in preferences.
*/
- public static synchronized PreferenceStore getPreferenceStore() {
- if (sPrefStore == null) {
- // get the location of the preferences
- String homeDir = null;
- try {
- homeDir = AndroidLocation.getFolder();
- } catch (AndroidLocationException e1) {
- // pass, we'll do a dummy store since homeDir is null
+ private void askUserPermissionForPing(final Shell parent) {
+ final Display display = parent.getDisplay();
+ display.syncExec(new Runnable() {
+ public void run() {
+ SdkStatsPermissionDialog dialog = new SdkStatsPermissionDialog(parent);
+ dialog.open();
+ mStore.setPingOptIn(dialog.getPingUserPreference());
}
-
- if (homeDir != null) {
- String rcFileName = homeDir + "ddms.cfg"; //$NON-NLS-1$
-
- // also look for an old pref file in the previous location
- String oldPrefPath = System.getProperty("user.home") //$NON-NLS-1$
- + File.separator + ".ddmsrc"; //$NON-NLS-1$
- File oldPrefFile = new File(oldPrefPath);
- if (oldPrefFile.isFile()) {
- try {
- PreferenceStore oldStore = new PreferenceStore(oldPrefPath);
- oldStore.load();
-
- oldStore.save(new FileOutputStream(rcFileName), "");
- oldPrefFile.delete();
-
- PreferenceStore newStore = new PreferenceStore(rcFileName);
- newStore.load();
- sPrefStore = newStore;
- } catch (IOException e) {
- // create a new empty store.
- sPrefStore = new PreferenceStore(rcFileName);
- }
- } else {
- sPrefStore = new PreferenceStore(rcFileName);
-
- try {
- sPrefStore.load();
- } catch (IOException e) {
- System.err.println("Error Loading Preferences");
- }
- }
- } else {
- sPrefStore = new PreferenceStore();
- }
- }
-
- return sPrefStore;
+ });
}
+ // -------
+
/**
* Pings the usage stats server, as long as the prefs contain the opt-in boolean
*
* @param app name to report in the ping
* @param version to report in the ping
- * @param prefs the preference store where the opt-in value and ping times are store
*/
- private static void doPing(final String app, String version, PreferenceStore prefs) {
+ private void doPing(final String app, String version) {
// Validate the application and version input.
final String normalVersion = normalizeVersion(app, version);
// If the user has not opted in, do nothing and quietly return.
- if (!prefs.getBoolean(PING_OPT_IN)) {
+ if (!mStore.isPingOptIn()) {
// user opted out.
return;
}
// If the last ping *for this app* was too recent, do nothing.
- String timePref = PING_TIME + "." + app; //$NON-NLS-1$
long now = System.currentTimeMillis();
- long then = prefs.getLong(timePref);
+ long then = mStore.getPingTime(app);
if (now - then < PING_INTERVAL_MSEC) {
// too soon after a ping.
return;
}
// Record the time of the attempt, whether or not it succeeds.
- prefs.setValue(timePref, now);
- try {
- prefs.save();
- }
- catch (IOException ioe) {
- }
+ mStore.setPingTime(app, now);
// Send the ping itself in the background (don't block if the
// network is down or slow or confused).
- final long id = prefs.getLong(PING_ID);
+ final long id = mStore.getPingId();
new Thread() {
@Override
public void run() {
@@ -269,21 +202,6 @@
}
/**
- * Prompt the user for whether they want to opt out of reporting, and save the user
- * input in preferences.
- */
- private static void getUserPermissionForPing(final PreferenceStore prefs, final Shell parent) {
- final Display display = parent.getDisplay();
- display.syncExec(new Runnable() {
- public void run() {
- SdkStatsPermissionDialog dialog = new SdkStatsPermissionDialog(parent);
- dialog.open();
- prefs.setValue(PING_OPT_IN, dialog.getPingUserPreference());
- }
- });
- }
-
- /**
* Validate the supplied application version, and normalize the version.
* @param app to report
* @param version supplied by caller