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 18 package com.android.systemui.controls.ui 19 20 import android.app.ActivityOptions 21 import android.app.ActivityTaskManager 22 import android.app.ActivityTaskManager.INVALID_TASK_ID 23 import android.app.PendingIntent 24 import android.content.ComponentName 25 import android.content.Context 26 import android.content.Intent 27 import android.graphics.Color 28 import android.graphics.drawable.ShapeDrawable 29 import android.graphics.drawable.shapes.RoundRectShape 30 import android.os.Trace 31 import com.android.systemui.R 32 import com.android.systemui.util.boundsOnScreen 33 import com.android.wm.shell.TaskView 34 import java.util.concurrent.Executor 35 36 class PanelTaskViewController( 37 private val activityContext: Context, 38 private val uiExecutor: Executor, 39 private val pendingIntent: PendingIntent, 40 val taskView: TaskView, <lambda>null41 private val hide: () -> Unit = {} 42 ) { 43 44 private var detailTaskId = INVALID_TASK_ID 45 46 private val fillInIntent = <lambda>null47 Intent().apply { 48 // Apply flags to make behaviour match documentLaunchMode=always. 49 addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 50 addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK) 51 } 52 removeDetailTasknull53 private fun removeDetailTask() { 54 if (detailTaskId == INVALID_TASK_ID) return 55 ActivityTaskManager.getInstance().removeTask(detailTaskId) 56 detailTaskId = INVALID_TASK_ID 57 } 58 59 private val stateCallback = 60 object : TaskView.Listener { onInitializednull61 override fun onInitialized() { 62 63 val options = 64 ActivityOptions.makeCustomAnimation( 65 activityContext, 66 0 /* enterResId */, 67 0 /* exitResId */ 68 ) 69 options.taskAlwaysOnTop = true 70 71 taskView.post { 72 val roundedCorner = 73 activityContext.resources.getDimensionPixelSize( 74 R.dimen.controls_panel_corner_radius 75 ) 76 val radii = FloatArray(8) { roundedCorner.toFloat() } 77 taskView.background = 78 ShapeDrawable(RoundRectShape(radii, null, null)).apply { 79 setTint(Color.TRANSPARENT) 80 } 81 taskView.clipToOutline = true 82 taskView.startActivity( 83 pendingIntent, 84 fillInIntent, 85 options, 86 taskView.boundsOnScreen 87 ) 88 Trace.instant(Trace.TRACE_TAG_APP, "PanelTaskViewController - startActivity") 89 } 90 } 91 onTaskRemovalStartednull92 override fun onTaskRemovalStarted(taskId: Int) { 93 detailTaskId = INVALID_TASK_ID 94 dismiss() 95 } 96 onTaskCreatednull97 override fun onTaskCreated(taskId: Int, name: ComponentName?) { 98 detailTaskId = taskId 99 } 100 onReleasednull101 override fun onReleased() { 102 removeDetailTask() 103 } 104 onBackPressedOnTaskRootnull105 override fun onBackPressedOnTaskRoot(taskId: Int) { 106 dismiss() 107 hide() 108 } 109 } 110 refreshBoundsnull111 fun refreshBounds() { 112 taskView.onLocationChanged() 113 } 114 dismissnull115 fun dismiss() { 116 taskView.release() 117 } 118 launchTaskViewnull119 fun launchTaskView() { 120 taskView.setListener(uiExecutor, stateCallback) 121 } 122 } 123