1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.documentsui.model;
18 
19 import android.content.ContentResolver;
20 import android.os.Parcel;
21 import android.os.Parcelable;
22 import android.provider.DocumentsProvider;
23 
24 import java.io.DataInputStream;
25 import java.io.DataOutputStream;
26 import java.io.FileNotFoundException;
27 import java.io.IOException;
28 import java.net.ProtocolException;
29 import java.util.Collection;
30 import java.util.LinkedList;
31 
32 /**
33  * Representation of a stack of {@link DocumentInfo}, usually the result of a
34  * user-driven traversal.
35  */
36 public class DocumentStack extends LinkedList<DocumentInfo> implements Durable, Parcelable {
37     private static final int VERSION_INIT = 1;
38     private static final int VERSION_ADD_ROOT = 2;
39 
40     public RootInfo root;
41 
getTitle()42     public String getTitle() {
43         if (size() == 1 && root != null) {
44             return root.title;
45         } else if (size() > 1) {
46             return peek().displayName;
47         } else {
48             return null;
49         }
50     }
51 
isRecents()52     public boolean isRecents() {
53         return size() == 0;
54     }
55 
updateRoot(Collection<RootInfo> matchingRoots)56     public void updateRoot(Collection<RootInfo> matchingRoots) throws FileNotFoundException {
57         for (RootInfo root : matchingRoots) {
58             if (root.equals(this.root)) {
59                 this.root = root;
60                 return;
61             }
62         }
63         throw new FileNotFoundException("Failed to find matching root for " + root);
64     }
65 
66     /**
67      * Update a possibly stale restored stack against a live
68      * {@link DocumentsProvider}.
69      */
updateDocuments(ContentResolver resolver)70     public void updateDocuments(ContentResolver resolver) throws FileNotFoundException {
71         for (DocumentInfo info : this) {
72             info.updateSelf(resolver);
73         }
74     }
75 
76     /**
77      * Build key that uniquely identifies this stack. It omits most of the raw
78      * details included in {@link #write(DataOutputStream)}, since they change
79      * too regularly to be used as a key.
80      */
buildKey()81     public String buildKey() {
82         final StringBuilder builder = new StringBuilder();
83         if (root != null) {
84             builder.append(root.authority).append('#');
85             builder.append(root.rootId).append('#');
86         } else {
87             builder.append("[null]").append('#');
88         }
89         for (DocumentInfo doc : this) {
90             builder.append(doc.documentId).append('#');
91         }
92         return builder.toString();
93     }
94 
95     @Override
reset()96     public void reset() {
97         clear();
98         root = null;
99     }
100 
101     @Override
read(DataInputStream in)102     public void read(DataInputStream in) throws IOException {
103         final int version = in.readInt();
104         switch (version) {
105             case VERSION_INIT:
106                 throw new ProtocolException("Ignored upgrade");
107             case VERSION_ADD_ROOT:
108                 if (in.readBoolean()) {
109                     root = new RootInfo();
110                     root.read(in);
111                 }
112                 final int size = in.readInt();
113                 for (int i = 0; i < size; i++) {
114                     final DocumentInfo doc = new DocumentInfo();
115                     doc.read(in);
116                     add(doc);
117                 }
118                 break;
119             default:
120                 throw new ProtocolException("Unknown version " + version);
121         }
122     }
123 
124     @Override
write(DataOutputStream out)125     public void write(DataOutputStream out) throws IOException {
126         out.writeInt(VERSION_ADD_ROOT);
127         if (root != null) {
128             out.writeBoolean(true);
129             root.write(out);
130         } else {
131             out.writeBoolean(false);
132         }
133         final int size = size();
134         out.writeInt(size);
135         for (int i = 0; i < size; i++) {
136             final DocumentInfo doc = get(i);
137             doc.write(out);
138         }
139     }
140 
141     @Override
describeContents()142     public int describeContents() {
143         return 0;
144     }
145 
146     @Override
writeToParcel(Parcel dest, int flags)147     public void writeToParcel(Parcel dest, int flags) {
148         DurableUtils.writeToParcel(dest, this);
149     }
150 
151     public static final Creator<DocumentStack> CREATOR = new Creator<DocumentStack>() {
152         @Override
153         public DocumentStack createFromParcel(Parcel in) {
154             final DocumentStack stack = new DocumentStack();
155             DurableUtils.readFromParcel(in, stack);
156             return stack;
157         }
158 
159         @Override
160         public DocumentStack[] newArray(int size) {
161             return new DocumentStack[size];
162         }
163     };
164 }
165