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