1b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey/*
2b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey * Copyright (C) 2013 The Android Open Source Project
3b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey *
4b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License");
5b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey * you may not use this file except in compliance with the License.
6b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey * You may obtain a copy of the License at
7b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey *
8b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey *      http://www.apache.org/licenses/LICENSE-2.0
9b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey *
10b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey * Unless required by applicable law or agreed to in writing, software
11b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS,
12b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey * See the License for the specific language governing permissions and
14b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey * limitations under the License.
15b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey */
16b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
17b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeypackage com.android.documentsui.model;
18b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
19deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkeyimport android.content.ContentResolver;
20deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkeyimport android.provider.DocumentsProvider;
21deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey
22b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkeyimport java.io.DataInputStream;
23b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkeyimport java.io.DataOutputStream;
24deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkeyimport java.io.FileNotFoundException;
25b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkeyimport java.io.IOException;
26b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkeyimport java.net.ProtocolException;
27deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkeyimport java.util.Collection;
28b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport java.util.LinkedList;
29b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
30b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey/**
31ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * Representation of a stack of {@link DocumentInfo}, usually the result of a
32b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey * user-driven traversal.
33b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey */
34b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkeypublic class DocumentStack extends LinkedList<DocumentInfo> implements Durable {
35b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    private static final int VERSION_INIT = 1;
36d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey    private static final int VERSION_ADD_ROOT = 2;
37aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
38d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey    public RootInfo root;
39aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
40d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey    public String getTitle() {
41d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        if (size() == 1 && root != null) {
42d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey            return root.title;
43aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        } else if (size() > 1) {
44aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            return peek().displayName;
45aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        } else {
46aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            return null;
47aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        }
48aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
49b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey
50ded77187ef53341765fcab8e29cda94810fc2ca5Jeff Sharkey    public boolean isRecents() {
51ded77187ef53341765fcab8e29cda94810fc2ca5Jeff Sharkey        return size() == 0;
52ded77187ef53341765fcab8e29cda94810fc2ca5Jeff Sharkey    }
53ded77187ef53341765fcab8e29cda94810fc2ca5Jeff Sharkey
54deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey    public void updateRoot(Collection<RootInfo> matchingRoots) throws FileNotFoundException {
55deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        for (RootInfo root : matchingRoots) {
56deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey            if (root.equals(this.root)) {
57deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey                this.root = root;
58deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey                return;
59deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey            }
60deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        }
61deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        throw new FileNotFoundException("Failed to find matching root for " + root);
62deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey    }
63deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey
64deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey    /**
65deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey     * Update a possibly stale restored stack against a live
66deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey     * {@link DocumentsProvider}.
67deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey     */
68deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey    public void updateDocuments(ContentResolver resolver) throws FileNotFoundException {
69deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        for (DocumentInfo info : this) {
70deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey            info.updateSelf(resolver);
71deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        }
72deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey    }
73deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey
746efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey    /**
756efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey     * Build key that uniquely identifies this stack. It omits most of the raw
766efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey     * details included in {@link #write(DataOutputStream)}, since they change
776efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey     * too regularly to be used as a key.
786efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey     */
796efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey    public String buildKey() {
806efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        final StringBuilder builder = new StringBuilder();
816efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        if (root != null) {
826efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            builder.append(root.authority).append('#');
836efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            builder.append(root.rootId).append('#');
846efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        } else {
856efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            builder.append("[null]").append('#');
866efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        }
876efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        for (DocumentInfo doc : this) {
886efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            builder.append(doc.documentId).append('#');
896efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        }
906efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        return builder.toString();
916efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey    }
926efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey
93b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    @Override
94b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    public void reset() {
95b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        clear();
96d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        root = null;
97b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    }
98b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey
99b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    @Override
100b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    public void read(DataInputStream in) throws IOException {
101b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        final int version = in.readInt();
102b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        switch (version) {
103b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey            case VERSION_INIT:
104d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey                throw new ProtocolException("Ignored upgrade");
105d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey            case VERSION_ADD_ROOT:
106d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey                if (in.readBoolean()) {
107d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey                    root = new RootInfo();
108d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey                    root.read(in);
109d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey                }
110b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey                final int size = in.readInt();
111b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey                for (int i = 0; i < size; i++) {
112b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey                    final DocumentInfo doc = new DocumentInfo();
113b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey                    doc.read(in);
114b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey                    add(doc);
115b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey                }
116b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey                break;
117b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey            default:
118b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey                throw new ProtocolException("Unknown version " + version);
119b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        }
120b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    }
121b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey
122b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    @Override
123b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    public void write(DataOutputStream out) throws IOException {
124d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        out.writeInt(VERSION_ADD_ROOT);
125d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        if (root != null) {
126d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey            out.writeBoolean(true);
127d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey            root.write(out);
128d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        } else {
129d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey            out.writeBoolean(false);
130d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        }
131b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        final int size = size();
132b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        out.writeInt(size);
133b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        for (int i = 0; i < size; i++) {
134b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey            final DocumentInfo doc = get(i);
135b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey            doc.write(out);
136b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        }
137b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    }
138b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey}
139