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