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.mediaprojection.appselector.view 18 19 import android.content.Context 20 import android.content.res.Configuration 21 import android.graphics.Rect 22 import android.view.WindowInsets.Type 23 import android.view.WindowManager 24 import androidx.lifecycle.DefaultLifecycleObserver 25 import androidx.lifecycle.LifecycleOwner 26 import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorScope 27 import com.android.systemui.mediaprojection.appselector.view.TaskPreviewSizeProvider.TaskPreviewSizeListener 28 import com.android.systemui.shared.recents.utilities.Utilities.isLargeScreen 29 import com.android.systemui.statusbar.policy.CallbackController 30 import com.android.systemui.statusbar.policy.ConfigurationController 31 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener 32 import javax.inject.Inject 33 34 @MediaProjectionAppSelectorScope 35 class TaskPreviewSizeProvider 36 @Inject 37 constructor( 38 private val context: Context, 39 private val windowManager: WindowManager, 40 private val configurationController: ConfigurationController, 41 ) : CallbackController<TaskPreviewSizeListener>, ConfigurationListener, DefaultLifecycleObserver { 42 43 /** Returns the size of the task preview on the screen in pixels */ 44 val size: Rect = calculateSize() 45 46 private val listeners = arrayListOf<TaskPreviewSizeListener>() 47 48 override fun onCreate(owner: LifecycleOwner) { 49 configurationController.addCallback(this) 50 } 51 52 override fun onDestroy(owner: LifecycleOwner) { 53 configurationController.removeCallback(this) 54 } 55 56 override fun onConfigChanged(newConfig: Configuration) { 57 val newSize = calculateSize() 58 if (newSize != size) { 59 size.set(newSize) 60 listeners.forEach { it.onTaskSizeChanged(size) } 61 } 62 } 63 64 private fun calculateSize(): Rect { 65 val windowMetrics = windowManager.maximumWindowMetrics 66 val maximumWindowHeight = windowMetrics.bounds.height() 67 val width = windowMetrics.bounds.width() 68 var height = maximumWindowHeight 69 70 val isLargeScreen = isLargeScreen(context) 71 if (isLargeScreen) { 72 val taskbarSize = 73 windowManager.currentWindowMetrics.windowInsets 74 .getInsets(Type.tappableElement()) 75 .bottom 76 height -= taskbarSize 77 } 78 79 val previewSize = Rect(0, 0, width, height) 80 val scale = (height / maximumWindowHeight.toFloat()) / SCREEN_HEIGHT_TO_TASK_HEIGHT_RATIO 81 previewSize.scale(scale) 82 83 return previewSize 84 } 85 86 override fun addCallback(listener: TaskPreviewSizeListener) { 87 listeners += listener 88 } 89 90 override fun removeCallback(listener: TaskPreviewSizeListener) { 91 listeners -= listener 92 } 93 94 interface TaskPreviewSizeListener { 95 fun onTaskSizeChanged(size: Rect) 96 } 97 } 98 99 /** 100 * How many times smaller the task preview should be on the screen comparing to the height of the 101 * screen 102 */ 103 private const val SCREEN_HEIGHT_TO_TASK_HEIGHT_RATIO = 4f 104