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