1 /*
2  * Copyright (C) 2023 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 android.content.pm;
18 
19 import android.annotation.FlaggedApi;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.content.ComponentName;
23 import android.graphics.Bitmap;
24 import android.graphics.Canvas;
25 import android.graphics.drawable.BitmapDrawable;
26 import android.graphics.drawable.Drawable;
27 import android.util.Slog;
28 
29 import com.android.internal.util.DataClass;
30 
31 import java.io.ByteArrayInputStream;
32 import java.io.ByteArrayOutputStream;
33 import java.io.IOException;
34 import java.util.Objects;
35 
36 /**
37  * Contains fields required to show archived package in Launcher.
38  * @see ArchivedPackageInfo
39  */
40 @DataClass(genBuilder = false, genConstructor = false, genSetters = true)
41 @FlaggedApi(Flags.FLAG_ARCHIVING)
42 public final class ArchivedActivityInfo {
43     private static final String TAG = "ArchivedActivityInfo";
44     /** The label for the activity. */
45     private @NonNull CharSequence mLabel;
46     /** The component name of this activity. */
47     private @NonNull ComponentName mComponentName;
48     /**
49      * Icon of the activity in the app's locale. if null then the default icon would be shown in the
50      * launcher.
51      */
52     private @Nullable Drawable mIcon;
53     /** Monochrome icon, if defined, of the activity. */
54     private @Nullable Drawable mMonochromeIcon;
55 
ArchivedActivityInfo(@onNull CharSequence label, @NonNull ComponentName componentName)56     public ArchivedActivityInfo(@NonNull CharSequence label, @NonNull ComponentName componentName) {
57         Objects.requireNonNull(label);
58         Objects.requireNonNull(componentName);
59         mLabel = label;
60         mComponentName = componentName;
61     }
62 
63     /* @hide */
ArchivedActivityInfo(@onNull ArchivedActivityParcel parcel)64     ArchivedActivityInfo(@NonNull ArchivedActivityParcel parcel) {
65         mLabel = parcel.title;
66         mComponentName = parcel.originalComponentName;
67         mIcon = drawableFromCompressedBitmap(parcel.iconBitmap);
68         mMonochromeIcon = drawableFromCompressedBitmap(parcel.monochromeIconBitmap);
69     }
70 
71     /* @hide */
getParcel()72     @NonNull ArchivedActivityParcel getParcel() {
73         var parcel = new ArchivedActivityParcel();
74         parcel.title = mLabel.toString();
75         parcel.originalComponentName = mComponentName;
76         parcel.iconBitmap = mIcon == null ? null :
77                 bytesFromBitmap(drawableToBitmap(mIcon));
78         parcel.monochromeIconBitmap = mMonochromeIcon == null ? null :
79                 bytesFromBitmap(drawableToBitmap(mMonochromeIcon));
80         return parcel;
81     }
82 
83     /**
84      * Convert a generic drawable into a bitmap.
85      * @hide
86      */
drawableToBitmap(Drawable drawable)87     public static Bitmap drawableToBitmap(Drawable drawable) {
88         return drawableToBitmap(drawable, /* iconSize= */ 0);
89     }
90 
91     /**
92      * Same as above, but scale the resulting image to fit iconSize.
93      * @hide
94      */
drawableToBitmap(Drawable drawable, int iconSize)95     public static Bitmap drawableToBitmap(Drawable drawable, int iconSize) {
96         Bitmap bitmap;
97         if (drawable instanceof BitmapDrawable) {
98             bitmap = ((BitmapDrawable) drawable).getBitmap();
99         } else {
100             if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
101                 // Needed for drawables that are just a single color.
102                 bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
103             } else {
104                 bitmap =
105                     Bitmap.createBitmap(
106                         drawable.getIntrinsicWidth(),
107                         drawable.getIntrinsicHeight(),
108                         Bitmap.Config.ARGB_8888);
109             }
110 
111             Canvas canvas = new Canvas(bitmap);
112             drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
113             drawable.draw(canvas);
114         }
115         if (iconSize <= 0) {
116             return bitmap;
117         }
118 
119         if (bitmap.getWidth() < iconSize || bitmap.getHeight() < iconSize
120                 || bitmap.getWidth() > iconSize * 2 || bitmap.getHeight() > iconSize * 2) {
121             var scaledBitmap = Bitmap.createScaledBitmap(bitmap, iconSize, iconSize, true);
122             if (scaledBitmap != bitmap) {
123                 bitmap.recycle();
124             }
125             return scaledBitmap;
126         }
127         return bitmap;
128     }
129 
130     /**
131      * Compress bitmap to PNG format.
132      * @hide
133      */
bytesFromBitmap(Bitmap bitmap)134     public static byte[] bytesFromBitmap(Bitmap bitmap) {
135         if (bitmap == null) {
136             return null;
137         }
138 
139         try (ByteArrayOutputStream baos = new ByteArrayOutputStream(
140                 bitmap.getByteCount())) {
141             bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
142             return baos.toByteArray();
143         } catch (IOException e) {
144             Slog.e(TAG, "Failed to compress bitmap", e);
145             return null;
146         }
147     }
148 
drawableFromCompressedBitmap(byte[] bytes)149     private static Drawable drawableFromCompressedBitmap(byte[] bytes) {
150         if (bytes == null) {
151             return null;
152         }
153         return new BitmapDrawable(null /*res*/, new ByteArrayInputStream(bytes));
154     }
155 
156 
157 
158     // Code below generated by codegen v1.0.23.
159     //
160     // DO NOT MODIFY!
161     // CHECKSTYLE:OFF Generated code
162     //
163     // To regenerate run:
164     // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/ArchivedActivityInfo.java
165     //
166     // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
167     //   Settings > Editor > Code Style > Formatter Control
168     //@formatter:off
169 
170 
171     /**
172      * The label for the activity.
173      */
174     @DataClass.Generated.Member
getLabel()175     public @NonNull CharSequence getLabel() {
176         return mLabel;
177     }
178 
179     /**
180      * The component name of this activity.
181      */
182     @DataClass.Generated.Member
getComponentName()183     public @NonNull ComponentName getComponentName() {
184         return mComponentName;
185     }
186 
187     /**
188      * Icon of the activity in the app's locale. if null then the default icon would be shown in the
189      * launcher.
190      */
191     @DataClass.Generated.Member
getIcon()192     public @Nullable Drawable getIcon() {
193         return mIcon;
194     }
195 
196     /**
197      * Monochrome icon, if defined, of the activity.
198      */
199     @DataClass.Generated.Member
getMonochromeIcon()200     public @Nullable Drawable getMonochromeIcon() {
201         return mMonochromeIcon;
202     }
203 
204     /**
205      * The label for the activity.
206      */
207     @DataClass.Generated.Member
setLabel(@onNull CharSequence value)208     public @NonNull ArchivedActivityInfo setLabel(@NonNull CharSequence value) {
209         mLabel = value;
210         com.android.internal.util.AnnotationValidations.validate(
211                 NonNull.class, null, mLabel);
212         return this;
213     }
214 
215     /**
216      * The component name of this activity.
217      */
218     @DataClass.Generated.Member
setComponentName(@onNull ComponentName value)219     public @NonNull ArchivedActivityInfo setComponentName(@NonNull ComponentName value) {
220         mComponentName = value;
221         com.android.internal.util.AnnotationValidations.validate(
222                 NonNull.class, null, mComponentName);
223         return this;
224     }
225 
226     /**
227      * Icon of the activity in the app's locale. if null then the default icon would be shown in the
228      * launcher.
229      */
230     @DataClass.Generated.Member
setIcon(@onNull Drawable value)231     public @NonNull ArchivedActivityInfo setIcon(@NonNull Drawable value) {
232         mIcon = value;
233         return this;
234     }
235 
236     /**
237      * Monochrome icon, if defined, of the activity.
238      */
239     @DataClass.Generated.Member
setMonochromeIcon(@onNull Drawable value)240     public @NonNull ArchivedActivityInfo setMonochromeIcon(@NonNull Drawable value) {
241         mMonochromeIcon = value;
242         return this;
243     }
244 
245     @DataClass.Generated(
246             time = 1708042076897L,
247             codegenVersion = "1.0.23",
248             sourceFile = "frameworks/base/core/java/android/content/pm/ArchivedActivityInfo.java",
249             inputSignatures = "private static final  java.lang.String TAG\nprivate @android.annotation.NonNull java.lang.CharSequence mLabel\nprivate @android.annotation.NonNull android.content.ComponentName mComponentName\nprivate @android.annotation.Nullable android.graphics.drawable.Drawable mIcon\nprivate @android.annotation.Nullable android.graphics.drawable.Drawable mMonochromeIcon\n @android.annotation.NonNull android.content.pm.ArchivedActivityParcel getParcel()\npublic static  android.graphics.Bitmap drawableToBitmap(android.graphics.drawable.Drawable)\npublic static  android.graphics.Bitmap drawableToBitmap(android.graphics.drawable.Drawable,int)\npublic static  byte[] bytesFromBitmap(android.graphics.Bitmap)\nprivate static  android.graphics.drawable.Drawable drawableFromCompressedBitmap(byte[])\nclass ArchivedActivityInfo extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=false, genConstructor=false, genSetters=true)")
250     @Deprecated
__metadata()251     private void __metadata() {}
252 
253 
254     //@formatter:on
255     // End of generated code
256 
257 }
258