1 /*
2  * Copyright (C) 2016 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.roots;
18 
19 import static com.android.documentsui.base.Shared.DEBUG;
20 import static com.android.documentsui.base.Shared.VERBOSE;
21 
22 import android.util.Log;
23 
24 import com.android.documentsui.base.MimeTypes;
25 import com.android.documentsui.base.RootInfo;
26 import com.android.documentsui.base.State;
27 
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.Collection;
31 import java.util.List;
32 
33 /**
34  * Provides testable access to key {@link ProvidersCache} methods.
35  */
36 public interface ProvidersAccess {
37 
38     String BROADCAST_ACTION = "com.android.documentsui.action.ROOT_CHANGED";
39 
40     /**
41      * Return the requested {@link RootInfo}, but only loading the roots for the
42      * requested authority. This is useful when we want to load fast without
43      * waiting for all the other roots to come back.
44      */
getRootOneshot(String authority, String rootId)45     RootInfo getRootOneshot(String authority, String rootId);
46 
getMatchingRootsBlocking(State state)47     Collection<RootInfo> getMatchingRootsBlocking(State state);
48 
getRootsBlocking()49     Collection<RootInfo> getRootsBlocking();
50 
getDefaultRootBlocking(State state)51     RootInfo getDefaultRootBlocking(State state);
52 
getRecentsRoot()53     RootInfo getRecentsRoot();
54 
getApplicationName(String authority)55     String getApplicationName(String authority);
56 
getPackageName(String authority)57     String getPackageName(String authority);
58 
59     /**
60      * Returns a list of roots for the specified authority. If not found, then
61      * an empty list is returned.
62      */
getRootsForAuthorityBlocking(String authority)63     Collection<RootInfo> getRootsForAuthorityBlocking(String authority);
64 
getMatchingRoots(Collection<RootInfo> roots, State state)65     public static List<RootInfo> getMatchingRoots(Collection<RootInfo> roots, State state) {
66 
67         final String tag = "ProvidersAccess";
68 
69         final List<RootInfo> matching = new ArrayList<>();
70         for (RootInfo root : roots) {
71 
72             if (VERBOSE) Log.v(tag, "Evaluationg root: " + root);
73 
74             if (state.action == State.ACTION_CREATE && !root.supportsCreate()) {
75                 if (VERBOSE) Log.v(tag, "Excluding read-only root because: ACTION_CREATE.");
76                 continue;
77             }
78 
79             if (state.action == State.ACTION_PICK_COPY_DESTINATION
80                     && !root.supportsCreate()) {
81                 if (VERBOSE) Log.v(
82                         tag, "Excluding read-only root because: ACTION_PICK_COPY_DESTINATION.");
83                 continue;
84             }
85 
86             if (state.action == State.ACTION_OPEN_TREE && !root.supportsChildren()) {
87                 if (VERBOSE) Log.v(
88                         tag, "Excluding root !supportsChildren because: ACTION_OPEN_TREE.");
89                 continue;
90             }
91 
92             if (!state.showAdvanced && root.isAdvanced()) {
93                 if (VERBOSE) Log.v(tag, "Excluding root because: unwanted advanced device.");
94                 continue;
95             }
96 
97             if (state.localOnly && !root.isLocalOnly()) {
98                 if (VERBOSE) Log.v(tag, "Excluding root because: unwanted non-local device.");
99                 continue;
100             }
101 
102             if (state.directoryCopy && root.isDownloads()) {
103                 if (VERBOSE) Log.v(
104                         tag, "Excluding downloads root because: unsupported directory copy.");
105                 continue;
106             }
107 
108             if (state.action == State.ACTION_OPEN && root.isEmpty()) {
109                 if (VERBOSE) Log.v(tag, "Excluding empty root because: ACTION_OPEN.");
110                 continue;
111             }
112 
113             if (state.action == State.ACTION_GET_CONTENT && root.isEmpty()) {
114                 if (VERBOSE) Log.v(tag, "Excluding empty root because: ACTION_GET_CONTENT.");
115                 continue;
116             }
117 
118             final boolean overlap =
119                     MimeTypes.mimeMatches(root.derivedMimeTypes, state.acceptMimes) ||
120                     MimeTypes.mimeMatches(state.acceptMimes, root.derivedMimeTypes);
121             if (!overlap) {
122                 if (VERBOSE) Log.v(
123                         tag, "Excluding root because: unsupported content types > "
124                         + Arrays.toString(state.acceptMimes));
125                 continue;
126             }
127 
128             if (state.excludedAuthorities.contains(root.authority)) {
129                 if (VERBOSE) Log.v(tag, "Excluding root because: owned by calling package.");
130                 continue;
131             }
132 
133             matching.add(root);
134         }
135 
136         if (DEBUG) Log.d(tag, "Matched roots: " + matching);
137         return matching;
138     }
139 }
140