1 /*
<lambda>null2  * Copyright (C) 2016 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.systemui.shared.recents.model
17 
18 import android.app.WindowConfiguration
19 import android.content.res.Configuration
20 import android.graphics.Bitmap
21 import android.graphics.Bitmap.Config.ARGB_8888
22 import android.graphics.Color
23 import android.graphics.Rect
24 import android.util.Log
25 import android.view.WindowInsetsController.Appearance
26 import android.window.TaskSnapshot
27 
28 /** Data for a single thumbnail. */
29 data class ThumbnailData(
30     val thumbnail: Bitmap? = null,
31     var orientation: Int = Configuration.ORIENTATION_UNDEFINED,
32     @JvmField var rotation: Int = WindowConfiguration.ROTATION_UNDEFINED,
33     @JvmField var insets: Rect = Rect(),
34     @JvmField var letterboxInsets: Rect = Rect(),
35     @JvmField var reducedResolution: Boolean = false,
36     @JvmField var isRealSnapshot: Boolean = true,
37     var isTranslucent: Boolean = false,
38     @JvmField var windowingMode: Int = WindowConfiguration.WINDOWING_MODE_UNDEFINED,
39     @JvmField @Appearance var appearance: Int = 0,
40     @JvmField var scale: Float = 1f,
41     var snapshotId: Long = 0,
42 ) {
43     fun recycleBitmap() {
44         thumbnail?.recycle()
45     }
46 
47     companion object {
48         private fun makeThumbnail(snapshot: TaskSnapshot): Bitmap {
49             var thumbnail: Bitmap? = null
50             try {
51                 snapshot.hardwareBuffer?.use { buffer ->
52                     thumbnail = Bitmap.wrapHardwareBuffer(buffer, snapshot.colorSpace)
53                 }
54             } catch (ex: IllegalArgumentException) {
55                 // TODO(b/157562905): Workaround for a crash when we get a snapshot without this
56                 // state
57                 Log.e(
58                     "ThumbnailData",
59                     "Unexpected snapshot without USAGE_GPU_SAMPLED_IMAGE: " +
60                         "${snapshot.hardwareBuffer}",
61                     ex
62                 )
63             }
64 
65             return thumbnail
66                 ?: Bitmap.createBitmap(snapshot.taskSize.x, snapshot.taskSize.y, ARGB_8888).apply {
67                     eraseColor(Color.BLACK)
68                 }
69         }
70 
71         @JvmStatic
72         fun wrap(taskIds: IntArray?, snapshots: Array<TaskSnapshot>?): HashMap<Int, ThumbnailData> {
73             return hashMapOf<Int, ThumbnailData>().apply {
74                 if (taskIds != null && snapshots != null && taskIds.size == snapshots.size) {
75                     repeat(snapshots.size) { put(taskIds[it], fromSnapshot(snapshots[it])) }
76                 }
77             }
78         }
79 
80         @JvmStatic
81         fun fromSnapshot(snapshot: TaskSnapshot): ThumbnailData {
82             val thumbnail = makeThumbnail(snapshot)
83             return ThumbnailData(
84                 thumbnail = thumbnail,
85                 insets = Rect(snapshot.contentInsets),
86                 letterboxInsets = Rect(snapshot.letterboxInsets),
87                 orientation = snapshot.orientation,
88                 rotation = snapshot.rotation,
89                 reducedResolution = snapshot.isLowResolution,
90                 // TODO(b/149579527): Pass task size instead of computing scale.
91                 // Assume width and height were scaled the same; compute scale only for width
92                 scale = thumbnail.width.toFloat() / snapshot.taskSize.x,
93                 isRealSnapshot = snapshot.isRealSnapshot,
94                 isTranslucent = snapshot.isTranslucent,
95                 windowingMode = snapshot.windowingMode,
96                 appearance = snapshot.appearance,
97                 snapshotId = snapshot.id,
98             )
99         }
100     }
101 }
102