• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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.settings.applications.credentials;
18 
19 import android.graphics.Bitmap;
20 import android.graphics.Canvas;
21 import android.graphics.ColorFilter;
22 import android.graphics.Paint;
23 import android.graphics.PaintFlagsDrawFilter;
24 import android.graphics.PixelFormat;
25 import android.graphics.Rect;
26 import android.graphics.drawable.BitmapDrawable;
27 import android.graphics.drawable.Drawable;
28 import android.graphics.drawable.PaintDrawable;
29 import android.util.DisplayMetrics;
30 
31 import androidx.annotation.NonNull;
32 
33 /** Handles resizing of images for CredMan settings. */
34 public class ImageUtils {
35 
36     /**
37      * Utility class to resize icons to match default icon size. Code is mostly borrowed from
38      * Launcher and ActivityPicker.
39      */
40     public static class IconResizer {
41         private final int mIconWidth;
42         private final int mIconHeight;
43 
44         private final DisplayMetrics mMetrics;
45         private final Rect mOldBounds = new Rect();
46         private final Canvas mCanvas = new Canvas();
47 
IconResizer(int width, int height, DisplayMetrics metrics)48         public IconResizer(int width, int height, DisplayMetrics metrics) {
49             mCanvas.setDrawFilter(
50                     new PaintFlagsDrawFilter(Paint.DITHER_FLAG, Paint.FILTER_BITMAP_FLAG));
51 
52             mMetrics = metrics;
53             mIconWidth = width;
54             mIconHeight = height;
55         }
56 
57         /**
58          * Returns a Drawable representing the thumbnail of the specified Drawable. The size of the
59          * thumbnail is defined by the dimension android.R.dimen.app_icon_size.
60          *
61          * <p>This method is not thread-safe and should be invoked on the UI thread only.
62          *
63          * @param icon The icon to get a thumbnail of.
64          * @return A thumbnail for the specified icon or the icon itself if the thumbnail could not
65          *     be created.
66          */
createIconThumbnail(Drawable icon)67         public Drawable createIconThumbnail(Drawable icon) {
68             int width = mIconWidth;
69             int height = mIconHeight;
70 
71             if (icon == null) {
72                 return new EmptyDrawable(width, height);
73             }
74 
75             try {
76                 if (icon instanceof PaintDrawable) {
77                     PaintDrawable painter = (PaintDrawable) icon;
78                     painter.setIntrinsicWidth(width);
79                     painter.setIntrinsicHeight(height);
80                 } else if (icon instanceof BitmapDrawable) {
81                     // Ensure the bitmap has a density.
82                     BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
83                     Bitmap bitmap = bitmapDrawable.getBitmap();
84                     if (bitmap.getDensity() == Bitmap.DENSITY_NONE) {
85                         bitmapDrawable.setTargetDensity(mMetrics);
86                     }
87                 }
88                 int iconWidth = icon.getIntrinsicWidth();
89                 int iconHeight = icon.getIntrinsicHeight();
90 
91                 if (iconWidth > 0 && iconHeight > 0) {
92                     if (width < iconWidth || height < iconHeight) {
93                         final float ratio = (float) iconWidth / iconHeight;
94 
95                         if (iconWidth > iconHeight) {
96                             height = (int) (width / ratio);
97                         } else if (iconHeight > iconWidth) {
98                             width = (int) (height * ratio);
99                         }
100 
101                         final Bitmap.Config c =
102                                 icon.getOpacity() != PixelFormat.OPAQUE
103                                         ? Bitmap.Config.ARGB_8888
104                                         : Bitmap.Config.RGB_565;
105                         final Bitmap thumb = Bitmap.createBitmap(mIconWidth, mIconHeight, c);
106                         final Canvas canvas = mCanvas;
107                         canvas.setBitmap(thumb);
108 
109                         // Copy the old bounds to restore them later
110                         // If we were to do oldBounds = icon.getBounds(),
111                         // the call to setBounds() that follows would
112                         // change the same instance and we would lose the
113                         // old bounds.
114                         mOldBounds.set(icon.getBounds());
115                         final int x = (mIconWidth - width) / 2;
116                         final int y = (mIconHeight - height) / 2;
117                         icon.setBounds(x, y, x + width, y + height);
118                         icon.draw(canvas);
119                         icon.setBounds(mOldBounds);
120 
121                         // Create the new resized drawable.
122                         icon = createBitmapDrawable(thumb);
123                     } else if (iconWidth < width && iconHeight < height) {
124                         final Bitmap.Config c = Bitmap.Config.ARGB_8888;
125                         final Bitmap thumb = Bitmap.createBitmap(mIconWidth, mIconHeight, c);
126                         final Canvas canvas = mCanvas;
127                         canvas.setBitmap(thumb);
128                         mOldBounds.set(icon.getBounds());
129 
130                         // Set the bounds for the new icon.
131                         final int x = (width - iconWidth) / 2;
132                         final int y = (height - iconHeight) / 2;
133                         icon.setBounds(x, y, x + iconWidth, y + iconHeight);
134                         icon.draw(canvas);
135                         icon.setBounds(mOldBounds);
136 
137                         // Create the new resized drawable.
138                         icon = createBitmapDrawable(thumb);
139                     }
140                 }
141 
142             } catch (Throwable t) {
143                 icon = new EmptyDrawable(width, height);
144             }
145 
146             return icon;
147         }
148 
createBitmapDrawable(Bitmap thumb)149         private BitmapDrawable createBitmapDrawable(Bitmap thumb) {
150             BitmapDrawable icon = new BitmapDrawable(thumb);
151             icon.setTargetDensity(mMetrics);
152             mCanvas.setBitmap(null);
153             return icon;
154         }
155     }
156 
157     public static class EmptyDrawable extends Drawable {
158         private final int mWidth;
159         private final int mHeight;
160 
EmptyDrawable(int width, int height)161         EmptyDrawable(int width, int height) {
162             mWidth = width;
163             mHeight = height;
164         }
165 
166         @Override
getIntrinsicWidth()167         public int getIntrinsicWidth() {
168             return mWidth;
169         }
170 
171         @Override
getIntrinsicHeight()172         public int getIntrinsicHeight() {
173             return mHeight;
174         }
175 
176         @Override
getMinimumWidth()177         public int getMinimumWidth() {
178             return mWidth;
179         }
180 
181         @Override
getMinimumHeight()182         public int getMinimumHeight() {
183             return mHeight;
184         }
185 
186         @Override
draw(@onNull Canvas canvas)187         public void draw(@NonNull Canvas canvas) {}
188 
189         @Override
setAlpha(int alpha)190         public void setAlpha(int alpha) {}
191 
192         @Override
setColorFilter(@onNull ColorFilter cf)193         public void setColorFilter(@NonNull ColorFilter cf) {}
194 
195         @Override
getOpacity()196         public int getOpacity() {
197             return PixelFormat.TRANSLUCENT;
198         }
199     }
200 }
201