• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.systemui.screenshot
18 
19 import android.app.IActivityTaskManager
20 import android.graphics.Bitmap
21 import android.graphics.Rect
22 import android.hardware.display.DisplayManager
23 import android.os.IBinder
24 import android.util.Log
25 import android.view.DisplayAddress
26 import android.view.SurfaceControl
27 import android.view.SurfaceControl.DisplayCaptureArgs
28 import android.view.SurfaceControl.ScreenshotHardwareBuffer
29 import androidx.annotation.VisibleForTesting
30 import com.android.systemui.dagger.SysUISingleton
31 import com.android.systemui.dagger.qualifiers.Background
32 import javax.inject.Inject
33 import kotlinx.coroutines.CoroutineDispatcher
34 import kotlinx.coroutines.withContext
35 
36 private const val TAG = "ImageCaptureImpl"
37 
38 @SysUISingleton
39 open class ImageCaptureImpl @Inject constructor(
40     private val displayManager: DisplayManager,
41     private val atmService: IActivityTaskManager,
42     @Background private val bgContext: CoroutineDispatcher
43 ) : ImageCapture {
44 
captureDisplaynull45     override fun captureDisplay(displayId: Int, crop: Rect?): Bitmap? {
46         val width = crop?.width() ?: 0
47         val height = crop?.height() ?: 0
48         val sourceCrop = crop ?: Rect()
49         val displayToken = physicalDisplayToken(displayId) ?: return null
50         val buffer = captureDisplay(displayToken, width, height, sourceCrop)
51 
52         return buffer?.asBitmap()
53     }
54 
captureTasknull55     override suspend fun captureTask(taskId: Int): Bitmap? {
56         val snapshot = withContext(bgContext) { atmService.takeTaskSnapshot(taskId) } ?: return null
57         return Bitmap.wrapHardwareBuffer(snapshot.hardwareBuffer, snapshot.colorSpace)
58     }
59 
60     @VisibleForTesting
physicalDisplayTokennull61     open fun physicalDisplayToken(displayId: Int): IBinder? {
62         val display = displayManager.getDisplay(displayId)
63         if (display == null) {
64             Log.e(TAG, "No display with id: $displayId")
65             return null
66         }
67         val address = display.address
68         if (address !is DisplayAddress.Physical) {
69             Log.e(TAG, "Display does not have a physical address: $display")
70             return null
71         }
72         return SurfaceControl.getPhysicalDisplayToken(address.physicalDisplayId)
73     }
74 
75     @VisibleForTesting
captureDisplaynull76     open fun captureDisplay(
77         displayToken: IBinder,
78         width: Int,
79         height: Int,
80         crop: Rect
81     ): ScreenshotHardwareBuffer? {
82         val captureArgs =
83             DisplayCaptureArgs.Builder(displayToken)
84                 .setSize(width, height)
85                 .setSourceCrop(crop)
86                 .build()
87         return SurfaceControl.captureDisplay(captureArgs)
88     }
89 }
90