| /* |
| * 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; |
| |
| /** |
| * Manages persistence settings for DDMS. |
| * |
| * 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. |
| */ |
| 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() { |
| 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 */ |
| } |
| } |
| } |
| } |