1 /* 2 * Copyright 2018 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 androidx.mediarouter.app; 18 19 import android.content.Context; 20 import android.graphics.Bitmap; 21 import android.graphics.Canvas; 22 import android.graphics.Rect; 23 import android.graphics.drawable.BitmapDrawable; 24 import android.util.DisplayMetrics; 25 import android.util.TypedValue; 26 import android.view.View; 27 import android.view.ViewGroup; 28 import android.widget.ArrayAdapter; 29 import android.widget.ListView; 30 31 import androidx.mediarouter.R; 32 33 import java.util.HashMap; 34 import java.util.HashSet; 35 import java.util.List; 36 import java.util.Set; 37 38 final class MediaRouteDialogHelper { 39 /** 40 * The framework should set the dialog width properly, but somehow it doesn't work, hence 41 * duplicating a similar logic here to determine the appropriate dialog width. 42 */ 43 public static int getDialogWidth(Context context) { 44 DisplayMetrics metrics = context.getResources().getDisplayMetrics(); 45 boolean isPortrait = metrics.widthPixels < metrics.heightPixels; 46 47 TypedValue value = new TypedValue(); 48 context.getResources().getValue(isPortrait ? R.dimen.mr_dialog_fixed_width_minor 49 : R.dimen.mr_dialog_fixed_width_major, value, true); 50 if (value.type == TypedValue.TYPE_DIMENSION) { 51 return (int) value.getDimension(metrics); 52 } else if (value.type == TypedValue.TYPE_FRACTION) { 53 return (int) value.getFraction(metrics.widthPixels, metrics.widthPixels); 54 } 55 return ViewGroup.LayoutParams.WRAP_CONTENT; 56 } 57 58 /** 59 * Compares two lists regardless of order. 60 * 61 * @param list1 A list 62 * @param list2 A list to be compared with {@code list1} 63 * @return True if two lists have exactly same items regardless of order, false otherwise. 64 */ 65 public static <E> boolean listUnorderedEquals(List<E> list1, List<E> list2) { 66 HashSet<E> set1 = new HashSet<>(list1); 67 HashSet<E> set2 = new HashSet<>(list2); 68 return set1.equals(set2); 69 } 70 71 /** 72 * Compares two lists and returns a set of items which exist 73 * after-list but before-list, which means newly added items. 74 * 75 * @param before A list 76 * @param after A list to be compared with {@code before} 77 * @return A set of items which contains newly added items while 78 * comparing {@code after} to {@code before}. 79 */ 80 public static <E> Set<E> getItemsAdded(List<E> before, List<E> after) { 81 HashSet<E> set = new HashSet<>(after); 82 set.removeAll(before); 83 return set; 84 } 85 86 /** 87 * Compares two lists and returns a set of items which exist 88 * before-list but after-list, which means removed items. 89 * 90 * @param before A list 91 * @param after A list to be compared with {@code before} 92 * @return A set of items which contains removed items while 93 * comparing {@code after} to {@code before}. 94 */ 95 public static <E> Set<E> getItemsRemoved(List<E> before, List<E> after) { 96 HashSet<E> set = new HashSet<>(before); 97 set.removeAll(after); 98 return set; 99 } 100 101 /** 102 * Generates an item-Rect map which indicates where member 103 * items are located in the given ListView. 104 * 105 * @param listView A list view 106 * @param adapter An array adapter which contains an array of items. 107 * @return A map of items and bounds of their views located in the given list view. 108 */ 109 public static <E> HashMap<E, Rect> getItemBoundMap(ListView listView, 110 ArrayAdapter<E> adapter) { 111 HashMap<E, Rect> itemBoundMap = new HashMap<>(); 112 int firstVisiblePosition = listView.getFirstVisiblePosition(); 113 for (int i = 0; i < listView.getChildCount(); ++i) { 114 int position = firstVisiblePosition + i; 115 E item = adapter.getItem(position); 116 View view = listView.getChildAt(i); 117 itemBoundMap.put(item, 118 new Rect(view.getLeft(), view.getTop(), view.getRight(), view.getBottom())); 119 } 120 return itemBoundMap; 121 } 122 123 /** 124 * Generates an item-BitmapDrawable map which stores snapshots 125 * of member items in the given ListView. 126 * 127 * @param context A context 128 * @param listView A list view 129 * @param adapter An array adapter which contains an array of items. 130 * @return A map of items and snapshots of their views in the given list view. 131 */ 132 public static <E> HashMap<E, BitmapDrawable> getItemBitmapMap(Context context, 133 ListView listView, ArrayAdapter<E> adapter) { 134 HashMap<E, BitmapDrawable> itemBitmapMap = new HashMap<>(); 135 int firstVisiblePosition = listView.getFirstVisiblePosition(); 136 for (int i = 0; i < listView.getChildCount(); ++i) { 137 int position = firstVisiblePosition + i; 138 E item = adapter.getItem(position); 139 View view = listView.getChildAt(i); 140 itemBitmapMap.put(item, getViewBitmap(context, view)); 141 } 142 return itemBitmapMap; 143 } 144 145 private static BitmapDrawable getViewBitmap(Context context, View view) { 146 Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), 147 Bitmap.Config.ARGB_8888); 148 Canvas canvas = new Canvas(bitmap); 149 view.draw(canvas); 150 return new BitmapDrawable(context.getResources(), bitmap); 151 } 152 153 private MediaRouteDialogHelper() { 154 } 155 } 156