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