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