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; 18 19 import static com.android.documentsui.Shared.DEBUG; 20 21 import android.annotation.IntDef; 22 import android.content.Intent; 23 import android.os.Parcel; 24 import android.os.Parcelable; 25 import android.util.Log; 26 import android.util.SparseArray; 27 28 import com.android.documentsui.dirlist.MultiSelectManager.Selection; 29 import com.android.documentsui.model.DocumentInfo; 30 import com.android.documentsui.model.DocumentStack; 31 import com.android.documentsui.model.DurableUtils; 32 import com.android.documentsui.model.RootInfo; 33 import com.android.documentsui.services.FileOperationService; 34 import com.android.documentsui.services.FileOperationService.OpType; 35 36 import java.lang.annotation.Retention; 37 import java.lang.annotation.RetentionPolicy; 38 import java.util.ArrayList; 39 import java.util.HashMap; 40 import java.util.List; 41 42 public class State implements android.os.Parcelable { 43 44 private static final String TAG = "State"; 45 46 @IntDef(flag = true, value = { 47 ACTION_BROWSE, 48 ACTION_PICK_COPY_DESTINATION, 49 ACTION_OPEN, 50 ACTION_CREATE, 51 ACTION_GET_CONTENT, 52 ACTION_OPEN_TREE 53 }) 54 @Retention(RetentionPolicy.SOURCE) 55 public @interface ActionType {} 56 // File manager and related private picking activity. 57 public static final int ACTION_BROWSE = 1; 58 public static final int ACTION_PICK_COPY_DESTINATION = 2; 59 // All public picking activities 60 public static final int ACTION_OPEN = 3; 61 public static final int ACTION_CREATE = 4; 62 public static final int ACTION_GET_CONTENT = 5; 63 public static final int ACTION_OPEN_TREE = 6; 64 65 @IntDef(flag = true, value = { 66 MODE_UNKNOWN, 67 MODE_LIST, 68 MODE_GRID 69 }) 70 @Retention(RetentionPolicy.SOURCE) 71 public @interface ViewMode {} 72 public static final int MODE_UNKNOWN = 0; 73 public static final int MODE_LIST = 1; 74 public static final int MODE_GRID = 2; 75 76 public static final int SORT_ORDER_UNKNOWN = 0; 77 public static final int SORT_ORDER_DISPLAY_NAME = 1; 78 public static final int SORT_ORDER_LAST_MODIFIED = 2; 79 public static final int SORT_ORDER_SIZE = 3; 80 81 public @ActionType int action; 82 public String[] acceptMimes; 83 84 /** Derived from local preferences */ 85 public @ViewMode int derivedMode = MODE_GRID; 86 87 /** Explicit user choice */ 88 public int userSortOrder = SORT_ORDER_UNKNOWN; 89 /** Derived after loader */ 90 public int derivedSortOrder = SORT_ORDER_DISPLAY_NAME; 91 92 public boolean allowMultiple; 93 public boolean forceSize; 94 public boolean showSize; 95 public boolean localOnly; 96 public boolean showAdvancedOption; 97 public boolean showAdvanced; 98 public boolean restored; 99 /* 100 * Indicates handler was an external app, like photos. 101 */ 102 public boolean external; 103 104 // Indicates that a copy operation (or move) includes a directory. 105 // Why? Directory creation isn't supported by some roots (like Downloads). 106 // This allows us to restrict available roots to just those with support. 107 public boolean directoryCopy; 108 public boolean openableOnly; 109 110 /** 111 * This is basically a sub-type for the copy operation. It can be either COPY or MOVE. 112 * The only legal values, if set, are: OPERATION_COPY, OPERATION_MOVE. Other pick 113 * operations don't use this. In those cases OPERATION_UNKNOWN is also legal. 114 */ 115 public @OpType int copyOperationSubType = FileOperationService.OPERATION_UNKNOWN; 116 117 /** Current user navigation stack; empty implies recents. */ 118 public DocumentStack stack = new DocumentStack(); 119 private boolean mStackTouched; 120 private boolean mInitialRootChanged; 121 private boolean mInitialDocChanged; 122 123 /** Instance state for every shown directory */ 124 public HashMap<String, SparseArray<Parcelable>> dirState = new HashMap<>(); 125 126 /** Currently copying file */ 127 public List<DocumentInfo> selectedDocumentsForCopy = new ArrayList<>(); 128 129 /** Name of the package that started DocsUI */ 130 public List<String> excludedAuthorities = new ArrayList<>(); 131 initAcceptMimes(Intent intent)132 public void initAcceptMimes(Intent intent) { 133 if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) { 134 acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES); 135 } else { 136 String glob = intent.getType(); 137 acceptMimes = new String[] { glob != null ? glob : "*/*" }; 138 } 139 } 140 onRootChanged(RootInfo root)141 public void onRootChanged(RootInfo root) { 142 if (DEBUG) Log.d(TAG, "Root changed to: " + root); 143 if (!mInitialRootChanged && stack.root != null && !root.equals(stack.root)) { 144 mInitialRootChanged = true; 145 } 146 stack.root = root; 147 stack.clear(); 148 mStackTouched = true; 149 } 150 pushDocument(DocumentInfo info)151 public void pushDocument(DocumentInfo info) { 152 if (DEBUG) Log.d(TAG, "Adding doc to stack: " + info); 153 if (!mInitialDocChanged && stack.size() > 0 && !info.equals(stack.peek())) { 154 mInitialDocChanged = true; 155 } 156 stack.push(info); 157 mStackTouched = true; 158 } 159 popDocument()160 public void popDocument() { 161 if (DEBUG) Log.d(TAG, "Popping doc off stack."); 162 stack.pop(); 163 mStackTouched = true; 164 } 165 setStack(DocumentStack stack)166 public void setStack(DocumentStack stack) { 167 if (DEBUG) Log.d(TAG, "Setting the whole darn stack to: " + stack); 168 this.stack = stack; 169 mStackTouched = true; 170 } 171 172 // This will return true even when the initial location is set. 173 // To get a read on if the user has changed something, use #hasInitialLocationChanged. hasLocationChanged()174 public boolean hasLocationChanged() { 175 return mStackTouched; 176 } 177 hasInitialLocationChanged()178 public boolean hasInitialLocationChanged() { 179 return mInitialRootChanged || mInitialDocChanged; 180 } 181 182 @Override describeContents()183 public int describeContents() { 184 return 0; 185 } 186 187 @Override writeToParcel(Parcel out, int flags)188 public void writeToParcel(Parcel out, int flags) { 189 out.writeInt(action); 190 out.writeStringArray(acceptMimes); 191 out.writeInt(userSortOrder); 192 out.writeInt(allowMultiple ? 1 : 0); 193 out.writeInt(forceSize ? 1 : 0); 194 out.writeInt(showSize ? 1 : 0); 195 out.writeInt(localOnly ? 1 : 0); 196 out.writeInt(showAdvancedOption ? 1 : 0); 197 out.writeInt(showAdvanced ? 1 : 0); 198 out.writeInt(restored ? 1 : 0); 199 out.writeInt(external ? 1 : 0); 200 DurableUtils.writeToParcel(out, stack); 201 out.writeMap(dirState); 202 out.writeList(selectedDocumentsForCopy); 203 out.writeList(excludedAuthorities); 204 out.writeInt(openableOnly ? 1 : 0); 205 out.writeInt(mStackTouched ? 1 : 0); 206 out.writeInt(mInitialRootChanged ? 1 : 0); 207 out.writeInt(mInitialDocChanged ? 1 : 0); 208 } 209 210 public static final ClassLoaderCreator<State> CREATOR = new ClassLoaderCreator<State>() { 211 @Override 212 public State createFromParcel(Parcel in) { 213 return createFromParcel(in, null); 214 } 215 216 @Override 217 public State createFromParcel(Parcel in, ClassLoader loader) { 218 final State state = new State(); 219 state.action = in.readInt(); 220 state.acceptMimes = in.readStringArray(); 221 state.userSortOrder = in.readInt(); 222 state.allowMultiple = in.readInt() != 0; 223 state.forceSize = in.readInt() != 0; 224 state.showSize = in.readInt() != 0; 225 state.localOnly = in.readInt() != 0; 226 state.showAdvancedOption = in.readInt() != 0; 227 state.showAdvanced = in.readInt() != 0; 228 state.restored = in.readInt() != 0; 229 state.external = in.readInt() != 0; 230 DurableUtils.readFromParcel(in, state.stack); 231 in.readMap(state.dirState, loader); 232 in.readList(state.selectedDocumentsForCopy, loader); 233 in.readList(state.excludedAuthorities, loader); 234 state.openableOnly = in.readInt() != 0; 235 state.mStackTouched = in.readInt() != 0; 236 state.mInitialRootChanged = in.readInt() != 0; 237 state.mInitialDocChanged = in.readInt() != 0; 238 return state; 239 } 240 241 @Override 242 public State[] newArray(int size) { 243 return new State[size]; 244 } 245 }; 246 } 247