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.provider.DocumentsProvider; 21 22 import java.io.DataInputStream; 23 import java.io.DataOutputStream; 24 import java.io.FileNotFoundException; 25 import java.io.IOException; 26 import java.net.ProtocolException; 27 import java.util.Collection; 28 import java.util.LinkedList; 29 30 /** 31 * Representation of a stack of {@link DocumentInfo}, usually the result of a 32 * user-driven traversal. 33 */ 34 public class DocumentStack extends LinkedList<DocumentInfo> implements Durable { 35 private static final int VERSION_INIT = 1; 36 private static final int VERSION_ADD_ROOT = 2; 37 38 public RootInfo root; 39 40 public String getTitle() { 41 if (size() == 1 && root != null) { 42 return root.title; 43 } else if (size() > 1) { 44 return peek().displayName; 45 } else { 46 return null; 47 } 48 } 49 50 public boolean isRecents() { 51 return size() == 0; 52 } 53 54 public void updateRoot(Collection<RootInfo> matchingRoots) throws FileNotFoundException { 55 for (RootInfo root : matchingRoots) { 56 if (root.equals(this.root)) { 57 this.root = root; 58 return; 59 } 60 } 61 throw new FileNotFoundException("Failed to find matching root for " + root); 62 } 63 64 /** 65 * Update a possibly stale restored stack against a live 66 * {@link DocumentsProvider}. 67 */ 68 public void updateDocuments(ContentResolver resolver) throws FileNotFoundException { 69 for (DocumentInfo info : this) { 70 info.updateSelf(resolver); 71 } 72 } 73 74 /** 75 * Build key that uniquely identifies this stack. It omits most of the raw 76 * details included in {@link #write(DataOutputStream)}, since they change 77 * too regularly to be used as a key. 78 */ 79 public String buildKey() { 80 final StringBuilder builder = new StringBuilder(); 81 if (root != null) { 82 builder.append(root.authority).append('#'); 83 builder.append(root.rootId).append('#'); 84 } else { 85 builder.append("[null]").append('#'); 86 } 87 for (DocumentInfo doc : this) { 88 builder.append(doc.documentId).append('#'); 89 } 90 return builder.toString(); 91 } 92 93 @Override 94 public void reset() { 95 clear(); 96 root = null; 97 } 98 99 @Override 100 public void read(DataInputStream in) throws IOException { 101 final int version = in.readInt(); 102 switch (version) { 103 case VERSION_INIT: 104 throw new ProtocolException("Ignored upgrade"); 105 case VERSION_ADD_ROOT: 106 if (in.readBoolean()) { 107 root = new RootInfo(); 108 root.read(in); 109 } 110 final int size = in.readInt(); 111 for (int i = 0; i < size; i++) { 112 final DocumentInfo doc = new DocumentInfo(); 113 doc.read(in); 114 add(doc); 115 } 116 break; 117 default: 118 throw new ProtocolException("Unknown version " + version); 119 } 120 } 121 122 @Override 123 public void write(DataOutputStream out) throws IOException { 124 out.writeInt(VERSION_ADD_ROOT); 125 if (root != null) { 126 out.writeBoolean(true); 127 root.write(out); 128 } else { 129 out.writeBoolean(false); 130 } 131 final int size = size(); 132 out.writeInt(size); 133 for (int i = 0; i < size; i++) { 134 final DocumentInfo doc = get(i); 135 doc.write(out); 136 } 137 } 138 } 139