Home | History | Annotate | Download | only in sdkstats
      1 /*
      2  * Copyright (C) 2007 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 
     17 package com.android.sdkstats;
     18 
     19 import com.android.prefs.AndroidLocation;
     20 import com.android.prefs.AndroidLocation.AndroidLocationException;
     21 
     22 import org.eclipse.jface.preference.PreferenceStore;
     23 
     24 import java.io.File;
     25 import java.io.FileOutputStream;
     26 import java.io.IOException;
     27 import java.util.Random;
     28 
     29 /**
     30  * Manages persistence settings for DDMS.
     31  *
     32  * For convenience, this also stores persistence settings related to the "server stats" ping
     33  * as well as some ADT settings that are SDK specific but not workspace specific.
     34  */
     35 public class DdmsPreferenceStore {
     36 
     37     public  final static String PING_OPT_IN = "pingOptIn";          //$NON-NLS-1$
     38     private final static String PING_TIME   = "pingTime";           //$NON-NLS-1$
     39     private final static String PING_ID     = "pingId";             //$NON-NLS-1$
     40 
     41     private final static String ADT_USED = "adtUsed";               //$NON-NLS-1$
     42     private final static String LAST_SDK_PATH = "lastSdkPath";      //$NON-NLS-1$
     43 
     44     /**
     45      * PreferenceStore for DDMS.
     46      * Creation and usage must be synchronized on {@code DdmsPreferenceStore.class}.
     47      * Don't use it directly, instead retrieve it via {@link #getPreferenceStore()}.
     48      */
     49     private static volatile PreferenceStore sPrefStore;
     50 
     51     public DdmsPreferenceStore() {
     52     }
     53 
     54     /**
     55      * Returns the DDMS {@link PreferenceStore}.
     56      * This keeps a static reference on the store, so consequent calls will
     57      * return always the same store.
     58      */
     59     public PreferenceStore getPreferenceStore() {
     60         synchronized (DdmsPreferenceStore.class) {
     61             if (sPrefStore == null) {
     62                 // get the location of the preferences
     63                 String homeDir = null;
     64                 try {
     65                     homeDir = AndroidLocation.getFolder();
     66                 } catch (AndroidLocationException e1) {
     67                     // pass, we'll do a dummy store since homeDir is null
     68                 }
     69 
     70                 if (homeDir == null) {
     71                     sPrefStore = new PreferenceStore();
     72                     return sPrefStore;
     73                 }
     74 
     75                 assert homeDir != null;
     76 
     77                 String rcFileName = homeDir + "ddms.cfg";                       //$NON-NLS-1$
     78 
     79                 // also look for an old pref file in the previous location
     80                 String oldPrefPath = System.getProperty("user.home")            //$NON-NLS-1$
     81                     + File.separator + ".ddmsrc";                               //$NON-NLS-1$
     82                 File oldPrefFile = new File(oldPrefPath);
     83                 if (oldPrefFile.isFile()) {
     84                     try {
     85                         PreferenceStore oldStore = new PreferenceStore(oldPrefPath);
     86                         oldStore.load();
     87 
     88                         oldStore.save(new FileOutputStream(rcFileName), "");    //$NON-NLS-1$
     89                         oldPrefFile.delete();
     90 
     91                         PreferenceStore newStore = new PreferenceStore(rcFileName);
     92                         newStore.load();
     93                         sPrefStore = newStore;
     94                     } catch (IOException e) {
     95                         // create a new empty store.
     96                         sPrefStore = new PreferenceStore(rcFileName);
     97                     }
     98                 } else {
     99                     sPrefStore = new PreferenceStore(rcFileName);
    100 
    101                     try {
    102                         sPrefStore.load();
    103                     } catch (IOException e) {
    104                         System.err.println("Error Loading DDMS Preferences");
    105                     }
    106                 }
    107             }
    108 
    109             assert sPrefStore != null;
    110             return sPrefStore;
    111         }
    112     }
    113 
    114     /**
    115      * Save the prefs to the config file.
    116      */
    117     public void save() {
    118         PreferenceStore prefs = getPreferenceStore();
    119         synchronized (DdmsPreferenceStore.class) {
    120             try {
    121                 prefs.save();
    122             }
    123             catch (IOException ioe) {
    124                 // FIXME com.android.dmmlib.Log.w("ddms", "Failed saving prefs file: " + ioe.getMessage());
    125             }
    126         }
    127     }
    128 
    129     // ---- Utility methods to access some specific prefs ----
    130 
    131     /**
    132      * Indicates whether the ping ID is set.
    133      * This should be true when {@link #isPingOptIn()} is true.
    134      *
    135      * @return true if a ping ID is set, which means the user gave permission
    136      *              to use the ping service.
    137      */
    138     public boolean hasPingId() {
    139         PreferenceStore prefs = getPreferenceStore();
    140         synchronized (DdmsPreferenceStore.class) {
    141             return prefs != null && prefs.contains(PING_ID);
    142         }
    143     }
    144 
    145     /**
    146      * Retrieves the current ping ID, if set.
    147      * To know if the ping ID is set, use {@link #hasPingId()}.
    148      * <p/>
    149      * There is no magic value reserved for "missing ping id or invalid store".
    150      * The only proper way to know if the ping id is missing is to use {@link #hasPingId()}.
    151      */
    152     public long getPingId() {
    153         PreferenceStore prefs = getPreferenceStore();
    154         synchronized (DdmsPreferenceStore.class) {
    155             // Note: getLong() returns 0L if the ID is missing so we do that too when
    156             // there's no store.
    157             return prefs == null ? 0L : prefs.getLong(PING_ID);
    158         }
    159     }
    160 
    161     /**
    162      * Generates a new random ping ID and saves it in the preference store.
    163      *
    164      * @return The new ping ID.
    165      */
    166     public long generateNewPingId() {
    167         PreferenceStore prefs = getPreferenceStore();
    168 
    169         Random rnd = new Random();
    170         long id = rnd.nextLong();
    171 
    172         synchronized (DdmsPreferenceStore.class) {
    173             prefs.setValue(PING_ID, id);
    174             try {
    175                 prefs.save();
    176             } catch (IOException e) {
    177                 /* ignore exceptions while saving preferences */
    178             }
    179         }
    180 
    181         return id;
    182     }
    183 
    184     /**
    185      * Returns the "ping opt in" value from the preference store.
    186      * This would be true if there's a valid preference store and
    187      * the user opted for sending ping statistics.
    188      */
    189     public boolean isPingOptIn() {
    190         PreferenceStore prefs = getPreferenceStore();
    191         synchronized (DdmsPreferenceStore.class) {
    192             return prefs != null && prefs.contains(PING_OPT_IN);
    193         }
    194     }
    195 
    196     /**
    197      * Saves the "ping opt in" value in the preference store.
    198      *
    199      * @param optIn The new user opt-in value.
    200      */
    201     public void setPingOptIn(boolean optIn) {
    202         PreferenceStore prefs = getPreferenceStore();
    203 
    204         synchronized (DdmsPreferenceStore.class) {
    205             prefs.setValue(PING_OPT_IN, optIn);
    206             try {
    207                 prefs.save();
    208             } catch (IOException e) {
    209                 /* ignore exceptions while saving preferences */
    210             }
    211         }
    212     }
    213 
    214     /**
    215      * Retrieves the ping time for the given app from the preference store.
    216      * Callers should use {@link System#currentTimeMillis()} for time stamps.
    217      *
    218      * @param app The app name identifier.
    219      * @return 0L if we don't have a preference store or there was no time
    220      *  recorded in the store for the requested app. Otherwise the time stamp
    221      *  from the store.
    222      */
    223     public long getPingTime(String app) {
    224         PreferenceStore prefs = getPreferenceStore();
    225         String timePref = PING_TIME + "." + app;  //$NON-NLS-1$
    226         synchronized (DdmsPreferenceStore.class) {
    227             return prefs == null ? 0 : prefs.getLong(timePref);
    228         }
    229     }
    230 
    231     /**
    232      * Sets the ping time for the given app from the preference store.
    233      * Callers should use {@link System#currentTimeMillis()} for time stamps.
    234      *
    235      * @param app The app name identifier.
    236      * @param timeStamp The time stamp from the store.
    237      *                   0L is a special value that should not be used.
    238      */
    239     public void setPingTime(String app, long timeStamp) {
    240         PreferenceStore prefs = getPreferenceStore();
    241         String timePref = PING_TIME + "." + app;  //$NON-NLS-1$
    242         synchronized (DdmsPreferenceStore.class) {
    243             prefs.setValue(timePref, timeStamp);
    244             try {
    245                 prefs.save();
    246             } catch (IOException ioe) {
    247                 /* ignore exceptions while saving preferences */
    248             }
    249         }
    250     }
    251 
    252     /**
    253      * True if this is the first time the users runs ADT, which is detected by
    254      * the lack of the setting set using {@link #setAdtUsed(boolean)}
    255      * or this value being set to true.
    256      *
    257      * @return true if ADT has been used  before
    258      *
    259      * @see #setAdtUsed(boolean)
    260      */
    261     public boolean isAdtUsed() {
    262         PreferenceStore prefs = getPreferenceStore();
    263         synchronized (DdmsPreferenceStore.class) {
    264             if (prefs == null || !prefs.contains(ADT_USED)) {
    265                 return false;
    266             }
    267             return prefs.getBoolean(ADT_USED);
    268         }
    269     }
    270 
    271     /**
    272      * Sets whether the ADT startup wizard has been shown.
    273      * ADT sets first to false once the welcome wizard has been shown once.
    274      *
    275      * @param used true if ADT has been used
    276      */
    277     public void setAdtUsed(boolean used) {
    278         PreferenceStore prefs = getPreferenceStore();
    279         synchronized (DdmsPreferenceStore.class) {
    280             prefs.setValue(ADT_USED, used);
    281             try {
    282                 prefs.save();
    283             } catch (IOException ioe) {
    284                 /* ignore exceptions while saving preferences */
    285             }
    286         }
    287     }
    288 
    289     /**
    290      * Retrieves the last SDK OS path.
    291      * <p/>
    292      * This is just an information value, the path may not exist, may not
    293      * even be on an existing file system and/or may not point to an SDK
    294      * anymore.
    295      *
    296      * @return The last SDK OS path from the preference store, or null if
    297      *  there is no store or an empty string if it is not defined.
    298      */
    299     public String getLastSdkPath() {
    300         PreferenceStore prefs = getPreferenceStore();
    301         synchronized (DdmsPreferenceStore.class) {
    302             return prefs == null ? null : prefs.getString(LAST_SDK_PATH);
    303         }
    304     }
    305 
    306     /**
    307      * Sets the last SDK OS path.
    308      *
    309      * @param osSdkPath The SDK OS Path. Can be null or empty.
    310      */
    311     public void setLastSdkPath(String osSdkPath) {
    312         PreferenceStore prefs = getPreferenceStore();
    313         synchronized (DdmsPreferenceStore.class) {
    314             prefs.setValue(LAST_SDK_PATH, osSdkPath);
    315             try {
    316                 prefs.save();
    317             } catch (IOException ioe) {
    318                 /* ignore exceptions while saving preferences */
    319             }
    320         }
    321     }
    322 }
    323