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.car.media.drawer; 17 18 import android.content.Context; 19 import android.graphics.Bitmap; 20 import android.media.MediaDescription; 21 import android.text.TextUtils; 22 import android.view.View; 23 24 import com.android.car.apps.common.BitmapDownloader; 25 import com.android.car.apps.common.BitmapWorkerOptions; 26 import com.android.car.apps.common.UriUtils; 27 import com.android.car.media.R; 28 29 import androidx.car.drawer.CarDrawerAdapter; 30 import androidx.car.drawer.DrawerItemViewHolder; 31 32 /** 33 * Component that handles fetching of items for {@link MediaDrawerAdapter}. 34 * <p> 35 * It also handles ViewHolder population and item clicks. 36 */ 37 interface MediaItemsFetcher { 38 int DONT_SCROLL = -1; 39 40 /** 41 * Used to inform owning {@link MediaDrawerAdapter} that items have changed. 42 */ 43 interface ItemsUpdatedCallback { 44 void onItemsUpdated(); 45 } 46 47 /** 48 * Kick-off fetching/monitoring of items. 49 * 50 * @param callback Callback that is invoked when items are first loaded ar if they change 51 * subsequently. 52 */ 53 void start(ItemsUpdatedCallback callback); 54 55 /** 56 * @return Number of items currently fetched. 57 */ 58 int getItemCount(); 59 60 /** 61 * Used to indicate the kind of layout (small or normal) to use for the views that will display 62 * this item in a {@link CarDrawerAdapter}. See {@link CarDrawerAdapter#usesSmallLayout} 63 * 64 * @param position Adapter position of item 65 * @return Whether to use small (true) or normal layout (false). 66 */ 67 boolean usesSmallLayout(int position); 68 69 /** 70 * Used by owning {@link MediaDrawerAdapter} to populate views. 71 * 72 * @param holder View-holder to populate. 73 * @param position Item position. 74 */ 75 void populateViewHolder(DrawerItemViewHolder holder, int position); 76 77 /** 78 * Used by owning {@link MediaDrawerAdapter} to handle clicks. 79 * 80 * @param position Item position. 81 */ 82 void onItemClick(int position); 83 84 /** 85 * Used when this instance is going to be released. Subclasses should release resources. 86 */ 87 void cleanup(); 88 89 90 /** 91 * Get the position to scroll to if any. 92 * @return An integer greater than or equal to 0 if there is a position to scroll to, the 93 * constant {@link DONT_SCROLL} otherwise. 94 */ 95 int getScrollPosition(); 96 97 /** 98 * Utility method to determine if description can be displayed in a small layout. 99 */ 100 static boolean usesSmallLayout(MediaDescription description) { 101 // Small layout is sufficient if there's no sub-title to display for the item. 102 return TextUtils.isEmpty(description.getSubtitle()); 103 } 104 105 /** 106 * Utility method to populate {@code holder} with details from {@code description}. It populates 107 * title, text and icon at most. 108 */ 109 static void populateViewHolderFrom(DrawerItemViewHolder holder, MediaDescription description) { 110 Context context = holder.itemView.getContext(); 111 holder.getTitle().setText(description.getTitle()); 112 // If normal layout, populate subtitle. 113 if (!usesSmallLayout(description)) { 114 holder.getText().setText(description.getSubtitle()); 115 } 116 Bitmap iconBitmap = description.getIconBitmap(); 117 holder.getIcon().setImageBitmap(iconBitmap); // Ok to set null here for clearing. 118 if (iconBitmap == null) { 119 if (description.getIconUri() != null) { 120 holder.getIcon().setVisibility(View.VISIBLE); 121 int bitmapSize = 122 context.getResources().getDimensionPixelSize(R.dimen.car_primary_icon_size); 123 // We don't want to cache android resources as they are needed to be refreshed after 124 // configuration changes. 125 int cacheFlag = UriUtils.isAndroidResourceUri(description.getIconUri()) 126 ? (BitmapWorkerOptions.CACHE_FLAG_DISK_DISABLED 127 | BitmapWorkerOptions.CACHE_FLAG_MEM_DISABLED) 128 : 0; 129 BitmapWorkerOptions options = new BitmapWorkerOptions.Builder(context) 130 .resource(description.getIconUri()) 131 .height(bitmapSize) 132 .width(bitmapSize) 133 .cacheFlag(cacheFlag) 134 .build(); 135 BitmapDownloader.getInstance(context).loadBitmap(options, holder.getIcon()); 136 } else { 137 holder.getIcon().setVisibility(View.GONE); 138 } 139 } 140 } 141 } 142