12dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll/* 22dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * Copyright (C) 2012 The Android Open Source Project 32dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * 42dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * Licensed under the Apache License, Version 2.0 (the "License"); 52dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * you may not use this file except in compliance with the License. 62dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * You may obtain a copy of the License at 72dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * 82dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * http://www.apache.org/licenses/LICENSE-2.0 92dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * 102dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * Unless required by applicable law or agreed to in writing, software 112dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * distributed under the License is distributed on an "AS IS" BASIS, 122dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * See the License for the specific language governing permissions and 142dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * limitations under the License. 152dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll */ 162dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 172dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Mollpackage com.android.sdklib.internal.repository.sources; 182dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 192dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Mollimport com.android.annotations.NonNull; 202dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Mollimport com.android.annotations.Nullable; 212dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Mollimport com.android.annotations.VisibleForTesting; 222dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Mollimport com.android.annotations.VisibleForTesting.Visibility; 232dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Mollimport com.android.prefs.AndroidLocation; 242dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Mollimport com.android.prefs.AndroidLocation.AndroidLocationException; 252dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 262dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Mollimport java.io.File; 272dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Mollimport java.io.FileInputStream; 282dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Mollimport java.io.FileOutputStream; 292dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Mollimport java.io.IOException; 302dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Mollimport java.util.Collections; 312dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Mollimport java.util.Comparator; 322dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Mollimport java.util.List; 332dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Mollimport java.util.Properties; 342dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 352dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll/** 362dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * Properties for individual sources which are persisted by a local settings file. 372dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * <p/> 382dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * All instances of {@link SdkSourceProperties} share the same singleton storage. 392dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * The persisted setting file is loaded as necessary, however callers must persist 402dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * it at some point by calling {@link #save()}. 412dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll */ 422dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Mollpublic class SdkSourceProperties { 432dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 442dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll /** 452dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * An internal file version number, in case we want to change the format later. 462dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll */ 472dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll private static final String KEY_VERSION = "@version@"; //$NON-NLS-1$ 482dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll /** 492dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * The last known UI name of the source. 502dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll */ 512dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll public static final String KEY_NAME = "@name@"; //$NON-NLS-1$ 522dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll /** 532dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * A non-null string if the source is disabled. Null if the source is enabled. 542dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll */ 552dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll public static final String KEY_DISABLED = "@disabled@"; //$NON-NLS-1$ 562dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 572dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll private static final Properties sSourcesProperties = new Properties(); 582dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll private static final String SRC_FILENAME = "sites-settings.cfg"; //$NON-NLS-1$ 592dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 602dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll private static boolean sModified = false; 612dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 622dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll public SdkSourceProperties() { 632dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 642dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 652dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll public void save() { 662dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll synchronized (sSourcesProperties) { 672dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll if (sModified && !sSourcesProperties.isEmpty()) { 682dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll saveLocked(); 692dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll sModified = false; 702dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 712dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 722dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 732dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 742dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll /** 752dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * Retrieves a property for the given source URL and the given key type. 762dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * <p/> 772dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * Implementation detail: this loads the persistent settings file as needed. 782dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * 792dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * @param key The kind of property to retrieve for that source URL. 802dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * @param sourceUrl The source URL. 812dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * @param defaultValue The default value to return, if the property isn't found. Can be null. 822dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * @return The non-null string property for the key/sourceUrl or the default value. 832dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll */ 842dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll @Nullable 852dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll public String getProperty(@NonNull String key, 862dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll @NonNull String sourceUrl, 872dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll @Nullable String defaultValue) { 882dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll String value = defaultValue; 892dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 902dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll synchronized (sSourcesProperties) { 912dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll if (sSourcesProperties.isEmpty()) { 922dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll loadLocked(); 932dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 942dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 952dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll value = sSourcesProperties.getProperty(key + sourceUrl, defaultValue); 962dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 972dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 982dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll return value; 992dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 1002dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 1012dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll /** 1022dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * Sets or remove a property for the given source URL and the given key type. 1032dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * <p/> 1042dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * Implementation detail: this does <em>not</em> save the persistent settings file. 1052dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * Somehow the caller will need to call the {@link #save()} method later. 1062dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * 1072dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * @param key The kind of property to retrieve for that source URL. 1082dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * @param sourceUrl The source URL. 1092dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * @param value The new value to set (if non null) or null to remove an existing property. 1102dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll */ 1112dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll public void setProperty(String key, String sourceUrl, String value) { 1122dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll synchronized (sSourcesProperties) { 1132dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll if (sSourcesProperties.isEmpty()) { 1142dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll loadLocked(); 1152dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 1162dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 1172dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll key += sourceUrl; 1182dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 1192dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll String old = sSourcesProperties.getProperty(key); 1202dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll if (value == null) { 1212dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll if (old != null) { 1222dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll sSourcesProperties.remove(key); 1232dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll sModified = true; 1242dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 1252dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } else if (old == null || !old.equals(value)) { 1262dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll sSourcesProperties.setProperty(key, value); 1272dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll sModified = true; 1282dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 1292dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 1302dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 1312dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 1322dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll /** 1332dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * Returns an internal string representation of the underlying Properties map, 1342dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * sorted by ascending keys. Useful for debugging and testing purposes only. 1352dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll */ 1362dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll @Override 1372dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll public String toString() { 1382dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll StringBuilder sb = new StringBuilder("<SdkSourceProperties"); //$NON-NLS-1$ 1392dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll synchronized (sSourcesProperties) { 1402dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll List<Object> keys = Collections.list(sSourcesProperties.keys()); 1412dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll Collections.sort(keys, new Comparator<Object>() { 1422dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll @Override 1432dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll public int compare(Object o1, Object o2) { 1442dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll return o1.toString().compareTo(o2.toString()); 1452dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll }}); 1462dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 1472dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll for (Object key : keys) { 1482dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll sb.append('\n').append(key) 1492dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll .append(" = ").append(sSourcesProperties.get(key)); //$NON-NLS-1$ 1502dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 1512dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 1522dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll sb.append('>'); 1532dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll return sb.toString(); 1542dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 1552dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 1562dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll /** Load state from persistent file. Expects sSourcesProperties to be synchronized. */ 1572dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll private void loadLocked() { 1582dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll // Load state from persistent file 1592dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll if (loadProperties()) { 1602dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll // If it lacks our magic version key, don't use it 1612dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll if (sSourcesProperties.getProperty(KEY_VERSION) == null) { 1622dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll sSourcesProperties.clear(); 1632dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 1642dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 1652dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll sModified = false; 1662dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 1672dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 1682dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll if (sSourcesProperties.isEmpty()) { 1692dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll // Nothing was loaded. Initialize the storage with a version 1702dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll // identified. This isn't currently checked back, but we might 1712dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll // want it later if we decide to change the way this works. 1722dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll // The version key is choosen on purpose to not match any valid URL. 1732dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll sSourcesProperties.setProperty(KEY_VERSION, "1"); //$NON-NLS-1$ //$NON-NLS-2$ 1742dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 1752dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 1762dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 1772dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll /** 1782dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * Load properties from default file. Extracted so that it can be mocked in tests. 1792dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * 1802dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * @return True if actually loaded the file. False if there was an IO error or no 1812dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * file and nothing was loaded. 1822dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll */ 1832dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll @VisibleForTesting(visibility=Visibility.PRIVATE) 1842dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll protected boolean loadProperties() { 1852dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll try { 1862dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll String folder = AndroidLocation.getFolder(); 1872dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll File f = new File(folder, SRC_FILENAME); 1882dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll if (f.exists()) { 1892dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll FileInputStream fis = null; 1902dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll try { 1912dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll fis = new FileInputStream(f); 1922dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll sSourcesProperties.load(fis); 1932dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } catch (IOException ignore) { 1942dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll // nop 1952dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } finally { 1962dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll if (fis != null) { 1972dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll try { 1982dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll fis.close(); 1992dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } catch (IOException ignore) {} 2002dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 2012dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 2022dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 2032dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll return true; 2042dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 2052dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } catch (AndroidLocationException ignore) { 2062dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll // nop 2072dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 2082dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll return false; 2092dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 2102dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 2112dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll /** 2122dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * Save file to disk. Expects sSourcesProperties to be synchronized. 2132dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * Made accessible for testing purposes. 2142dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll * For public usage, please use {@link #save()} instead. 2152dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll */ 2162dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll @VisibleForTesting(visibility=Visibility.PRIVATE) 2172dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll protected void saveLocked() { 2182dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll // Persist it to the file 2192dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll FileOutputStream fos = null; 2202dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll try { 2212dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll String folder = AndroidLocation.getFolder(); 2222dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll File f = new File(folder, SRC_FILENAME); 2232dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 2242dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll fos = new FileOutputStream(f); 2252dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 2262dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll sSourcesProperties.store(fos,"## Sites Settings for Android SDK Manager");//$NON-NLS-1$ 2272dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 2282dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } catch (AndroidLocationException ignore) { 2292dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll // nop 2302dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } catch (IOException ignore) { 2312dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll // nop 2322dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } finally { 2332dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll if (fos != null) { 2342dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll try { 2352dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll fos.close(); 2362dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } catch (IOException ignore) {} 2372dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 2382dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 2392dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 2402dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll 2412dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll /** Empty current property list. Made accessible for testing purposes. */ 2422dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll @VisibleForTesting(visibility=Visibility.PRIVATE) 2432dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll protected void clear() { 2442dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll synchronized (sSourcesProperties) { 2452dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll sSourcesProperties.clear(); 2462dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll sModified = false; 2472dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 2482dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll } 2492dbb10456924ea2cbce7c4647881fd57f766c3aaRaphael Moll} 250