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.base;
18 
19 import android.content.Intent;
20 import android.os.Parcel;
21 import android.os.Parcelable;
22 import android.util.SparseArray;
23 
24 import androidx.annotation.IntDef;
25 
26 import com.android.documentsui.services.FileOperationService;
27 import com.android.documentsui.services.FileOperationService.OpType;
28 import com.android.documentsui.sorting.SortModel;
29 
30 import java.lang.annotation.Retention;
31 import java.lang.annotation.RetentionPolicy;
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.HashMap;
35 import java.util.List;
36 
37 public class State implements android.os.Parcelable {
38 
39     private static final String TAG = "State";
40 
41     @IntDef(flag = true, value = {
42             ACTION_BROWSE,
43             ACTION_PICK_COPY_DESTINATION,
44             ACTION_OPEN,
45             ACTION_CREATE,
46             ACTION_GET_CONTENT,
47             ACTION_OPEN_TREE
48     })
49     @Retention(RetentionPolicy.SOURCE)
50     public @interface ActionType {}
51     // File manager and related private picking activity.
52     public static final int ACTION_BROWSE = 1;
53     public static final int ACTION_PICK_COPY_DESTINATION = 2;
54     // All public picking activities
55     public static final int ACTION_OPEN = 3;
56     public static final int ACTION_CREATE = 4;
57     public static final int ACTION_GET_CONTENT = 5;
58     public static final int ACTION_OPEN_TREE = 6;
59 
60     @IntDef(flag = true, value = {
61             MODE_UNKNOWN,
62             MODE_LIST,
63             MODE_GRID
64     })
65     @Retention(RetentionPolicy.SOURCE)
66     public @interface ViewMode {}
67     public static final int MODE_UNKNOWN = 0;
68     public static final int MODE_LIST = 1;
69     public static final int MODE_GRID = 2;
70 
71     public @ActionType int action;
72     public String[] acceptMimes;
73 
74     /** Derived from local preferences */
75     public @ViewMode int derivedMode = MODE_GRID;
76 
77     public boolean debugMode = false;
78 
79     /** Current sort state */
80     public SortModel sortModel;
81 
82     public boolean allowMultiple;
83     public boolean localOnly;
84 
85     public boolean openableOnly;
86     public boolean restrictScopeStorage;
87     public boolean showHiddenFiles;
88 
89     /**
90      * Represents whether the state supports cross-profile file picking.
91      */
92     public boolean supportsCrossProfile = false;
93 
94     /**
95      * Represents whether the intent is a cross-profile intent
96      */
97     public boolean canShareAcrossProfile = false;
98 
99     /**
100      * Returns true if we are allowed to interact with the user.
101      */
canInteractWith(UserId userId)102     public boolean canInteractWith(UserId userId) {
103         return canShareAcrossProfile || UserId.CURRENT_USER.equals(userId);
104     }
105 
106     /**
107      * This is basically a sub-type for the copy operation. It can be either COPY,
108      * COMPRESS, EXTRACT or MOVE.
109      * The only legal values, if set, are: OPERATION_COPY, OPERATION_COMPRESS,
110      * OPERATION_EXTRACT and OPERATION_MOVE. Other pick
111      * operations don't use this. In those cases OPERATION_UNKNOWN is also legal.
112      */
113     public @OpType int copyOperationSubType = FileOperationService.OPERATION_UNKNOWN;
114 
115     /** Current user navigation stack; empty implies recents. */
116     public final DocumentStack stack = new DocumentStack();
117 
118     /** Instance configs for every shown directory */
119     public HashMap<String, SparseArray<Parcelable>> dirConfigs = new HashMap<>();
120 
121     /** Name of the package that started DocsUI */
122     public List<String> excludedAuthorities = new ArrayList<>();
123 
initAcceptMimes(Intent intent, String defaultAcceptMimeType)124     public void initAcceptMimes(Intent intent, String defaultAcceptMimeType) {
125         if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) {
126             acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES);
127         } else {
128             acceptMimes = new String[] { defaultAcceptMimeType };
129         }
130     }
131 
132     /**
133      * Check current action should have preview function or not.
134      * @return True, if the action should have preview.
135      */
shouldShowPreview()136     public boolean shouldShowPreview() {
137         return action == ACTION_GET_CONTENT
138                 || action == ACTION_OPEN_TREE
139                 || action == ACTION_OPEN;
140     }
141 
142     /**
143      * Check the action is file picking and acceptMimes are all images type or not.
144      * @return True, if acceptMimes are all image type and action is file picking.
145      */
isPhotoPicking()146     public boolean isPhotoPicking() {
147         if (action != ACTION_GET_CONTENT && action != ACTION_OPEN || acceptMimes == null) {
148             return false;
149         }
150 
151         for (String mimeType : acceptMimes) {
152             if (!MimeTypes.mimeMatches(MimeTypes.IMAGE_MIME, mimeType)) {
153                 return false;
154             }
155         }
156         return true;
157     }
158 
159     /**
160      * Returns true if DocsUI supports cross-profile for this {@link State}.
161      */
supportsCrossProfile()162     public boolean supportsCrossProfile() {
163         return supportsCrossProfile;
164     }
165 
166     @Override
describeContents()167     public int describeContents() {
168         return 0;
169     }
170 
171     @Override
writeToParcel(Parcel out, int flags)172     public void writeToParcel(Parcel out, int flags) {
173         out.writeInt(action);
174         out.writeStringArray(acceptMimes);
175         out.writeInt(allowMultiple ? 1 : 0);
176         out.writeInt(localOnly ? 1 : 0);
177         DurableUtils.writeToParcel(out, stack);
178         out.writeMap(dirConfigs);
179         out.writeList(excludedAuthorities);
180         out.writeInt(openableOnly ? 1 : 0);
181         out.writeInt(restrictScopeStorage ? 1 : 0);
182         out.writeParcelable(sortModel, 0);
183     }
184 
185     @Override
toString()186     public String toString() {
187         return "State{"
188                 + "action=" + action
189                 + ", acceptMimes=" + Arrays.toString(acceptMimes)
190                 + ", allowMultiple=" + allowMultiple
191                 + ", localOnly=" + localOnly
192                 + ", stack=" + stack
193                 + ", dirConfigs=" + dirConfigs
194                 + ", excludedAuthorities=" + excludedAuthorities
195                 + ", openableOnly=" + openableOnly
196                 + ", restrictScopeStorage=" + restrictScopeStorage
197                 + ", sortModel=" + sortModel
198                 + "}";
199     }
200 
201     public static final ClassLoaderCreator<State> CREATOR = new ClassLoaderCreator<State>() {
202         @Override
203         public State createFromParcel(Parcel in) {
204             return createFromParcel(in, null);
205         }
206 
207         @Override
208         public State createFromParcel(Parcel in, ClassLoader loader) {
209             final State state = new State();
210             state.action = in.readInt();
211             state.acceptMimes = in.createStringArray();
212             state.allowMultiple = in.readInt() != 0;
213             state.localOnly = in.readInt() != 0;
214             DurableUtils.readFromParcel(in, state.stack);
215             in.readMap(state.dirConfigs, loader);
216             in.readList(state.excludedAuthorities, loader);
217             state.openableOnly = in.readInt() != 0;
218             state.restrictScopeStorage = in.readInt() != 0;
219             state.sortModel = in.readParcelable(loader);
220             return state;
221         }
222 
223         @Override
224         public State[] newArray(int size) {
225             return new State[size];
226         }
227     };
228 }
229