• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.dirlist;
18 
19 import static com.android.documentsui.base.DocumentInfo.getCursorInt;
20 import static com.android.documentsui.base.DocumentInfo.getCursorString;
21 import static com.android.documentsui.base.State.MODE_GRID;
22 import static com.android.documentsui.base.State.MODE_LIST;
23 
24 import android.database.Cursor;
25 import android.provider.DocumentsContract.Document;
26 import android.util.Log;
27 import android.view.ViewGroup;
28 
29 import com.android.documentsui.Model;
30 import com.android.documentsui.base.EventListener;
31 import com.android.documentsui.base.Lookup;
32 import com.android.documentsui.base.State;
33 import com.android.documentsui.Model.Update;
34 
35 import java.util.ArrayList;
36 import java.util.List;
37 
38 /**
39  * Adapts from dirlist.Model to something RecyclerView understands.
40  */
41 final class ModelBackedDocumentsAdapter extends DocumentsAdapter {
42 
43     private static final String TAG = "ModelBackedDocuments";
44 
45     // Provides access to information needed when creating and view holders. This
46     // isn't an ideal pattern (more transitive dependency stuff) but good enough for now.
47     private final Environment mEnv;
48     private final IconHelper mIconHelper;  // a transitive dependency of the holders.
49     private final Lookup<String, String> mFileTypeLookup;
50 
51     /**
52      * An ordered list of model IDs. This is the data structure that determines what shows up in
53      * the UI, and where.
54      */
55     private List<String> mModelIds = new ArrayList<>();
56     private EventListener<Model.Update> mModelUpdateListener;
57 
ModelBackedDocumentsAdapter( Environment env, IconHelper iconHelper, Lookup<String, String> fileTypeLookup)58     public ModelBackedDocumentsAdapter(
59             Environment env, IconHelper iconHelper, Lookup<String, String> fileTypeLookup) {
60         mEnv = env;
61         mIconHelper = iconHelper;
62         mFileTypeLookup = fileTypeLookup;
63 
64         mModelUpdateListener = new EventListener<Model.Update>() {
65             @Override
66             public void accept(Update event) {
67                 if (event.hasException()) {
68                     onModelUpdateFailed(event.getException());
69                 } else {
70                     onModelUpdate(mEnv.getModel());
71                 }
72             }
73         };
74     }
75 
76     @Override
getModelUpdateListener()77     EventListener<Update> getModelUpdateListener() {
78         return mModelUpdateListener;
79     }
80 
81     @Override
onCreateViewHolder(ViewGroup parent, int viewType)82     public DocumentHolder onCreateViewHolder(ViewGroup parent, int viewType) {
83         DocumentHolder holder = null;
84         final State state = mEnv.getDisplayState();
85         switch (state.derivedMode) {
86             case MODE_GRID:
87                 switch (viewType) {
88                     case ITEM_TYPE_DIRECTORY:
89                         holder = new GridDirectoryHolder(mEnv.getContext(), parent);
90                         break;
91                     case ITEM_TYPE_DOCUMENT:
92                         holder = new GridDocumentHolder(mEnv.getContext(), parent, mIconHelper);
93                         break;
94                     default:
95                         throw new IllegalStateException("Unsupported layout type.");
96                 }
97                 break;
98             case MODE_LIST:
99                 holder = new ListDocumentHolder(
100                         mEnv.getContext(), parent, mIconHelper, mFileTypeLookup);
101                 break;
102             default:
103                 throw new IllegalStateException("Unsupported layout mode.");
104         }
105 
106         mEnv.initDocumentHolder(holder);
107         return holder;
108     }
109 
110     @Override
onBindViewHolder(DocumentHolder holder, int position, List<Object> payload)111     public void onBindViewHolder(DocumentHolder holder, int position, List<Object> payload) {
112         if (payload.contains(SELECTION_CHANGED_MARKER)) {
113             final boolean selected = mEnv.isSelected(mModelIds.get(position));
114             holder.setSelected(selected, true);
115         } else {
116             onBindViewHolder(holder, position);
117         }
118     }
119 
120     @Override
onBindViewHolder(DocumentHolder holder, int position)121     public void onBindViewHolder(DocumentHolder holder, int position) {
122         String modelId = mModelIds.get(position);
123         Cursor cursor = mEnv.getModel().getItem(modelId);
124         holder.bind(cursor, modelId);
125 
126         final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
127         final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
128 
129         boolean enabled = mEnv.isDocumentEnabled(docMimeType, docFlags);
130         boolean selected = mEnv.isSelected(modelId);
131         if (!enabled) {
132             assert(!selected);
133         }
134         holder.setEnabled(enabled);
135         holder.setSelected(mEnv.isSelected(modelId), false);
136 
137         mEnv.onBindDocumentHolder(holder, cursor);
138     }
139 
140     @Override
getItemCount()141     public int getItemCount() {
142         return mModelIds.size();
143     }
144 
onModelUpdate(Model model)145     private void onModelUpdate(Model model) {
146         String[] modelIds = model.getModelIds();
147         mModelIds = new ArrayList<>(modelIds.length);
148         for (String id : modelIds) {
149             mModelIds.add(id);
150         }
151     }
152 
onModelUpdateFailed(Exception e)153     private void onModelUpdateFailed(Exception e) {
154         Log.w(TAG, "Model update failed.", e);
155         mModelIds.clear();
156     }
157 
158     @Override
getModelId(int adapterPosition)159     public String getModelId(int adapterPosition) {
160         return mModelIds.get(adapterPosition);
161     }
162 
163     @Override
getAdapterPosition(String modelId)164     public int getAdapterPosition(String modelId) {
165         return mModelIds.indexOf(modelId);
166     }
167 
168     @Override
getModelIds()169     public List<String> getModelIds() {
170         return mModelIds;
171     }
172 
173     @Override
getItemViewType(int position)174     public int getItemViewType(int position) {
175         return isDirectory(mEnv.getModel(), position)
176                 ? ITEM_TYPE_DIRECTORY
177                 : ITEM_TYPE_DOCUMENT;
178     }
179 
180     /**
181      * @return true if the item type is either document or directory, false for all other
182      * possible types.
183      */
isContentType(int type)184     public static boolean isContentType(int type) {
185         switch (type) {
186             case ModelBackedDocumentsAdapter.ITEM_TYPE_DOCUMENT:
187             case ModelBackedDocumentsAdapter.ITEM_TYPE_DIRECTORY:
188                 return true;
189         }
190         return false;
191     }
192 
193     @Override
onItemSelectionChanged(String id)194     public void onItemSelectionChanged(String id) {
195         int position = mModelIds.indexOf(id);
196 
197         if (position >= 0) {
198             notifyItemChanged(position, SELECTION_CHANGED_MARKER);
199         } else {
200             Log.w(TAG, "Item change notification received for unknown item: " + id);
201         }
202     }
203 }
204