blob: 95654138b9deaf2a251f3ba366bc937614e4c308 [file] [log] [blame]
/*
* 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.tools.idea.stats;
import com.android.prefs.AndroidLocation;
import com.android.prefs.AndroidLocation.AndroidLocationException;
import com.intellij.internal.statistic.StatisticsUploadAssistant;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Random;
/**
* Manages persistence settings for DDMS.
* <p/>
* For convenience, this also stores persistence settings related to the "server stats" ping
* as well as some ADT settings that are SDK specific but not workspace specific.
* <p/>
* This is mostly a copy of the tools/swt/sdkstats counterpart, adapted for compatibility with Studio.
*/
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_USED = "adtUsed"; //$NON-NLS-1$
private final static String LAST_SDK_PATH = "lastSdkPath"; //$NON-NLS-1$
/**
* PreferenceStore for DDMS.
* Creation and usage must be synchronized on {@code DdmsPreferenceStore.class}.
* 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 (DdmsPreferenceStore.class) {
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()) {
FileOutputStream fileOutputStream = null;
try {
PreferenceStore oldStore = new PreferenceStore(oldPrefPath);
oldStore.load();
fileOutputStream = new FileOutputStream(rcFileName);
oldStore.save(fileOutputStream, ""); //$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);
} finally {
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {
// pass
}
}
}
}
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 (DdmsPreferenceStore.class) {
try {
prefs.save();
} catch (IOException ioe) {
// FIXME com.android.dmmlib.Log.w("ddms", "Failed saving prefs file: " + ioe.getMessage());
}
}
}
// ---- Utility methods to access some specific 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 (DdmsPreferenceStore.class) {
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()}.
* <p/>
* There is no magic value reserved for "missing ping id or invalid store".
* The only proper way to know if the ping id is missing is to use {@link #hasPingId()}.
*/
public long getPingId() {
PreferenceStore prefs = getPreferenceStore();
synchronized (DdmsPreferenceStore.class) {
// Note: getLong() returns 0L if the ID is missing so we do that too when
// there's no store.
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();
synchronized (DdmsPreferenceStore.class) {
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() {
// In the context of Studio, this checks whether the user approved to send stats
// from the settings > stats panel. The whole stats code will only be invoked
// if this is true, so it's almost certain this will return true.
if (StatisticsUploadAssistant.isSendAllowed()) {
return true;
}
// Legacy code from ADT/ddms. This won't be used here. Keep for reference.
PreferenceStore prefs = getPreferenceStore();
synchronized (DdmsPreferenceStore.class) {
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 (DdmsPreferenceStore.class) {
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 (DdmsPreferenceStore.class) {
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 special 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 (DdmsPreferenceStore.class) {
prefs.setValue(timePref, timeStamp);
try {
prefs.save();
} catch (IOException ioe) {
/* ignore exceptions while saving preferences */
}
}
}
/**
* True if this is the first time the users runs ADT, which is detected by
* the lack of the setting set using {@link #setAdtUsed(boolean)}
* or this value being set to true.
*
* @return true if ADT has been used before
* @see #setAdtUsed(boolean)
*/
public boolean isAdtUsed() {
PreferenceStore prefs = getPreferenceStore();
synchronized (DdmsPreferenceStore.class) {
if (prefs == null || !prefs.contains(ADT_USED)) {
return false;
}
return prefs.getBoolean(ADT_USED);
}
}
/**
* Sets whether the ADT startup wizard has been shown.
* ADT sets first to false once the welcome wizard has been shown once.
*
* @param used true if ADT has been used
*/
public void setAdtUsed(boolean used) {
PreferenceStore prefs = getPreferenceStore();
synchronized (DdmsPreferenceStore.class) {
prefs.setValue(ADT_USED, used);
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 (DdmsPreferenceStore.class) {
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 (DdmsPreferenceStore.class) {
prefs.setValue(LAST_SDK_PATH, osSdkPath);
try {
prefs.save();
} catch (IOException ioe) {
/* ignore exceptions while saving preferences */
}
}
}
}