189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown/*
289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown * Copyright (C) 2012 The Android Open Source Project
389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown *
489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown * you may not use this file except in compliance with the License.
689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown * You may obtain a copy of the License at
789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown *
889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown *
1089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown * Unless required by applicable law or agreed to in writing, software
1189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
1289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown * See the License for the specific language governing permissions and
1489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown * limitations under the License.
1589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown */
1689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
1789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownpackage com.android.server.display;
1889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
1989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport com.android.internal.util.FastXmlSerializer;
2089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport com.android.internal.util.XmlUtils;
2189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
2289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport org.xmlpull.v1.XmlPullParser;
2389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport org.xmlpull.v1.XmlPullParserException;
2489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport org.xmlpull.v1.XmlSerializer;
2589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
2689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport android.hardware.display.WifiDisplay;
2789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport android.util.AtomicFile;
2889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport android.util.Slog;
2989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport android.util.Xml;
3089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
3189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport java.io.BufferedInputStream;
3289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport java.io.BufferedOutputStream;
3389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport java.io.File;
3489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport java.io.FileNotFoundException;
3589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport java.io.FileOutputStream;
3689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport java.io.IOException;
3789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport java.io.InputStream;
3889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport java.util.ArrayList;
3989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
4089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport libcore.io.IoUtils;
4189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport libcore.util.Objects;
4289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
4389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown/**
4489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown * Manages persistent state recorded by the display manager service as an XML file.
4589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown * Caller must acquire lock on the data store before accessing it.
4689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown *
4789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown * File format:
4889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown * <code>
4989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown * &lt;display-manager-state>
5089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown *   &lt;remembered-wifi-displays>
5189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown *     &lt;wifi-display deviceAddress="00:00:00:00:00:00" deviceName="XXXX" deviceAlias="YYYY" />
5289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown *   &gt;remembered-wifi-displays>
5389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown * &gt;/display-manager-state>
5489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown * </code>
5589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown *
5689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown * TODO: refactor this to extract common code shared with the input manager's data store
5789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown */
5889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownfinal class PersistentDataStore {
5989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    static final String TAG = "DisplayManager";
6089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
6189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    // Remembered Wifi display devices.
6289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private ArrayList<WifiDisplay> mRememberedWifiDisplays = new ArrayList<WifiDisplay>();
6389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
6489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    // The atomic file used to safely read or write the file.
6589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private final AtomicFile mAtomicFile;
6689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
6789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    // True if the data has been loaded.
6889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private boolean mLoaded;
6989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
7089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    // True if there are changes to be saved.
7189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private boolean mDirty;
7289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
7389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    public PersistentDataStore() {
7489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mAtomicFile = new AtomicFile(new File("/data/system/display-manager-state.xml"));
7589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
7689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
7789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    public void saveIfNeeded() {
7889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (mDirty) {
7989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            save();
8089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mDirty = false;
8189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
8289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
8389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
8474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    public WifiDisplay getRememberedWifiDisplay(String deviceAddress) {
8574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        loadIfNeeded();
8674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        int index = findRememberedWifiDisplay(deviceAddress);
8774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        if (index >= 0) {
8874da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            return mRememberedWifiDisplays.get(index);
8974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        }
9074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        return null;
9174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    }
9274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown
9389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    public WifiDisplay[] getRememberedWifiDisplays() {
9489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        loadIfNeeded();
9589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        return mRememberedWifiDisplays.toArray(new WifiDisplay[mRememberedWifiDisplays.size()]);
9689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
9789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
9889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    public WifiDisplay applyWifiDisplayAlias(WifiDisplay display) {
9989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (display != null) {
10089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            loadIfNeeded();
10189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
102c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            String alias = null;
10389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            int index = findRememberedWifiDisplay(display.getDeviceAddress());
10489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            if (index >= 0) {
105c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                alias = mRememberedWifiDisplays.get(index).getDeviceAlias();
106c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            }
107c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            if (!Objects.equal(display.getDeviceAlias(), alias)) {
10821f603996ed83c7a9a6c430582e8a5af5ac13c6cChong Zhang                return new WifiDisplay(display.getDeviceAddress(), display.getDeviceName(),
109ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                        alias, display.isAvailable(), display.canConnect(), display.isRemembered());
11089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            }
11189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
11289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        return display;
11389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
11489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
11589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    public WifiDisplay[] applyWifiDisplayAliases(WifiDisplay[] displays) {
11689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        WifiDisplay[] results = displays;
11789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (results != null) {
11889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            int count = displays.length;
11989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            for (int i = 0; i < count; i++) {
12089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                WifiDisplay result = applyWifiDisplayAlias(displays[i]);
12189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                if (result != displays[i]) {
12289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    if (results == displays) {
12389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        results = new WifiDisplay[count];
12489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        System.arraycopy(displays, 0, results, 0, count);
12589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    }
12689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    results[i] = result;
12789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                }
12889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            }
12989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
13089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        return results;
13189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
13289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
13389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    public boolean rememberWifiDisplay(WifiDisplay display) {
13489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        loadIfNeeded();
13589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
13689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        int index = findRememberedWifiDisplay(display.getDeviceAddress());
13789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (index >= 0) {
13889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            WifiDisplay other = mRememberedWifiDisplays.get(index);
13989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            if (other.equals(display)) {
14089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                return false; // already remembered without change
14189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            }
14289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mRememberedWifiDisplays.set(index, display);
14389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        } else {
14489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mRememberedWifiDisplays.add(display);
14589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
14689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        setDirty();
14789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        return true;
14889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
14989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
15089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    public boolean forgetWifiDisplay(String deviceAddress) {
15189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        int index = findRememberedWifiDisplay(deviceAddress);
15289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (index >= 0) {
15389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mRememberedWifiDisplays.remove(index);
15489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            setDirty();
15589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            return true;
15689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
15789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        return false;
15889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
15989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
16089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private int findRememberedWifiDisplay(String deviceAddress) {
16189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        int count = mRememberedWifiDisplays.size();
16289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        for (int i = 0; i < count; i++) {
16389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            if (mRememberedWifiDisplays.get(i).getDeviceAddress().equals(deviceAddress)) {
16489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                return i;
16589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            }
16689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
16789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        return -1;
16889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
16989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
17089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private void loadIfNeeded() {
17189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (!mLoaded) {
17289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            load();
17389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mLoaded = true;
17489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
17589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
17689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
17789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private void setDirty() {
17889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mDirty = true;
17989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
18089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
18189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private void clearState() {
18289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mRememberedWifiDisplays.clear();
18389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
18489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
18589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private void load() {
18689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        clearState();
18789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
18889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        final InputStream is;
18989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        try {
19089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            is = mAtomicFile.openRead();
19189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        } catch (FileNotFoundException ex) {
19289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            return;
19389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
19489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
19589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        XmlPullParser parser;
19689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        try {
19789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            parser = Xml.newPullParser();
19889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            parser.setInput(new BufferedInputStream(is), null);
19989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            loadFromXml(parser);
20089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        } catch (IOException ex) {
20189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            Slog.w(TAG, "Failed to load display manager persistent store data.", ex);
20289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            clearState();
20389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        } catch (XmlPullParserException ex) {
20489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            Slog.w(TAG, "Failed to load display manager persistent store data.", ex);
20589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            clearState();
20689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        } finally {
20789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            IoUtils.closeQuietly(is);
20889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
20989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
21089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
21189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private void save() {
21289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        final FileOutputStream os;
21389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        try {
21489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            os = mAtomicFile.startWrite();
21589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            boolean success = false;
21689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            try {
21789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                XmlSerializer serializer = new FastXmlSerializer();
21889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                serializer.setOutput(new BufferedOutputStream(os), "utf-8");
21989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                saveToXml(serializer);
22089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                serializer.flush();
22189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                success = true;
22289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            } finally {
22389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                if (success) {
22489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    mAtomicFile.finishWrite(os);
22589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                } else {
22689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    mAtomicFile.failWrite(os);
22789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                }
22889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            }
22989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        } catch (IOException ex) {
23089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            Slog.w(TAG, "Failed to save display manager persistent store data.", ex);
23189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
23289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
23389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
23489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private void loadFromXml(XmlPullParser parser)
23589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            throws IOException, XmlPullParserException {
23689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        XmlUtils.beginDocument(parser, "display-manager-state");
23789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        final int outerDepth = parser.getDepth();
23889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        while (XmlUtils.nextElementWithin(parser, outerDepth)) {
23989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            if (parser.getName().equals("remembered-wifi-displays")) {
24089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                loadRememberedWifiDisplaysFromXml(parser);
24189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            }
24289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
24389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
24489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
24589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private void loadRememberedWifiDisplaysFromXml(XmlPullParser parser)
24689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            throws IOException, XmlPullParserException {
24789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        final int outerDepth = parser.getDepth();
24889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        while (XmlUtils.nextElementWithin(parser, outerDepth)) {
24989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            if (parser.getName().equals("wifi-display")) {
25089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                String deviceAddress = parser.getAttributeValue(null, "deviceAddress");
25189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                String deviceName = parser.getAttributeValue(null, "deviceName");
25289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                String deviceAlias = parser.getAttributeValue(null, "deviceAlias");
25389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                if (deviceAddress == null || deviceName == null) {
25489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    throw new XmlPullParserException(
25589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                            "Missing deviceAddress or deviceName attribute on wifi-display.");
25689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                }
25789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                if (findRememberedWifiDisplay(deviceAddress) >= 0) {
25889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    throw new XmlPullParserException(
25989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                            "Found duplicate wifi display device address.");
26089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                }
26189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
26289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                mRememberedWifiDisplays.add(
263ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                        new WifiDisplay(deviceAddress, deviceName, deviceAlias,
264ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                                false, false, false));
26589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            }
26689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
26789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
26889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
26989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private void saveToXml(XmlSerializer serializer) throws IOException {
27089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        serializer.startDocument(null, true);
27189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
27289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        serializer.startTag(null, "display-manager-state");
27389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        serializer.startTag(null, "remembered-wifi-displays");
27489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        for (WifiDisplay display : mRememberedWifiDisplays) {
27589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            serializer.startTag(null, "wifi-display");
27689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            serializer.attribute(null, "deviceAddress", display.getDeviceAddress());
27789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            serializer.attribute(null, "deviceName", display.getDeviceName());
27889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            if (display.getDeviceAlias() != null) {
27989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                serializer.attribute(null, "deviceAlias", display.getDeviceAlias());
28089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            }
28189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            serializer.endTag(null, "wifi-display");
28289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
28389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        serializer.endTag(null, "remembered-wifi-displays");
28489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        serializer.endTag(null, "display-manager-state");
28589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        serializer.endDocument();
28689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
28789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown}