1 /*
2  * Copyright (C) 2017 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 package com.android.documentsui.dirlist;
17 
18 import static androidx.core.util.Preconditions.checkArgument;
19 
20 import static com.android.documentsui.base.DocumentInfo.getCursorInt;
21 import static com.android.documentsui.base.DocumentInfo.getCursorString;
22 
23 import android.database.Cursor;
24 import android.provider.DocumentsContract.Document;
25 import android.util.Log;
26 
27 import androidx.recyclerview.selection.SelectionTracker.SelectionPredicate;
28 import androidx.recyclerview.widget.RecyclerView;
29 
30 import com.android.documentsui.ActivityConfig;
31 import com.android.documentsui.Model;
32 import com.android.documentsui.base.State;
33 
34 /**
35  * Class embodying the logic as to whether an item (specified by id or position)
36  * can be selected (or not).
37  */
38 final class DocsSelectionPredicate extends SelectionPredicate<String> {
39 
40     private ActivityConfig mConfig;
41     private Model mModel;
42     private RecyclerView mRecView;
43     private State mState;
44 
DocsSelectionPredicate( ActivityConfig config, State state, Model model, RecyclerView recView)45     DocsSelectionPredicate(
46             ActivityConfig config, State state, Model model, RecyclerView recView) {
47 
48         checkArgument(config != null);
49         checkArgument(state != null);
50         checkArgument(model != null);
51         checkArgument(recView != null);
52 
53         mConfig = config;
54         mState = state;
55         mModel = model;
56         mRecView = recView;
57 
58     }
59 
60     @Override
canSetStateForKey(String id, boolean nextState)61     public boolean canSetStateForKey(String id, boolean nextState) {
62         if (nextState) {
63             // Check if an item can be selected
64             final Cursor cursor = mModel.getItem(id);
65             if (cursor == null) {
66                 Log.w(DirectoryFragment.TAG, "Couldn't obtain cursor for id: " + id);
67                 return false;
68             }
69 
70             final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
71             final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
72             return mConfig.canSelectType(docMimeType, docFlags, mState);
73         }
74 
75         // Right now all selected items can be deselected.
76         return true;
77     }
78 
79     @Override
canSetStateAtPosition(int position, boolean nextState)80     public boolean canSetStateAtPosition(int position, boolean nextState) {
81         // This method features a nextState arg for symmetry.
82         // But, there are no current uses for checking un-selecting state by position.
83         // So rather than have some unsuspecting client think canSetState(int, false)
84         // will ever do anything. Let's just be grumpy about it.
85         assert nextState == true;
86 
87         // NOTE: Given that we have logic in some places disallowing selection,
88         // it may be a bug that Band and Gesture based selections don't
89         // also verify something can be unselected.
90 
91         // The band selection model only operates on documents and directories.
92         // Exclude other types of adapter items like whitespace and dividers.
93         final RecyclerView.ViewHolder vh = mRecView.findViewHolderForAdapterPosition(position);
94         if (vh == null) {
95             return false;
96         } else {
97             return ModelBackedDocumentsAdapter.isContentType(vh.getItemViewType());
98         }
99     }
100 
101     @Override
canSelectMultiple()102     public boolean canSelectMultiple() {
103         return mState.allowMultiple;
104     }
105 }
106