• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.wallpaper.util;
17 
18 import android.app.Activity;
19 import android.content.Context;
20 import android.content.res.Resources;
21 import android.graphics.Point;
22 import android.graphics.drawable.GradientDrawable;
23 import android.util.DisplayMetrics;
24 import android.view.Display;
25 import android.view.View;
26 import android.view.WindowManager;
27 
28 import androidx.annotation.NonNull;
29 
30 import com.android.systemui.shared.system.QuickStepContract;
31 import com.android.wallpaper.R;
32 
33 /**
34  * Simple utility class that calculates various sizes relative to the display or current
35  * configuration.
36  */
37 public class SizeCalculator {
38     private static final int COLUMN_COUNT_THRESHOLD_DP = 732;
39 
40     /**
41      * The number of columns for a "fewer columns" configuration of the category tiles grid.
42      */
43     private static final int CATEGORY_FEWER_COLUMNS = 3;
44 
45     /**
46      * The number of columns for a "more columns" configuration of the category tiles grid.
47      */
48     private static final int CATEGORY_MORE_COLUMNS = 3;
49 
50     /**
51      * The number of columns for a "fewer columns" configuration of the featured category tiles
52      * grid.
53      */
54     private static final int FEATURED_CATEGORY_FEWER_COLUMNS = 2;
55 
56     /**
57      * The number of columns for a "more columns" configuration of the featured category tiles grid.
58      */
59     private static final int FEATURED_CATEGORY_MORE_COLUMNS = 2;
60 
61     /**
62      * The number of columns for a "fewer columns" configuration of the individual wallpaper tiles
63      * grid.
64      */
65     private static final int INDIVIDUAL_FEWER_COLUMNS = 3;
66 
67     /**
68      * The number of columns for a "more columns" configuration of the individual wallpaper tiles
69      * grid.
70      */
71     private static final int INDIVIDUAL_MORE_COLUMNS = 4;
72 
73     /**
74      * The number of columns for a "fewer columns" configuration of the featured individual
75      * wallpaper tiles grid.
76      */
77     private static final int FEATURED_INDIVIDUAL_FEWER_COLUMNS = 2;
78 
79     /**
80      * The number of columns for a "more columns" configuration of the featured individual wallpaper
81      * tiles grid.
82      */
83     private static final int FEATURED_INDIVIDUAL_MORE_COLUMNS = 2;
84 
85     // Suppress default constructor for noninstantiability.
SizeCalculator()86     private SizeCalculator() {
87         throw new AssertionError("Can't initialize a SizeCalculator.");
88     }
89 
90     /**
91      * Returns the number of columns for a grid of category tiles. Selects from fewer and more
92      * columns based on the width of the activity.
93      */
getNumCategoryColumns(@onNull Activity activity)94     public static int getNumCategoryColumns(@NonNull Activity activity) {
95         int windowWidthPx = getActivityWindowWidthPx(activity);
96         return getNumCategoryColumns(activity, windowWidthPx);
97     }
98 
99     /**
100      * Returns the number of columns for a grid of individual tiles. Selects from fewer and more
101      * columns based on the width of the activity.
102      */
getNumIndividualColumns(@onNull Activity activity)103     public static int getNumIndividualColumns(@NonNull Activity activity) {
104         int windowWidthPx = getActivityWindowWidthPx(activity);
105         return getNumIndividualColumns(activity, windowWidthPx);
106     }
107 
108     /**
109      * Returns the number of columns for a grid of featured individual tiles. Selects from fewer and
110      * more columns based on the width of the activity.
111      */
getNumFeaturedIndividualColumns(@onNull Activity activity)112     public static int getNumFeaturedIndividualColumns(@NonNull Activity activity) {
113         int windowWidthPx = getActivityWindowWidthPx(activity);
114         return getNumFeaturedIndividualColumns(activity, windowWidthPx);
115     }
116 
getNumCategoryColumns(Activity activity, int windowWidthPx)117     private static int getNumCategoryColumns(Activity activity, int windowWidthPx) {
118         return getNumColumns(activity, windowWidthPx, CATEGORY_FEWER_COLUMNS,
119                 CATEGORY_MORE_COLUMNS);
120     }
121 
getNumFeaturedCategoryColumns(Activity activity, int windowWidthPx)122     private static int getNumFeaturedCategoryColumns(Activity activity, int windowWidthPx) {
123         return getNumColumns(activity, windowWidthPx, FEATURED_CATEGORY_FEWER_COLUMNS,
124                 FEATURED_CATEGORY_MORE_COLUMNS);
125     }
126 
getNumIndividualColumns(Activity activity, int windowWidthPx)127     private static int getNumIndividualColumns(Activity activity, int windowWidthPx) {
128         return getNumColumns(
129                 activity, windowWidthPx, INDIVIDUAL_FEWER_COLUMNS, INDIVIDUAL_MORE_COLUMNS);
130     }
131 
getNumFeaturedIndividualColumns(Activity activity, int windowWidthPx)132     private static int getNumFeaturedIndividualColumns(Activity activity, int windowWidthPx) {
133         return getNumColumns(activity, windowWidthPx, FEATURED_INDIVIDUAL_FEWER_COLUMNS,
134                 FEATURED_INDIVIDUAL_MORE_COLUMNS);
135     }
136 
getNumColumns( Context context, int windowWidthPx, int fewerCount, int moreCount)137     private static int getNumColumns(
138             Context context, int windowWidthPx, int fewerCount, int moreCount) {
139         WindowManager windowManager = (WindowManager)
140                 context.getSystemService(Context.WINDOW_SERVICE);
141         Display display = windowManager.getDefaultDisplay();
142 
143         DisplayMetrics metrics = DisplayMetricsRetriever.getInstance()
144                 .getDisplayMetrics(context.getResources(), display);
145 
146         // Columns should be based on the size of the window, not the size of the display.
147         int windowWidthDp = (int) (windowWidthPx / metrics.density);
148 
149         if (windowWidthDp < COLUMN_COUNT_THRESHOLD_DP) {
150             return fewerCount;
151         } else {
152             return moreCount;
153         }
154     }
155 
156     /**
157      * Returns the size of a category grid tile in px.
158      */
getCategoryTileSize(@onNull Activity activity)159     public static Point getCategoryTileSize(@NonNull Activity activity) {
160         Resources res = activity.getResources();
161         int windowWidthPx = getActivityWindowWidthPx(activity);
162 
163         int columnCount = getNumCategoryColumns(activity, windowWidthPx);
164         return getSquareTileSize(columnCount, windowWidthPx,
165                 res.getDimensionPixelSize(R.dimen.grid_item_category_padding_horizontal),
166                 res.getDimensionPixelSize(R.dimen.category_grid_edge_space));
167     }
168 
169     /**
170      * Returns the size of a featured category grid tile in px.
171      */
getFeaturedCategoryTileSize(@onNull Activity activity)172     public static Point getFeaturedCategoryTileSize(@NonNull Activity activity) {
173         Resources res = activity.getResources();
174         int windowWidthPx = getActivityWindowWidthPx(activity);
175 
176         int columnCount = getNumFeaturedCategoryColumns(activity, windowWidthPx);
177         return getSquareTileSize(columnCount, windowWidthPx,
178                 res.getDimensionPixelSize(R.dimen.grid_item_category_padding_horizontal),
179                 res.getDimensionPixelSize(R.dimen.category_grid_edge_space));
180     }
181 
182     /**
183      * Returns the size of an individual grid tile for the given activity in px.
184      */
getIndividualTileSize(@onNull Activity activity)185     public static Point getIndividualTileSize(@NonNull Activity activity) {
186         Resources res = activity.getResources();
187         int windowWidthPx = getActivityWindowWidthPx(activity);
188 
189         int columnCount = getNumIndividualColumns(activity, windowWidthPx);
190         return getSquareTileSize(columnCount, windowWidthPx,
191                 res.getDimensionPixelSize(R.dimen.grid_item_individual_padding_horizontal),
192                 res.getDimensionPixelSize(R.dimen.wallpaper_grid_edge_space));
193     }
194 
195     /**
196      * Returns the size of a featured individual grid tile for the given activity in px.
197      */
getFeaturedIndividualTileSize(@onNull Activity activity)198     public static Point getFeaturedIndividualTileSize(@NonNull Activity activity) {
199         Resources res = activity.getResources();
200         int windowWidthPx = getActivityWindowWidthPx(activity);
201 
202         int columnCount = getNumFeaturedIndividualColumns(activity, windowWidthPx);
203         return getSquareTileSize(columnCount, windowWidthPx,
204                 res.getDimensionPixelSize(R.dimen.grid_item_featured_individual_padding_horizontal),
205                 res.getDimensionPixelSize(R.dimen.featured_wallpaper_grid_edge_space));
206     }
207 
208     /**
209      * Returns a suggested thumbnail tile size for images that may be presented either as a
210      * category or individual tile on any-sized activity on the device. This size matches the
211      * individual tile size when an activity takes up the entire screen's width.
212      */
getSuggestedThumbnailSize(@onNull Context appContext)213     public static Point getSuggestedThumbnailSize(@NonNull Context appContext) {
214         // Category tiles are larger than individual tiles, so get the number of columns for
215         // categories and then calculate a tile size for when the app window takes up the entire
216         // display.
217         int windowWidthPx = getDeviceDisplayWidthPx(appContext);
218         int columnCount = getNumColumns(
219                 appContext, windowWidthPx, INDIVIDUAL_FEWER_COLUMNS, INDIVIDUAL_MORE_COLUMNS);
220         return getTileSize(appContext, columnCount, windowWidthPx);
221     }
222 
223     /**
224      * Returns the corner radius to use in a wallpaper preview view so that it's proportional
225      * to the screen's corner radius
226      */
getPreviewCornerRadius(@onNull Activity activity, int previewWidth)227     public static float getPreviewCornerRadius(@NonNull Activity activity, int previewWidth) {
228         Point screenSize = ScreenSizeCalculator.getInstance().getScreenSize(
229                 activity.getWindowManager().getDefaultDisplay());
230 
231         return QuickStepContract.getWindowCornerRadius(activity)
232                 / ((float) screenSize.x / previewWidth);
233     }
234 
235     /**
236      * Returns the size of a grid tile with the given "fewer" count and "more" count, on the given
237      * display. The size is determined by these counts and by the aspect ratio of the display and is
238      * in units of px.
239      */
getTileSize(Context context, int columnCount, int windowWidthPx)240     private static Point getTileSize(Context context, int columnCount, int windowWidthPx) {
241         WindowManager windowManager = (WindowManager)
242                 context.getSystemService(Context.WINDOW_SERVICE);
243         Display display = windowManager.getDefaultDisplay();
244         Point screenSizePx = ScreenSizeCalculator.getInstance().getScreenSize(display);
245 
246         Resources res = context.getResources();
247         int gridPaddingPx = res.getDimensionPixelSize(R.dimen.grid_padding);
248 
249         // Note: don't need to multiply by density because getting the dimension from resources
250         // already does that.
251         int guttersWidthPx = (columnCount + 1) * gridPaddingPx;
252         int availableWidthPx = windowWidthPx - guttersWidthPx;
253 
254         int widthPx = Math.round((float) availableWidthPx / columnCount);
255         int heightPx = Math.round(((float) availableWidthPx / columnCount)
256                 //* screenSizePx.y / screenSizePx.x);
257                 * res.getDimensionPixelSize(R.dimen.grid_tile_aspect_height)
258                 / res.getDimensionPixelSize(R.dimen.grid_tile_aspect_width));
259         return new Point(widthPx, heightPx);
260     }
261 
262     /**
263      * Returns the size of a grid tile with the given "fewer" count and "more" count, on the given
264      * display. The size is determined by these counts with the aspect ratio of 1:1 and is in units
265      * of px.
266      */
getSquareTileSize(int columnCount, int windowWidthPx, int gridPaddingPx, int gridEdgeSpacePx)267     private static Point getSquareTileSize(int columnCount, int windowWidthPx, int gridPaddingPx,
268             int gridEdgeSpacePx) {
269         int availableWidthPx = windowWidthPx
270                 - gridPaddingPx * 2 * columnCount // Item's left and right padding * column count
271                 - gridEdgeSpacePx * 2; // Grid view's left and right edge's space
272         int widthPx = Math.round((float) availableWidthPx / columnCount);
273 
274         return new Point(widthPx, widthPx);
275     }
276 
277     /**
278      * Returns the available width of the activity window in pixels.
279      */
getActivityWindowWidthPx(Activity activity)280     private static int getActivityWindowWidthPx(Activity activity) {
281         Display display = activity.getWindowManager().getDefaultDisplay();
282 
283         Point outPoint = new Point();
284         display.getSize(outPoint);
285 
286         return outPoint.x;
287     }
288 
289     /**
290      * Returns the available width of the device's default display in pixels.
291      */
getDeviceDisplayWidthPx(Context appContext)292     private static int getDeviceDisplayWidthPx(Context appContext) {
293         WindowManager windowManager =
294                 (WindowManager) appContext.getSystemService(Context.WINDOW_SERVICE);
295         Display defaultDisplay = windowManager.getDefaultDisplay();
296 
297         Point outPoint = new Point();
298         defaultDisplay.getSize(outPoint);
299 
300         return outPoint.x;
301     }
302 
303     /**
304      * Adjusts the corner radius of the given view by doubling their current values
305      *
306      * @param view whose background is set to a GradientDrawable
307      */
adjustBackgroundCornerRadius(View view)308     public static void adjustBackgroundCornerRadius(View view) {
309         GradientDrawable background = (GradientDrawable) view.getBackground();
310         // Using try/catch because currently GradientDrawable has a bug where when the radii array
311         // is null, instead of getCornerRadii returning null, it throws NPE.
312         try {
313             float[] radii = background.getCornerRadii();
314             if (radii == null) {
315                 return;
316             }
317             for (int i = 0; i < radii.length; i++) {
318                 radii[i] *= 2f;
319             }
320             background = ((GradientDrawable) background.mutate());
321             background.setCornerRadii(radii);
322             view.setBackground(background);
323         } catch (NullPointerException e) {
324             //Ignore in this case, since it means the radius was 0.
325         }
326     }
327 }
328