1b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael/* 2b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * Copyright (C) 2013 The Android Open Source Project 3b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * 4b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * Licensed under the Apache License, Version 2.0 (the "License"); 5b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * you may not use this file except in compliance with the License. 6b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * You may obtain a copy of the License at 7b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * 8b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * http://www.apache.org/licenses/LICENSE-2.0 9b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * 10b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * Unless required by applicable law or agreed to in writing, software 11b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * distributed under the License is distributed on an "AS IS" BASIS, 12b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * See the License for the specific language governing permissions and 14b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * limitations under the License. 15b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael */ 16b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael 17b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphaelpackage com.android.camera.settings; 18b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael 19fb0496133a0b4b526dc70f6447bd4b97d95de95fSenpo Huimport android.content.Context; 20fb0496133a0b4b526dc70f6447bd4b97d95de95fSenpo Huimport android.util.DisplayMetrics; 21fb0496133a0b4b526dc70f6447bd4b97d95de95fSenpo Huimport android.view.WindowManager; 22fb0496133a0b4b526dc70f6447bd4b97d95de95fSenpo Hu 238be316c7a8caf962cf3fcf5e49d332fb2718319fPaul Rohdeimport com.android.camera.exif.Rational; 248be316c7a8caf962cf3fcf5e49d332fb2718319fPaul Rohdeimport com.android.camera.util.AndroidServices; 258be316c7a8caf962cf3fcf5e49d332fb2718319fPaul Rohdeimport com.android.camera.util.ApiHelper; 268be316c7a8caf962cf3fcf5e49d332fb2718319fPaul Rohdeimport com.android.camera.util.Size; 278d8b329da25456adb5ee45e0450680654114e125I-Jong Lin 2886d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberlingimport com.google.common.collect.Lists; 298be316c7a8caf962cf3fcf5e49d332fb2718319fPaul Rohde 30b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphaelimport java.math.BigInteger; 31b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphaelimport java.util.ArrayList; 32b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphaelimport java.util.Arrays; 33b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphaelimport java.util.Collections; 34b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphaelimport java.util.Comparator; 35b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphaelimport java.util.HashMap; 3686d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberlingimport java.util.HashSet; 37b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphaelimport java.util.LinkedList; 38b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphaelimport java.util.List; 3986d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberlingimport java.util.Set; 4086d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling 411d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohdeimport javax.annotation.Nonnull; 4286d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberlingimport javax.annotation.ParametersAreNonnullByDefault; 4386d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling 44b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael 45b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael/** 46b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * This class is used to help manage the many different resolutions available on 47b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * the device. <br/> 48b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * It allows you to specify which aspect ratios to offer the user, and then 49b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * chooses which resolutions are the most pertinent to avoid overloading the 50b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * user with so many options. 51b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael */ 52b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphaelpublic class ResolutionUtil { 532272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu /** 542272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu * Different aspect ratio constants. 552272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu */ 562272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu public static final Rational ASPECT_RATIO_16x9 = new Rational(16, 9); 572272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu public static final Rational ASPECT_RATIO_4x3 = new Rational(4, 3); 582272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu private static final double ASPECT_RATIO_TOLERANCE = 0.05; 59b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael 60454d63f617489281971fb151abfe14730209c047Angus Kong public static final String NEXUS_5_LARGE_16_BY_9 = "1836x3264"; 61454d63f617489281971fb151abfe14730209c047Angus Kong public static final float NEXUS_5_LARGE_16_BY_9_ASPECT_RATIO = 16f / 9f; 622f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall public static Size NEXUS_5_LARGE_16_BY_9_SIZE = new Size(3264, 1836); 63454d63f617489281971fb151abfe14730209c047Angus Kong 64b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael /** 65b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * These are the preferred aspect ratios for the settings. We will take HAL 662272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu * supported aspect ratios that are within ASPECT_RATIO_TOLERANCE of these values. 67b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * We will also take the maximum supported resolution for full sensor image. 68b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael */ 69b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael private static Float[] sDesiredAspectRatios = { 70b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael 16.0f / 9.0f, 4.0f / 3.0f 71b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael }; 72b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael 731cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael private static Size[] sDesiredAspectRatioSizes = { 741cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael new Size(16, 9), new Size(4, 3) 751cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael }; 761cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael 77b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael /** 78b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * A resolution bucket holds a list of sizes that are of a given aspect 79b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * ratio. 80b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael */ 81b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael private static class ResolutionBucket { 82b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael public Float aspectRatio; 83b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael /** 84b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * This is a sorted list of sizes, going from largest to smallest. 85b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael */ 86b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael public List<Size> sizes = new LinkedList<Size>(); 87b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael /** 88b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * This is the head of the sizes array. 89b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael */ 90b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael public Size largest; 91b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael /** 92b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * This is the area of the largest size, used for sorting 93b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * ResolutionBuckets. 94b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael */ 95b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael public Integer maxPixels = 0; 96b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael 97b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael /** 98b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * Use this to add a new resolution to this bucket. It will insert it 99b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * into the sizes array and update appropriate members. 10008b3c94a7d7aff30b5da8e99649346e37b67a5c5Sascha Haeberling * 101b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * @param size the new size to be added 102b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael */ 103b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael public void add(Size size) { 104b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael sizes.add(size); 105b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael Collections.sort(sizes, new Comparator<Size>() { 106b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael @Override 107b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael public int compare(Size size, Size size2) { 108b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael // sort area greatest to least 109b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael return Integer.compare(size2.width() * size2.height(), 110b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael size.width() * size.height()); 111b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael } 112b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael }); 113b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael maxPixels = sizes.get(0).width() * sizes.get(0).height(); 114b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael } 115b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael } 116b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael 117b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael /** 118b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * Given a list of camera sizes, this uses some heuristics to decide which 119b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * options to present to a user. It currently returns up to 3 sizes for each 120b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * aspect ratio. The aspect ratios returned include the ones in 121b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * sDesiredAspectRatios, and the largest full sensor ratio. T his guarantees 122b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * that users can use a full-sensor size, as well as any of the preferred 123b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * aspect ratios from above; 12408b3c94a7d7aff30b5da8e99649346e37b67a5c5Sascha Haeberling * 125b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * @param sizes A super set of all sizes to be displayed 126a4b0118d15d4a3c6b77827feb63c3809c61c0fcfSeth Raphael * @param isBackCamera true if these are sizes for the back camera 127b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * @return The list of sizes to display grouped first by aspect ratio 128b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * (sorted by maximum area), and sorted within aspect ratio by area) 129b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael */ 130a4b0118d15d4a3c6b77827feb63c3809c61c0fcfSeth Raphael public static List<Size> getDisplayableSizesFromSupported(List<Size> sizes, boolean isBackCamera) { 131a4b0118d15d4a3c6b77827feb63c3809c61c0fcfSeth Raphael List<ResolutionBucket> buckets = parseAvailableSizes(sizes, isBackCamera); 132b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael 133b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael List<Float> sortedDesiredAspectRatios = new ArrayList<Float>(); 134b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael // We want to make sure we support the maximum pixel aspect ratio, even 135b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael // if it doesn't match a desired aspect ratio 136b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael sortedDesiredAspectRatios.add(buckets.get(0).aspectRatio.floatValue()); 137b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael 138b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael // Now go through the buckets from largest mp to smallest, adding 139b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael // desired ratios 140b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael for (ResolutionBucket bucket : buckets) { 141b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael Float aspectRatio = bucket.aspectRatio; 142b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael if (Arrays.asList(sDesiredAspectRatios).contains(aspectRatio) 143b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael && !sortedDesiredAspectRatios.contains(aspectRatio)) { 144b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael sortedDesiredAspectRatios.add(aspectRatio); 145b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael } 146b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael } 147b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael 148b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael List<Size> result = new ArrayList<Size>(sizes.size()); 149b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael for (Float targetRatio : sortedDesiredAspectRatios) { 150b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael for (ResolutionBucket bucket : buckets) { 151b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael Number aspectRatio = bucket.aspectRatio; 1522272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu if (Math.abs(aspectRatio.floatValue() - targetRatio) <= ASPECT_RATIO_TOLERANCE) { 153b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael result.addAll(pickUpToThree(bucket.sizes)); 154b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael } 155b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael } 156b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael } 157b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael return result; 158b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael } 159b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael 160b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael /** 161b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * Get the area in pixels of a size. 16208b3c94a7d7aff30b5da8e99649346e37b67a5c5Sascha Haeberling * 163b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * @param size the size to measure 164b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * @return the area. 165b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael */ 166b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael private static int area(Size size) { 167b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael if (size == null) { 168b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael return 0; 169b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael } 170b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael return size.width() * size.height(); 171b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael } 172b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael 173b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael /** 174b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * Given a list of sizes of a similar aspect ratio, it tries to pick evenly 175b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * spaced out options. It starts with the largest, then tries to find one at 176b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * 50% of the last chosen size for the subsequent size. 17708b3c94a7d7aff30b5da8e99649346e37b67a5c5Sascha Haeberling * 178b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * @param sizes A list of Sizes that are all of a similar aspect ratio 179b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * @return A list of at least one, and no more than three representative 180b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * sizes from the list. 181b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael */ 182b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael private static List<Size> pickUpToThree(List<Size> sizes) { 183b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael List<Size> result = new ArrayList<Size>(); 184b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael Size largest = sizes.get(0); 185b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael result.add(largest); 186b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael Size lastSize = largest; 187b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael for (Size size : sizes) { 188b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael double targetArea = Math.pow(.5, result.size()) * area(largest); 189b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael if (area(size) < targetArea) { 190b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael // This candidate is smaller than half the mega pixels of the 191b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael // last one. Let's see whether the previous size, or this size 192b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael // is closer to the desired target. 193b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael if (!result.contains(lastSize) 194b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael && (targetArea - area(lastSize) < area(size) - targetArea)) { 195b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael result.add(lastSize); 196b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael } else { 197b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael result.add(size); 198b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael } 199b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael } 200b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael lastSize = size; 201b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael if (result.size() == 3) { 202b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael break; 203b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael } 204b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael } 205b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael 206b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael // If we have less than three, we can add the smallest size. 207b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael if (result.size() < 3 && !result.contains(lastSize)) { 208b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael result.add(lastSize); 209b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael } 210b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael return result; 211b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael } 212b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael 213b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael /** 214b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * Take an aspect ratio and squish it into a nearby desired aspect ratio, if 215b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * possible. 21608b3c94a7d7aff30b5da8e99649346e37b67a5c5Sascha Haeberling * 217b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * @param aspectRatio the aspect ratio to fuzz 2182272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu * @return the closest desiredAspectRatio within ASPECT_RATIO_TOLERANCE, or the 219b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * original ratio 220b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael */ 221b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael private static float fuzzAspectRatio(float aspectRatio) { 222b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael for (float desiredAspectRatio : sDesiredAspectRatios) { 2232272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu if ((Math.abs(aspectRatio - desiredAspectRatio)) < ASPECT_RATIO_TOLERANCE) { 224b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael return desiredAspectRatio; 225b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael } 226b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael } 227b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael return aspectRatio; 228b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael } 229b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael 230b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael /** 231b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * This takes a bunch of supported sizes and buckets them by aspect ratio. 232b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * The result is a list of buckets sorted by each bucket's largest area. 233b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * They are sorted from largest to smallest. This will bucket aspect ratios 234b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * that are close to the sDesiredAspectRatios in to the same bucket. 23508b3c94a7d7aff30b5da8e99649346e37b67a5c5Sascha Haeberling * 236b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * @param sizes all supported sizes for a camera 237a4b0118d15d4a3c6b77827feb63c3809c61c0fcfSeth Raphael * @param isBackCamera true if these are sizes for the back camera 238b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * @return all of the sizes grouped by their closest aspect ratio 239b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael */ 240a4b0118d15d4a3c6b77827feb63c3809c61c0fcfSeth Raphael private static List<ResolutionBucket> parseAvailableSizes(List<Size> sizes, boolean isBackCamera) { 241b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael HashMap<Float, ResolutionBucket> aspectRatioToBuckets = new HashMap<Float, ResolutionBucket>(); 242b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael 243b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael for (Size size : sizes) { 2442272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu Float aspectRatio = (float) size.getWidth() / (float) size.getHeight(); 245b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael // If this aspect ratio is close to a desired Aspect Ratio, 246b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael // fuzz it so that they are bucketed together 247b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael aspectRatio = fuzzAspectRatio(aspectRatio); 248b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael ResolutionBucket bucket = aspectRatioToBuckets.get(aspectRatio); 249b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael if (bucket == null) { 250b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael bucket = new ResolutionBucket(); 251b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael bucket.aspectRatio = aspectRatio; 252b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael aspectRatioToBuckets.put(aspectRatio, bucket); 253b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael } 254b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael bucket.add(size); 255b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael } 256a4b0118d15d4a3c6b77827feb63c3809c61c0fcfSeth Raphael if (ApiHelper.IS_NEXUS_5 && isBackCamera) { 257454d63f617489281971fb151abfe14730209c047Angus Kong aspectRatioToBuckets.get(16 / 9.0f).add(NEXUS_5_LARGE_16_BY_9_SIZE); 258454d63f617489281971fb151abfe14730209c047Angus Kong } 259b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael List<ResolutionBucket> sortedBuckets = new ArrayList<ResolutionBucket>( 260b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael aspectRatioToBuckets.values()); 261b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael Collections.sort(sortedBuckets, new Comparator<ResolutionBucket>() { 262b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael @Override 263b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael public int compare(ResolutionBucket resolutionBucket, ResolutionBucket resolutionBucket2) { 264b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael return Integer.compare(resolutionBucket2.maxPixels, resolutionBucket.maxPixels); 265b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael } 266b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael }); 267b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael return sortedBuckets; 268b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael } 269b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael 270b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael /** 271b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * Given a size, return a string describing the aspect ratio by reducing the 27208b3c94a7d7aff30b5da8e99649346e37b67a5c5Sascha Haeberling * 273b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * @param size the size to describe 274b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael * @return a string description of the aspect ratio 275b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael */ 276b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael public static String aspectRatioDescription(Size size) { 2771cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael Size aspectRatio = reduce(size); 2781cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael return aspectRatio.width() + "x" + aspectRatio.height(); 2791cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael } 2801cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael 2811cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael /** 2821cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael * Reduce an aspect ratio to its lowest common denominator. The ratio of the 2831cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael * input and output sizes is guaranteed to be the same. 28408b3c94a7d7aff30b5da8e99649346e37b67a5c5Sascha Haeberling * 2851cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael * @param aspectRatio the aspect ratio to reduce 2861cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael * @return The reduced aspect ratio which may equal the original. 2871cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael */ 2881cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael public static Size reduce(Size aspectRatio) { 2891cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael BigInteger width = BigInteger.valueOf(aspectRatio.width()); 2901cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael BigInteger height = BigInteger.valueOf(aspectRatio.height()); 291b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael BigInteger gcd = width.gcd(height); 292b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael int numerator = Math.max(width.intValue(), height.intValue()) / gcd.intValue(); 293b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael int denominator = Math.min(width.intValue(), height.intValue()) / gcd.intValue(); 2941cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael return new Size(numerator, denominator); 295b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael } 296d074fffd7c85df39893125f29fb3d487864feaf1Seth Raphael 297d074fffd7c85df39893125f29fb3d487864feaf1Seth Raphael /** 298d074fffd7c85df39893125f29fb3d487864feaf1Seth Raphael * Given a size return the numerator of its aspect ratio 29908b3c94a7d7aff30b5da8e99649346e37b67a5c5Sascha Haeberling * 300d074fffd7c85df39893125f29fb3d487864feaf1Seth Raphael * @param size the size to measure 301d074fffd7c85df39893125f29fb3d487864feaf1Seth Raphael * @return the numerator 302d074fffd7c85df39893125f29fb3d487864feaf1Seth Raphael */ 303d074fffd7c85df39893125f29fb3d487864feaf1Seth Raphael public static int aspectRatioNumerator(Size size) { 3041cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael Size aspectRatio = reduce(size); 3051cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael return aspectRatio.width(); 3061cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael } 3071cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael 3081cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael /** 3091cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael * Given a size, return the closest aspect ratio that falls close to the 3101cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael * given size. 31108b3c94a7d7aff30b5da8e99649346e37b67a5c5Sascha Haeberling * 3121cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael * @param size the size to approximate 3131cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael * @return the closest desired aspect ratio, or the original aspect ratio if 3141cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael * none were close enough 3151cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael */ 3161cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael public static Size getApproximateSize(Size size) { 3171cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael Size aspectRatio = reduce(size); 3181cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael float fuzzy = fuzzAspectRatio(size.width() / (float) size.height()); 3191cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael int index = Arrays.asList(sDesiredAspectRatios).indexOf(fuzzy); 3201cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael if (index != -1) { 3212272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu aspectRatio = sDesiredAspectRatioSizes[index]; 3221cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael } 3231cced0e893b6a2f37d447a049c1c3c08affd2d41Seth Raphael return aspectRatio; 324d074fffd7c85df39893125f29fb3d487864feaf1Seth Raphael } 325d074fffd7c85df39893125f29fb3d487864feaf1Seth Raphael 326d074fffd7c85df39893125f29fb3d487864feaf1Seth Raphael /** 327d074fffd7c85df39893125f29fb3d487864feaf1Seth Raphael * Given a size return the numerator of its aspect ratio 32808b3c94a7d7aff30b5da8e99649346e37b67a5c5Sascha Haeberling * 329d074fffd7c85df39893125f29fb3d487864feaf1Seth Raphael * @param size 330d074fffd7c85df39893125f29fb3d487864feaf1Seth Raphael * @return the denominator 331d074fffd7c85df39893125f29fb3d487864feaf1Seth Raphael */ 332d074fffd7c85df39893125f29fb3d487864feaf1Seth Raphael public static int aspectRatioDenominator(Size size) { 333d074fffd7c85df39893125f29fb3d487864feaf1Seth Raphael BigInteger width = BigInteger.valueOf(size.width()); 334d074fffd7c85df39893125f29fb3d487864feaf1Seth Raphael BigInteger height = BigInteger.valueOf(size.height()); 335d074fffd7c85df39893125f29fb3d487864feaf1Seth Raphael BigInteger gcd = width.gcd(height); 336d074fffd7c85df39893125f29fb3d487864feaf1Seth Raphael int denominator = Math.min(width.intValue(), height.intValue()) / gcd.intValue(); 337d074fffd7c85df39893125f29fb3d487864feaf1Seth Raphael return denominator; 338d074fffd7c85df39893125f29fb3d487864feaf1Seth Raphael } 339d074fffd7c85df39893125f29fb3d487864feaf1Seth Raphael 3402272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu /** 3412272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu * Returns the aspect ratio for the given size. 3422272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu * 3432272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu * @param size The given size. 3442272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu * @return A {@link Rational} which represents the aspect ratio. 3452272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu */ 3462272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu public static Rational getAspectRatio(Size size) { 3472272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu int width = size.getWidth(); 3482272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu int height = size.getHeight(); 3492272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu int numerator = width; 3502272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu int denominator = height; 3512272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu if (height > width) { 3522272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu numerator = height; 3532272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu denominator = width; 3542272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu } 3552272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu return new Rational(numerator, denominator); 3562272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu } 3572272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu 3582272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu public static boolean hasSameAspectRatio(Rational ar1, Rational ar2) { 3592272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu return Math.abs(ar1.toDouble() - ar2.toDouble()) < ASPECT_RATIO_TOLERANCE; 3602272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu } 3612272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu 3622272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu /** 3638d8b329da25456adb5ee45e0450680654114e125I-Jong Lin * Selects the maximal resolution for the given desired aspect ratio from all available 3648d8b329da25456adb5ee45e0450680654114e125I-Jong Lin * resolutions. If no resolution exists for the desired aspect ratio, return a resolution 3658d8b329da25456adb5ee45e0450680654114e125I-Jong Lin * with the maximum number of pixels. 3662272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu * 3672272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu * @param desiredAspectRatio The desired aspect ratio. 3682272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu * @param sizes All available resolutions. 3698d8b329da25456adb5ee45e0450680654114e125I-Jong Lin * @return The maximal resolution for desired aspect ratio ; if no sizes are found, then 3708d8b329da25456adb5ee45e0450680654114e125I-Jong Lin * return size of (0,0) 3712272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu */ 3722272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu public static Size getLargestPictureSize(Rational desiredAspectRatio, List<Size> sizes) { 3738d8b329da25456adb5ee45e0450680654114e125I-Jong Lin int maxPixelNumNoAspect = 0; 3742272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu Size maxSize = new Size(0, 0); 3758d8b329da25456adb5ee45e0450680654114e125I-Jong Lin 3768d8b329da25456adb5ee45e0450680654114e125I-Jong Lin // Fix for b/21758681 3778d8b329da25456adb5ee45e0450680654114e125I-Jong Lin // Do first pass with the candidate with closest size, regardless of aspect ratio, 3788d8b329da25456adb5ee45e0450680654114e125I-Jong Lin // to loosen the requirement of valid preview sizes. As long as one size exists 3798d8b329da25456adb5ee45e0450680654114e125I-Jong Lin // in the list, we should pass back a valid size. 3808d8b329da25456adb5ee45e0450680654114e125I-Jong Lin for (Size size : sizes) { 3818d8b329da25456adb5ee45e0450680654114e125I-Jong Lin int pixelNum = size.getWidth() * size.getHeight(); 3828d8b329da25456adb5ee45e0450680654114e125I-Jong Lin if (pixelNum > maxPixelNumNoAspect) { 3838d8b329da25456adb5ee45e0450680654114e125I-Jong Lin maxPixelNumNoAspect = pixelNum; 3848d8b329da25456adb5ee45e0450680654114e125I-Jong Lin maxSize = size; 3858d8b329da25456adb5ee45e0450680654114e125I-Jong Lin } 3868d8b329da25456adb5ee45e0450680654114e125I-Jong Lin } 3878d8b329da25456adb5ee45e0450680654114e125I-Jong Lin 3888d8b329da25456adb5ee45e0450680654114e125I-Jong Lin // With second pass, override first pass with the candidate with closest 3898d8b329da25456adb5ee45e0450680654114e125I-Jong Lin // size AND similar aspect ratio. If there are no valid candidates are found 3908d8b329da25456adb5ee45e0450680654114e125I-Jong Lin // in the second pass, take the candidate from the first pass. 3918d8b329da25456adb5ee45e0450680654114e125I-Jong Lin int maxPixelNumWithAspect = 0; 3922272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu for (Size size : sizes) { 3932272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu Rational aspectRatio = getAspectRatio(size); 3942272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu // Skip if the aspect ratio is not desired. 3952272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu if (!hasSameAspectRatio(aspectRatio, desiredAspectRatio)) { 3962272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu continue; 3972272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu } 3982272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu int pixelNum = size.getWidth() * size.getHeight(); 3998d8b329da25456adb5ee45e0450680654114e125I-Jong Lin if (pixelNum > maxPixelNumWithAspect) { 4008d8b329da25456adb5ee45e0450680654114e125I-Jong Lin maxPixelNumWithAspect = pixelNum; 4012272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu maxSize = size; 4022272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu } 4032272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu } 4048d8b329da25456adb5ee45e0450680654114e125I-Jong Lin 4052272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu return maxSize; 4062272f8a6bfc8adca8ada7a215bef038d45256085Senpo Hu } 407fb0496133a0b4b526dc70f6447bd4b97d95de95fSenpo Hu 408fb0496133a0b4b526dc70f6447bd4b97d95de95fSenpo Hu public static DisplayMetrics getDisplayMetrics(Context context) { 409fb0496133a0b4b526dc70f6447bd4b97d95de95fSenpo Hu DisplayMetrics displayMetrics = new DisplayMetrics(); 4108be316c7a8caf962cf3fcf5e49d332fb2718319fPaul Rohde WindowManager wm = AndroidServices.instance().provideWindowManager(); 411fb0496133a0b4b526dc70f6447bd4b97d95de95fSenpo Hu if (wm != null) { 412fb0496133a0b4b526dc70f6447bd4b97d95de95fSenpo Hu wm.getDefaultDisplay().getMetrics(displayMetrics); 413fb0496133a0b4b526dc70f6447bd4b97d95de95fSenpo Hu } 414fb0496133a0b4b526dc70f6447bd4b97d95de95fSenpo Hu return displayMetrics; 415fb0496133a0b4b526dc70f6447bd4b97d95de95fSenpo Hu } 416fb0496133a0b4b526dc70f6447bd4b97d95de95fSenpo Hu 41786d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling /** 41886d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling * Takes selected sizes and a list of blacklisted sizes. All the blacklistes 41986d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling * sizes will be removed from the 'sizes' list. 42086d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling * 42186d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling * @param sizes the sizes to be filtered. 42286d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling * @param blacklistString a String containing a comma-separated list of 42386d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling * sizes that should be removed from the original list. 42486d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling * @return A list that contains the filtered items. 42586d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling */ 42686d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling @ParametersAreNonnullByDefault 42786d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling public static List<Size> filterBlackListedSizes(List<Size> sizes, String blacklistString) { 42886d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling String[] blacklistStringArray = blacklistString.split(","); 42986d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling if (blacklistStringArray.length == 0) { 43086d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling return sizes; 43186d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling } 43286d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling 43386d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling Set<String> blacklistedSizes = new HashSet(Lists.newArrayList(blacklistStringArray)); 43486d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling List<Size> newSizeList = new ArrayList<>(); 43586d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling for (Size size : sizes) { 43686d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling if (!isBlackListed(size, blacklistedSizes)) { 43786d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling newSizeList.add(size); 43886d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling } 43986d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling } 44086d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling return newSizeList; 44186d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling } 44286d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling 44386d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling /** 44486d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling * Returns whether the given size is within the blacklist string. 44586d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling * 44686d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling * @param size the size to check 44786d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling * @param blacklistString a String containing a comma-separated list of 44886d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling * sizes that should not be available on the device. 44986d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling * @return Whether the given size is blacklisted. 45086d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling */ 4511d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde public static boolean isBlackListed(@Nonnull Size size, @Nonnull String blacklistString) { 45286d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling String[] blacklistStringArray = blacklistString.split(","); 45386d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling if (blacklistStringArray.length == 0) { 45486d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling return false; 45586d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling } 45686d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling Set<String> blacklistedSizes = new HashSet(Lists.newArrayList(blacklistStringArray)); 45786d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling return isBlackListed(size, blacklistedSizes); 45886d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling } 45986d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling 4601d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde private static boolean isBlackListed(@Nonnull Size size, @Nonnull Set<String> blacklistedSizes) { 46186d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling String sizeStr = size.getWidth() + "x" + size.getHeight(); 46286d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling return blacklistedSizes.contains(sizeStr); 46386d753fcbb0c7474fa9b2797e76e31ef575e76cdSascha Haeberling } 464b19eaa0bb37a1252015eafd3e965a011e6e98727Seth Raphael} 465