blob: dfb7b5da645d80f3226668b47ba2612d988bdf0a [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.documentsui.roots;
import static com.android.documentsui.base.SharedMinimal.DEBUG;
import static com.android.documentsui.base.SharedMinimal.VERBOSE;
import android.util.Log;
import androidx.annotation.Nullable;
import com.android.documentsui.base.MimeTypes;
import com.android.documentsui.base.RootInfo;
import com.android.documentsui.base.State;
import com.android.documentsui.base.UserId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/**
* Provides testable access to key {@link ProvidersCache} methods.
*/
public interface ProvidersAccess {
String BROADCAST_ACTION = "com.android.documentsui.action.ROOT_CHANGED";
/**
* Return the requested {@link RootInfo}, but only loading the roots for the
* requested user and authority. This is useful when we want to load fast without
* waiting for all the other roots to come back.
*/
RootInfo getRootOneshot(UserId userId, String authority, String rootId);
Collection<RootInfo> getMatchingRootsBlocking(State state);
Collection<RootInfo> getRootsBlocking();
RootInfo getDefaultRootBlocking(State state);
RootInfo getRecentsRoot(UserId userId);
String getApplicationName(UserId userId, String authority);
String getPackageName(UserId userId, String authority);
/**
* Returns a list of roots for the specified user and authority. If not found, then
* an empty list is returned.
*/
Collection<RootInfo> getRootsForAuthorityBlocking(UserId userId, String authority);
public static List<RootInfo> getMatchingRoots(Collection<RootInfo> roots, State state) {
final String tag = "ProvidersAccess";
final List<RootInfo> matching = new ArrayList<>();
for (RootInfo root : roots) {
if (VERBOSE) Log.v(tag, "Evaluationg root: " + root);
if (state.action == State.ACTION_CREATE && !root.supportsCreate()) {
if (VERBOSE) Log.v(tag, "Excluding read-only root because: ACTION_CREATE.");
continue;
}
if (state.action == State.ACTION_PICK_COPY_DESTINATION
&& !root.supportsCreate()) {
if (VERBOSE) Log.v(
tag, "Excluding read-only root because: ACTION_PICK_COPY_DESTINATION.");
continue;
}
if (state.action == State.ACTION_OPEN_TREE && !root.supportsChildren()) {
if (VERBOSE) Log.v(
tag, "Excluding root !supportsChildren because: ACTION_OPEN_TREE.");
continue;
}
if (state.action == State.ACTION_OPEN_TREE && root.isRecents()) {
if (VERBOSE) Log.v(
tag, "Excluding recent root because: ACTION_OPEN_TREE.");
continue;
}
if (state.localOnly && !root.isLocalOnly()) {
if (VERBOSE) Log.v(tag, "Excluding root because: unwanted non-local device.");
continue;
}
if (state.action == State.ACTION_OPEN && root.isEmpty()) {
if (VERBOSE) Log.v(tag, "Excluding empty root because: ACTION_OPEN.");
continue;
}
if (state.action == State.ACTION_GET_CONTENT && root.isEmpty()) {
if (VERBOSE) Log.v(tag, "Excluding empty root because: ACTION_GET_CONTENT.");
continue;
}
if (!UserId.CURRENT_USER.equals(root.userId) && !state.supportsCrossProfile()) {
if (VERBOSE) {
Log.v(tag, "Excluding root because: action does not support cross profile.");
}
continue;
}
final boolean overlap =
MimeTypes.mimeMatches(root.derivedMimeTypes, state.acceptMimes) ||
MimeTypes.mimeMatches(state.acceptMimes, root.derivedMimeTypes);
if (!overlap) {
if (VERBOSE) Log.v(
tag, "Excluding root because: unsupported content types > "
+ Arrays.toString(state.acceptMimes));
continue;
}
if (state.excludedAuthorities.contains(root.authority)) {
if (VERBOSE) Log.v(tag, "Excluding root because: owned by calling package.");
continue;
}
matching.add(root);
}
if (DEBUG) {
Log.d(tag, "Matched roots: " + matching);
}
return matching;
}
/**
* Returns the root should default show on current state.
*/
static @Nullable RootInfo getDefaultRoot(Collection<RootInfo> roots, State state) {
for (RootInfo root : ProvidersAccess.getMatchingRoots(roots, state)) {
if (root.isExternalStorage() && state.action == State.ACTION_OPEN_TREE) {
return root;
}
if (root.isDownloads()) {
return root;
}
}
return null;
}
}