AbstractPreferences.java revision e810d3b49631329b11440aa5b7a54db181d42ed1
1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  this work for additional information regarding copyright ownership.
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  the License.  You may obtain a copy of the License at
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  See the License for the specific language governing permissions and
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  limitations under the License.
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage java.util.prefs;
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException;
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.OutputStream;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.UnsupportedEncodingException;
23e810d3b49631329b11440aa5b7a54db181d42ed1Elliott Hughesimport java.nio.charset.Charsets;
245cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilsonimport java.util.Collection;
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.EventListener;
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.EventObject;
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.HashMap;
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Iterator;
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.LinkedList;
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.List;
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Map;
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.TreeSet;
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.apache.harmony.luni.util.Base64;
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * This abstract class is a partial implementation of the abstract class
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Preferences, which can be used to simplify {@code Preferences} provider's
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * implementation. This class defines nine abstract SPI methods, which must be
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * implemented by a preference provider.
415cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson *
425cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson * @since 1.4
435cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson * @see Preferences
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic abstract class AbstractPreferences extends Preferences {
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * -----------------------------------------------------------
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Class fields
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * -----------------------------------------------------------
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
515cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson    /** the unhandled events collection */
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final List<EventObject> events = new LinkedList<EventObject>();
535cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson    /** the event dispatcher thread */
5403c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes    private static final EventDispatcher dispatcher = new EventDispatcher("Preference Event Dispatcher");
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * -----------------------------------------------------------
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Class initializer
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * -----------------------------------------------------------
60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    static {
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        dispatcher.setDaemon(true);
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        dispatcher.start();
64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Runtime.getRuntime().addShutdownHook(new Thread() {
65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            @Override
66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            public void run() {
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                Preferences uroot = Preferences.userRoot();
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                Preferences sroot = Preferences.systemRoot();
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                try {
70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    uroot.flush();
715cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson                } catch (BackingStoreException e) {
725cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson                    // ignore
73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                try {
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    sroot.flush();
765cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson                } catch (BackingStoreException e) {
775cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson                    // ignore
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        });
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
82f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * -----------------------------------------------------------
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Instance fields (package-private)
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * -----------------------------------------------------------
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
885cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson    /** true if this node is in user preference hierarchy */
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    boolean userNode;
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * -----------------------------------------------------------
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Instance fields (private)
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * -----------------------------------------------------------
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
965cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson    /** Marker class for 'lock' field. */
975cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson    private static class Lock {}
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The object used to lock this node.
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected final Object lock;
103f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This field is true if this node is created while it doesn't exist in the
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * backing store. This field's default value is false, and it is checked
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * when the node creation is completed, and if it is true, the node change
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * event will be fired for this node's parent.
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected boolean newNode;
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1125cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson    /** cached child nodes */
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private Map<String, AbstractPreferences> cachedNode;
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    //the collections of listeners
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private List<EventListener> nodeChangeListeners;
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private List<EventListener> preferenceChangeListeners;
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    //this node's name
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private String nodeName;
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    //handler to this node's parent
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private AbstractPreferences parentPref;
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    //true if this node has been removed
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private boolean isRemoved;
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    //handler to this node's root node
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private AbstractPreferences root;
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * -----------------------------------------------------------
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Constructors
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * -----------------------------------------------------------
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1375cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     * Constructs a new {@code AbstractPreferences} instance using the given
1385cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     * parent node and node name.
1395cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     *
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param parent
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the parent node of the new node or {@code null} to indicate
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            that the new node is a root node.
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param name
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the name of the new node or an empty string to indicate that
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            this node is called "root".
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the name contains a slash character or is empty if {@code
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             parent} is not {@code null}.
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected AbstractPreferences(AbstractPreferences parent, String name) {
15103c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes        if ((null == parent ^ name.length() == 0) || name.indexOf("/") >= 0) {
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException();
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        root = null == parent ? this : parent.root;
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        nodeChangeListeners = new LinkedList<EventListener>();
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        preferenceChangeListeners = new LinkedList<EventListener>();
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        isRemoved = false;
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        cachedNode = new HashMap<String, AbstractPreferences>();
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        nodeName = name;
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        parentPref = parent;
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        lock = new Lock();
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        userNode = root.userNode;
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * -----------------------------------------------------------
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Methods
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * -----------------------------------------------------------
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns an array of all cached child nodes.
172f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the array of cached child nodes.
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected final AbstractPreferences[] cachedChildren() {
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return cachedNode.values().toArray(new AbstractPreferences[cachedNode.size()]);
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the child node with the specified name or {@code null} if it
1815cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     * doesn't exist. Implementers can assume that the name supplied to this
1825cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     * method will be a valid node name string (conforming to the node naming
1835cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     * format) and will not correspond to a node that has been cached or
1845cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     * removed.
185f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param name
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the name of the desired child node.
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the child node with the given name or {@code null} if it doesn't
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         exist.
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws BackingStoreException
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the backing store is unavailable or causes an operation
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             failure.
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected AbstractPreferences getChild(String name)
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws BackingStoreException {
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (lock) {
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            checkState();
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            AbstractPreferences result = null;
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String[] childrenNames = childrenNames();
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            for (int i = 0; i < childrenNames.length; i++) {
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (childrenNames[i].equals(name)) {
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    result = childSpi(name);
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    break;
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return result;
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns whether this node has been removed by invoking the method {@code
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * removeNode()}.
2145cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     *
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return {@code true}, if this node has been removed, {@code false}
216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         otherwise.
217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected boolean isRemoved() {
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (lock) {
220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return isRemoved;
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
223adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Flushes changes of this node to the backing store. This method should
226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * only flush this node and should not include the descendant nodes. Any
2275cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     * implementation that wants to provide functionality to flush all nodes
228adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * at once should override the method {@link #flush() flush()}.
2295cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     *
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws BackingStoreException
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the backing store is unavailable or causes an operation
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             failure.
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected abstract void flushSpi() throws BackingStoreException;
235f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
2375cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     * Returns the names of all of the child nodes of this node or an empty
2385cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     * array if this node has no children. The names of cached children are not
2395cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     * required to be returned.
2405cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     *
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the names of this node's children.
242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws BackingStoreException
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the backing store is unavailable or causes an operation
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             failure.
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected abstract String[] childrenNamesSpi() throws BackingStoreException;
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the child preference node with the given name, creating it
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * if it does not exist. The caller of this method should ensure that the
2515cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     * given name is valid and that this node has not been removed or cached.
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * If the named node has just been removed, the implementation
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * of this method must create a new one instead of reactivating the removed
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * one.
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The new creation is not required to be persisted immediately until the
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * flush method will be invoked.
258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * </p>
259f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param name
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the name of the child preference to be returned.
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the child preference node.
263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected abstract AbstractPreferences childSpi(String name);
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Puts the given key-value pair into this node. Caller of this method
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * should ensure that both of the given values are valid and that this
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * node has not been removed.
2715cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     *
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param name
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the given preference key.
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param value
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the given preference value.
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected abstract void putSpi(String name, String value);
278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
2805cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     * Gets the preference value mapped to the given key. The caller of this
2815cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     * method should ensure that the given key is valid and that this node has
2825cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     * not been removed. This method should not throw any exceptions but if it
2835cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     * does, the caller will ignore the exception, regarding it as a {@code
2845cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     * null} return value.
2855cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     *
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param key
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the given key to be searched for.
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the preference value mapped to the given key.
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected abstract String getSpi(String key);
291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
292adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns an array of all preference keys of this node or an empty array if
2955cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     * no preferences have been found. The caller of this method should ensure
2965cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     * that this node has not been removed.
2975cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     *
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the array of all preference keys.
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws BackingStoreException
300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the backing store is unavailable or causes an operation
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             failure.
302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
303adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected abstract String[] keysSpi() throws BackingStoreException;
304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
305adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Removes this node from the preference hierarchy tree. The caller of this
307adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * method should ensure that this node has no child nodes, which means the
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * method {@link Preferences#removeNode() Preferences.removeNode()} should
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * invoke this method multiple-times in bottom-up pattern. The removal is
310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * not required to be persisted until after it is flushed.
3115cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     *
312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws BackingStoreException
313adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the backing store is unavailable or causes an operation
314adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             failure.
315adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected abstract void removeNodeSpi() throws BackingStoreException;
317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
318adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
319adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Removes the preference with the specified key. The caller of this method
320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * should ensure that the given key is valid and that this node has not been
321adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * removed.
322f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
323adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param key
324adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the key of the preference that is to be removed.
325adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
326adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected abstract void removeSpi(String key);
327adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
328adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
329adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Synchronizes this node with the backing store. This method should only
330adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * synchronize this node and should not include the descendant nodes. An
3315cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     * implementation that wants to provide functionality to synchronize all
3325cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson     * nodes at once should override the method {@link #sync() sync()}.
333f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
334adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws BackingStoreException
335adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the backing store is unavailable or causes an operation
336adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             failure.
337adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
338adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected abstract void syncSpi() throws BackingStoreException;
339adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
340adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
341adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * -----------------------------------------------------------
342adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Methods inherited from Preferences
343adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * -----------------------------------------------------------
344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
345adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
346adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String absolutePath() {
347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (parentPref == null) {
34803c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            return "/";
349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else if (parentPref == root) {
35003c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            return "/" + nodeName;
351adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
35203c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes        return parentPref.absolutePath() + "/" + nodeName;
353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
355adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String[] childrenNames() throws BackingStoreException {
357adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (lock) {
358adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            checkState();
359adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            TreeSet<String> result = new TreeSet<String>(cachedNode.keySet());
360adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String[] names = childrenNamesSpi();
361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            for (int i = 0; i < names.length; i++) {
362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                result.add(names[i]);
363adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
3645cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson            return result.toArray(new String[result.size()]);
365adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
366adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
367adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
368adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
369adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void clear() throws BackingStoreException {
370adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (lock) {
371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String[] keyList = keys();
372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            for (int i = 0; i < keyList.length; i++) {
373adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                remove(keyList[i]);
374adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
375adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
376adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
377adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
378adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
37903c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes    public void exportNode(OutputStream ostream) throws IOException, BackingStoreException {
38003c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes        if (ostream == null) {
38103c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            throw new NullPointerException("Stream is null");
382adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
383adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        checkState();
384adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        XMLParser.exportPrefs(this, ostream, false);
385adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
386adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
387adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
38803c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes    public void exportSubtree(OutputStream ostream) throws IOException, BackingStoreException {
38903c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes        if (ostream == null) {
39003c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            throw new NullPointerException("Stream is null");
391adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
392adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        checkState();
393adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        XMLParser.exportPrefs(this, ostream, true);
394adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
395adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
396adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
397adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void flush() throws BackingStoreException {
398adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (lock) {
399adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            flushSpi();
400adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
401adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        AbstractPreferences[] cc = cachedChildren();
402adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int i;
403adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        for (i = 0; i < cc.length; i++) {
404adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            cc[i].flush();
405adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
406adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
407adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
408adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
409adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String get(String key, String deflt) {
410adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (key == null) {
411adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new NullPointerException();
412adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
4135cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson        String result = null;
414adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (lock) {
415adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            checkState();
416adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
417adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                result = getSpi(key);
418adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } catch (Exception e) {
4195cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson                // ignored
420adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
421adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
422adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return (result == null ? deflt : result);
423adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
424adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
425adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
426adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean getBoolean(String key, boolean deflt) {
427adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String result = get(key, null);
428adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (result == null) {
429adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return deflt;
4305cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson        }
43103c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes        if ("true".equalsIgnoreCase(result)) {
432adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return true;
43303c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes        } else if ("false".equalsIgnoreCase(result)) {
434adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return false;
435adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
436adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return deflt;
437adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
438adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
439adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
440adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
441adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public byte[] getByteArray(String key, byte[] deflt) {
442adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String svalue = get(key, null);
443adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (svalue == null) {
444adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return deflt;
445adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
446f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        if (svalue.length() == 0) {
447adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return new byte[0];
448adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
449adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
450e810d3b49631329b11440aa5b7a54db181d42ed1Elliott Hughes            byte[] bavalue = svalue.getBytes(Charsets.US_ASCII);
451adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (bavalue.length % 4 != 0) {
452adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return deflt;
453adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
4545cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson            return Base64.decode(bavalue);
455adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (Exception e) {
4565cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson            return deflt;
457adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
458adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
459adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
460adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
461adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public double getDouble(String key, double deflt) {
462adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String result = get(key, null);
463adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (result == null) {
464adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return deflt;
465adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
466adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
4675cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson            return Double.parseDouble(result);
468adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (NumberFormatException e) {
4695cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson            return deflt;
470adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
471adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
472adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
473adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
474adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public float getFloat(String key, float deflt) {
475adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String result = get(key, null);
476adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (result == null) {
477adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return deflt;
478adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
479adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
4805cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson            return Float.parseFloat(result);
481adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (NumberFormatException e) {
4825cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson            return deflt;
483adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
484adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
485adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
486adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
487adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public int getInt(String key, int deflt) {
488adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String result = get(key, null);
489adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (result == null) {
490adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return deflt;
491adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
492adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
4935cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson            return Integer.parseInt(result);
494adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (NumberFormatException e) {
4955cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson            return deflt;
496adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
497adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
498adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
499adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
500adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public long getLong(String key, long deflt) {
501adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String result = get(key, null);
502adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (result == null) {
503adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return deflt;
504adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
505adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
5065cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson            return Long.parseLong(result);
507adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (NumberFormatException e) {
5085cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson            return deflt;
509adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
510adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
511adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
512adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
513adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean isUserNode() {
514adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return root == Preferences.userRoot();
515adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
516adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
517adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
518adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String[] keys() throws BackingStoreException {
519adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (lock) {
520adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            checkState();
521adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return keysSpi();
522adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
523adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
524adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
525adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
526adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String name() {
527adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return nodeName;
528adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
529adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
530adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
531adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Preferences node(String name) {
532adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        AbstractPreferences startNode = null;
533adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (lock) {
534adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            checkState();
535adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            validateName(name);
53680a7fbab52b96c9fd47c72f8987d1babe2cd001dElliott Hughes            if (name.isEmpty()) {
537adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return this;
53803c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            } else if ("/".equals(name)) {
539adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return root;
540adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
54103c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            if (name.startsWith("/")) {
542adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                startNode = root;
543adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                name = name.substring(1);
544adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
545adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                startNode = this;
546adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
547adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
548adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
5495cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson            return startNode.nodeImpl(name, true);
550adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (BackingStoreException e) {
5515cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson            // should not happen
5525cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson            return null;
553adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
554adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
555adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
556adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void validateName(String name) {
55703c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes        if (name.endsWith("/") && name.length() > 1) {
55803c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            throw new IllegalArgumentException("Name cannot end with '/'");
559adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
56003c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes        if (name.indexOf("//") >= 0) {
56103c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            throw new IllegalArgumentException("Name cannot contain consecutive '/' characters");
562adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
563adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
564adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
565adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private AbstractPreferences nodeImpl(String path, boolean createNew)
566adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws BackingStoreException {
567fd6bb3510c2f94d636f3572dcf5f7f4dcd1a2726Elliott Hughes        String[] names = path.split("/");
568adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        AbstractPreferences currentNode = this;
569adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        AbstractPreferences temp = null;
5705cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson        if (null != currentNode) {
5715cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson            for (int i = 0; i < names.length; i++) {
5725cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson                String name = names[i];
5735cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson                synchronized (currentNode.lock) {
5745cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson                    temp = currentNode.cachedNode.get(name);
5755cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson                    if (temp == null) {
5765cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson                        temp = getNodeFromBackend(createNew, currentNode, name);
5775cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson                    }
5785cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson                }
5795cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson                currentNode = temp;
5805cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson                if (null == currentNode) {
5815cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson                    break;
582adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
583adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
584adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
585adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return currentNode;
586adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
587adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
588adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private AbstractPreferences getNodeFromBackend(boolean createNew,
58903c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            AbstractPreferences currentNode, String name) throws BackingStoreException {
590adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (name.length() > MAX_NAME_LENGTH) {
59103c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            throw new IllegalArgumentException("Name '" + name + "' too long");
592adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
5935cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson        AbstractPreferences temp;
594adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (createNew) {
595adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            temp = currentNode.childSpi(name);
596adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            currentNode.cachedNode.put(name, temp);
597adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (temp.newNode && currentNode.nodeChangeListeners.size() > 0) {
598adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                currentNode.notifyChildAdded(temp);
599adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
600adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
601adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            temp = currentNode.getChild(name);
602adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
603adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return temp;
604adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
605adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
606adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
607adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean nodeExists(String name) throws BackingStoreException {
6085cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson        if (null == name) {
6095cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson            throw new NullPointerException();
6105cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson        }
611adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        AbstractPreferences startNode = null;
612adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (lock) {
613adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (isRemoved()) {
61403c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes                if (name.isEmpty()) {
615adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    return false;
616adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
61703c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes                throw new IllegalStateException("This node has been removed");
618adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
619adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            validateName(name);
62003c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            if (name.isEmpty() || "/".equals(name)) {
621adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return true;
622adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
62303c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            if (name.startsWith("/")) {
624adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                startNode = root;
625adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                name = name.substring(1);
626adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
627adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                startNode = this;
628adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
629adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
630adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
631adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Preferences result = startNode.nodeImpl(name, false);
632adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null == result ? false : true;
633adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch(IllegalArgumentException e) {
634adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return false;
635adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
636adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
637adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
638adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
639adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Preferences parent() {
640adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        checkState();
641adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return parentPref;
642adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
643adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
644adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void checkState() {
645adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (isRemoved()) {
64603c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            throw new IllegalStateException("This node has been removed");
647adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
648adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
649adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
650adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
651adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void put(String key, String value) {
652adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (null == key || null == value) {
653adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new NullPointerException();
654adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
655adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (key.length() > MAX_KEY_LENGTH || value.length() > MAX_VALUE_LENGTH) {
656adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException();
657adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
658adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (lock) {
659adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            checkState();
660adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            putSpi(key, value);
661adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
662adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        notifyPreferenceChange(key, value);
663adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
664adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
665adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
666adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void putBoolean(String key, boolean value) {
667adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String sval = String.valueOf(value);
668adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        put(key, sval);
669adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
670adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
671adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
672adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void putByteArray(String key, byte[] value) {
673adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
67403c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            put(key, Base64.encode(value, "US-ASCII"));
675adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (UnsupportedEncodingException e) {
676adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new AssertionError(e);
677adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
678adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
679adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
680adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
681adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void putDouble(String key, double value) {
682adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String sval = Double.toString(value);
683adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        put(key, sval);
684adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
685adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
686adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
687adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void putFloat(String key, float value) {
688adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String sval = Float.toString(value);
689adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        put(key, sval);
690adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
691adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
692adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
693adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void putInt(String key, int value) {
694adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String sval = Integer.toString(value);
695adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        put(key, sval);
696adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
697adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
698adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
699adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void putLong(String key, long value) {
700adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String sval = Long.toString(value);
701adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        put(key, sval);
702adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
703adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
704adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
705adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void remove(String key) {
706adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (lock) {
707adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            checkState();
708adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            removeSpi(key);
709adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
710adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        notifyPreferenceChange(key, null);
711adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
712adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
713adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
714adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void removeNode() throws BackingStoreException {
715adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (root == this) {
71603c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            throw new UnsupportedOperationException("Cannot remove root node");
717adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
718adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (parentPref.lock) {
719adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            removeNodeImpl();
720adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
721adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
722adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
723adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void removeNodeImpl() throws BackingStoreException {
724adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (lock) {
725adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            checkState();
726adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String[] childrenNames = childrenNamesSpi();
727adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            for (int i = 0; i < childrenNames.length; i++) {
728adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (null == cachedNode.get(childrenNames[i])) {
729adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    AbstractPreferences child = childSpi(childrenNames[i]);
730adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    cachedNode.put(childrenNames[i], child);
731adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
732adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
733f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
7345cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson            final Collection<AbstractPreferences> values = cachedNode.values();
7355cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson            final AbstractPreferences[] children = values.toArray(new AbstractPreferences[values.size()]);
7365cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson            for (AbstractPreferences child : children) {
7375cc8cb84ac4a3474cfb666c9b94fd721e4615ca0Jesse Wilson                child.removeNodeImpl();
738adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
739adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            removeNodeSpi();
740adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            isRemoved = true;
741adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            parentPref.cachedNode.remove(nodeName);
742adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
743adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (parentPref.nodeChangeListeners.size() > 0) {
744adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            parentPref.notifyChildRemoved(this);
745adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
746adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
747adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
748adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
749adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void addNodeChangeListener(NodeChangeListener ncl) {
750adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (null == ncl) {
751adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new NullPointerException();
752adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
753adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        checkState();
754adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (nodeChangeListeners) {
755adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            nodeChangeListeners.add(ncl);
756adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
757adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
758adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
759adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
760adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void addPreferenceChangeListener(PreferenceChangeListener pcl) {
761adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (null == pcl) {
762adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new NullPointerException();
763adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
764adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        checkState();
765adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (preferenceChangeListeners) {
766adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            preferenceChangeListeners.add(pcl);
767adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
768adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
769adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
770adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
771adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void removeNodeChangeListener(NodeChangeListener ncl) {
772adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        checkState();
773adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (nodeChangeListeners) {
774adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int pos;
775adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if ((pos = nodeChangeListeners.indexOf(ncl)) == -1) {
776adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new IllegalArgumentException();
777adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
778adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            nodeChangeListeners.remove(pos);
779adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
780adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
781adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
782adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
783adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void removePreferenceChangeListener(PreferenceChangeListener pcl) {
784adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        checkState();
785adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (preferenceChangeListeners) {
786adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int pos;
787adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if ((pos = preferenceChangeListeners.indexOf(pcl)) == -1) {
788adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new IllegalArgumentException();
789adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
790adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            preferenceChangeListeners.remove(pos);
791adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
792adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
793adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
794adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
795adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void sync() throws BackingStoreException {
796adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (lock) {
797adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            checkState();
798adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            syncSpi();
799adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
80003c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes        for (AbstractPreferences child : cachedChildren()) {
80103c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            child.sync();
802adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
803adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
804adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
805adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
806adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String toString() {
807adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        StringBuffer sb = new StringBuffer();
80803c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes        sb.append(isUserNode() ? "User" : "System");
80903c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes        sb.append(" Preference Node: ");
810adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        sb.append(absolutePath());
811adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return sb.toString();
812adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
813adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
814adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void notifyChildAdded(Preferences child) {
815adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        NodeChangeEvent nce = new NodeAddEvent(this, child);
816adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (events) {
817adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            events.add(nce);
818adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            events.notifyAll();
819adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
820adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
821adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
822adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void notifyChildRemoved(Preferences child) {
823adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        NodeChangeEvent nce = new NodeRemoveEvent(this, child);
824adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (events) {
825adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            events.add(nce);
826adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            events.notifyAll();
827adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
828adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
829adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
830adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void notifyPreferenceChange(String key, String newValue) {
83103c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes        PreferenceChangeEvent pce = new PreferenceChangeEvent(this, key, newValue);
832adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (events) {
833adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            events.add(pce);
834adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            events.notifyAll();
835adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
836adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
837adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
838adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static class EventDispatcher extends Thread {
839adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        EventDispatcher(String name){
840adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            super(name);
841adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
842f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
843adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
844adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public void run() {
845adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (true) {
846adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                EventObject event = null;
847adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                try {
848adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    event = getEventObject();
849adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } catch (InterruptedException e) {
850adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    e.printStackTrace();
851adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    continue;
852adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
853adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                AbstractPreferences pref = (AbstractPreferences) event
854adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        .getSource();
855adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (event instanceof NodeAddEvent) {
856adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    dispatchNodeAdd((NodeChangeEvent) event,
857adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            pref.nodeChangeListeners);
858adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } else if (event instanceof NodeRemoveEvent) {
859adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    dispatchNodeRemove((NodeChangeEvent) event,
860adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            pref.nodeChangeListeners);
861adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } else if (event instanceof PreferenceChangeEvent) {
862adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    dispatchPrefChange((PreferenceChangeEvent) event,
863adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            pref.preferenceChangeListeners);
864adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
865adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
866adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
867adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
868adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        private EventObject getEventObject() throws InterruptedException {
869adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            synchronized (events) {
870adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (events.isEmpty()) {
871adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    events.wait();
872adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
873adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                EventObject event = events.get(0);
874adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                events.remove(0);
875adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return event;
876adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
877adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
878adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
879adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        private void dispatchPrefChange(PreferenceChangeEvent event,
880adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                List<EventListener> preferenceChangeListeners) {
881adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            synchronized (preferenceChangeListeners) {
882adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                Iterator<EventListener> i = preferenceChangeListeners.iterator();
883adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                while (i.hasNext()) {
884adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    PreferenceChangeListener pcl = (PreferenceChangeListener) i
885adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            .next();
886adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    pcl.preferenceChange(event);
887adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
888adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
889adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
890adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
891adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        private void dispatchNodeRemove(NodeChangeEvent event,
892adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                List<EventListener> nodeChangeListeners) {
893adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            synchronized (nodeChangeListeners) {
894adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                Iterator<EventListener> i = nodeChangeListeners.iterator();
895adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                while (i.hasNext()) {
896adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    NodeChangeListener ncl = (NodeChangeListener) i.next();
897adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    ncl.childRemoved(event);
898adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
899adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
900adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
901adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
902adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        private void dispatchNodeAdd(NodeChangeEvent event,
903adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                List<EventListener> nodeChangeListeners) {
904adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            synchronized (nodeChangeListeners) {
905adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                Iterator<EventListener> i = nodeChangeListeners.iterator();
906adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                while (i.hasNext()) {
907adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    NodeChangeListener ncl = (NodeChangeListener) i.next();
908adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    ncl.childAdded(event);
909adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
910adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
911adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
912adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
913adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
914adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static class NodeAddEvent extends NodeChangeEvent {
915adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        //The base class is NOT serializable, so this class isn't either.
916adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        private static final long serialVersionUID = 1L;
917adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
918adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public NodeAddEvent(Preferences p, Preferences c) {
919adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            super(p, c);
920adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
921adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
922adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
923adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static class NodeRemoveEvent extends NodeChangeEvent {
924adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        //The base class is NOT serializable, so this class isn't either.
925adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        private static final long serialVersionUID = 1L;
926f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
927adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public NodeRemoveEvent(Preferences p, Preferences c) {
928adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            super(p, c);
929adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
930adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
931adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
932