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;
20e1a03f8eec2719279037ab348df306764dc45a70Tomasz Mikolajewskiimport android.os.Parcel;
21e1a03f8eec2719279037ab348df306764dc45a70Tomasz Mikolajewskiimport android.os.Parcelable;
22deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkeyimport android.provider.DocumentsProvider;
23deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey
24b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkeyimport java.io.DataInputStream;
25b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkeyimport java.io.DataOutputStream;
26deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkeyimport java.io.FileNotFoundException;
27b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkeyimport java.io.IOException;
28b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkeyimport java.net.ProtocolException;
29deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkeyimport java.util.Collection;
30b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport java.util.LinkedList;
31b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
32b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey/**
33ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * Representation of a stack of {@link DocumentInfo}, usually the result of a
34b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey * user-driven traversal.
35b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey */
36e1a03f8eec2719279037ab348df306764dc45a70Tomasz Mikolajewskipublic class DocumentStack extends LinkedList<DocumentInfo> implements Durable, Parcelable {
37b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    private static final int VERSION_INIT = 1;
38d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey    private static final int VERSION_ADD_ROOT = 2;
39aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
40d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey    public RootInfo root;
41aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
42d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey    public String getTitle() {
43d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        if (size() == 1 && root != null) {
44d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey            return root.title;
45aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        } else if (size() > 1) {
46aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            return peek().displayName;
47aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        } else {
48aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            return null;
49aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        }
50aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
51b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey
52ded77187ef53341765fcab8e29cda94810fc2ca5Jeff Sharkey    public boolean isRecents() {
53ded77187ef53341765fcab8e29cda94810fc2ca5Jeff Sharkey        return size() == 0;
54ded77187ef53341765fcab8e29cda94810fc2ca5Jeff Sharkey    }
55ded77187ef53341765fcab8e29cda94810fc2ca5Jeff Sharkey
56deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey    public void updateRoot(Collection<RootInfo> matchingRoots) throws FileNotFoundException {
57deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        for (RootInfo root : matchingRoots) {
58deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey            if (root.equals(this.root)) {
59deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey                this.root = root;
60deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey                return;
61deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey            }
62deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        }
63deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        throw new FileNotFoundException("Failed to find matching root for " + root);
64deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey    }
65deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey
66deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey    /**
67deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey     * Update a possibly stale restored stack against a live
68deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey     * {@link DocumentsProvider}.
69deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey     */
70deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey    public void updateDocuments(ContentResolver resolver) throws FileNotFoundException {
71deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        for (DocumentInfo info : this) {
72deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey            info.updateSelf(resolver);
73deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        }
74deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey    }
75deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey
766efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey    /**
776efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey     * Build key that uniquely identifies this stack. It omits most of the raw
786efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey     * details included in {@link #write(DataOutputStream)}, since they change
796efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey     * too regularly to be used as a key.
806efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey     */
816efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey    public String buildKey() {
826efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        final StringBuilder builder = new StringBuilder();
836efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        if (root != null) {
846efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            builder.append(root.authority).append('#');
856efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            builder.append(root.rootId).append('#');
866efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        } else {
876efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            builder.append("[null]").append('#');
886efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        }
896efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        for (DocumentInfo doc : this) {
906efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            builder.append(doc.documentId).append('#');
916efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        }
926efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        return builder.toString();
936efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey    }
946efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey
95b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    @Override
96b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    public void reset() {
97b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        clear();
98d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        root = null;
99b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    }
100b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey
101b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    @Override
102b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    public void read(DataInputStream in) throws IOException {
103b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        final int version = in.readInt();
104b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        switch (version) {
105b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey            case VERSION_INIT:
106d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey                throw new ProtocolException("Ignored upgrade");
107d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey            case VERSION_ADD_ROOT:
108d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey                if (in.readBoolean()) {
109d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey                    root = new RootInfo();
110d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey                    root.read(in);
111d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey                }
112b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey                final int size = in.readInt();
113b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey                for (int i = 0; i < size; i++) {
114b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey                    final DocumentInfo doc = new DocumentInfo();
115b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey                    doc.read(in);
116b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey                    add(doc);
117b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey                }
118b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey                break;
119b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey            default:
120b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey                throw new ProtocolException("Unknown version " + version);
121b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        }
122b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    }
123b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey
124b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    @Override
125b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    public void write(DataOutputStream out) throws IOException {
126d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        out.writeInt(VERSION_ADD_ROOT);
127d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        if (root != null) {
128d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey            out.writeBoolean(true);
129d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey            root.write(out);
130d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        } else {
131d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey            out.writeBoolean(false);
132d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        }
133b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        final int size = size();
134b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        out.writeInt(size);
135b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        for (int i = 0; i < size; i++) {
136b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey            final DocumentInfo doc = get(i);
137b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey            doc.write(out);
138b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        }
139b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    }
140e1a03f8eec2719279037ab348df306764dc45a70Tomasz Mikolajewski
141e1a03f8eec2719279037ab348df306764dc45a70Tomasz Mikolajewski    @Override
142e1a03f8eec2719279037ab348df306764dc45a70Tomasz Mikolajewski    public int describeContents() {
143e1a03f8eec2719279037ab348df306764dc45a70Tomasz Mikolajewski        return 0;
144e1a03f8eec2719279037ab348df306764dc45a70Tomasz Mikolajewski    }
145e1a03f8eec2719279037ab348df306764dc45a70Tomasz Mikolajewski
146e1a03f8eec2719279037ab348df306764dc45a70Tomasz Mikolajewski    @Override
147e1a03f8eec2719279037ab348df306764dc45a70Tomasz Mikolajewski    public void writeToParcel(Parcel dest, int flags) {
148e1a03f8eec2719279037ab348df306764dc45a70Tomasz Mikolajewski        DurableUtils.writeToParcel(dest, this);
149e1a03f8eec2719279037ab348df306764dc45a70Tomasz Mikolajewski    }
150e1a03f8eec2719279037ab348df306764dc45a70Tomasz Mikolajewski
151e1a03f8eec2719279037ab348df306764dc45a70Tomasz Mikolajewski    public static final Creator<DocumentStack> CREATOR = new Creator<DocumentStack>() {
152e1a03f8eec2719279037ab348df306764dc45a70Tomasz Mikolajewski        @Override
153e1a03f8eec2719279037ab348df306764dc45a70Tomasz Mikolajewski        public DocumentStack createFromParcel(Parcel in) {
154e1a03f8eec2719279037ab348df306764dc45a70Tomasz Mikolajewski            final DocumentStack stack = new DocumentStack();
155e1a03f8eec2719279037ab348df306764dc45a70Tomasz Mikolajewski            DurableUtils.readFromParcel(in, stack);
156e1a03f8eec2719279037ab348df306764dc45a70Tomasz Mikolajewski            return stack;
157e1a03f8eec2719279037ab348df306764dc45a70Tomasz Mikolajewski        }
158e1a03f8eec2719279037ab348df306764dc45a70Tomasz Mikolajewski
159e1a03f8eec2719279037ab348df306764dc45a70Tomasz Mikolajewski        @Override
160e1a03f8eec2719279037ab348df306764dc45a70Tomasz Mikolajewski        public DocumentStack[] newArray(int size) {
161e1a03f8eec2719279037ab348df306764dc45a70Tomasz Mikolajewski            return new DocumentStack[size];
162e1a03f8eec2719279037ab348df306764dc45a70Tomasz Mikolajewski        }
163e1a03f8eec2719279037ab348df306764dc45a70Tomasz Mikolajewski    };
164b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey}
165