1 /* <lambda>null2 * Copyright (C) 2021 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.controls.ui 18 19 import android.content.BroadcastReceiver 20 import android.content.Context 21 import android.content.Intent 22 import android.content.IntentFilter 23 import android.content.pm.ActivityInfo 24 import android.content.res.Configuration 25 import android.os.Bundle 26 import android.os.RemoteException 27 import android.service.dreams.IDreamManager 28 import android.view.View 29 import android.view.ViewGroup 30 import android.view.WindowInsets 31 import android.view.WindowInsets.Type 32 import android.view.WindowManager 33 import androidx.activity.ComponentActivity 34 import com.android.systemui.R 35 import com.android.systemui.broadcast.BroadcastDispatcher 36 import com.android.systemui.controls.management.ControlsAnimations 37 import com.android.systemui.controls.settings.ControlsSettingsDialogManager 38 import com.android.systemui.flags.FeatureFlags 39 import com.android.systemui.flags.Flags 40 import com.android.systemui.statusbar.policy.KeyguardStateController 41 import javax.inject.Inject 42 43 /** 44 * Displays Device Controls inside an activity. This activity is available to be displayed over the 45 * lockscreen if the user has allowed it via 46 * [android.provider.Settings.Secure.LOCKSCREEN_SHOW_CONTROLS]. This activity will be 47 * destroyed on SCREEN_OFF events, due to issues with occluded activities over lockscreen as well as 48 * user expectations for the activity to not continue running. 49 */ 50 // Open for testing 51 open class ControlsActivity @Inject constructor( 52 private val uiController: ControlsUiController, 53 private val broadcastDispatcher: BroadcastDispatcher, 54 private val dreamManager: IDreamManager, 55 private val featureFlags: FeatureFlags, 56 private val controlsSettingsDialogManager: ControlsSettingsDialogManager, 57 private val keyguardStateController: KeyguardStateController 58 ) : ComponentActivity() { 59 60 private lateinit var parent: ViewGroup 61 private lateinit var broadcastReceiver: BroadcastReceiver 62 private var mExitToDream: Boolean = false 63 private lateinit var lastConfiguration: Configuration 64 65 override fun onCreate(savedInstanceState: Bundle?) { 66 super.onCreate(savedInstanceState) 67 lastConfiguration = resources.configuration 68 if (featureFlags.isEnabled(Flags.USE_APP_PANELS)) { 69 window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY) 70 } 71 72 setContentView(R.layout.controls_fullscreen) 73 74 getLifecycle().addObserver( 75 ControlsAnimations.observerForAnimations( 76 requireViewById(R.id.control_detail_root), 77 window, 78 intent, 79 !featureFlags.isEnabled(Flags.USE_APP_PANELS) 80 ) 81 ) 82 83 requireViewById<ViewGroup>(R.id.control_detail_root).apply { 84 setOnApplyWindowInsetsListener { 85 v: View, insets: WindowInsets -> 86 v.apply { 87 val l = getPaddingLeft() 88 val t = getPaddingTop() 89 val r = getPaddingRight() 90 setPadding(l, t, r, insets.getInsets(Type.systemBars()).bottom) 91 } 92 93 WindowInsets.CONSUMED 94 } 95 } 96 97 initBroadcastReceiver() 98 } 99 100 override fun onConfigurationChanged(newConfig: Configuration) { 101 super.onConfigurationChanged(newConfig) 102 val interestingFlags = ActivityInfo.CONFIG_ORIENTATION or 103 ActivityInfo.CONFIG_SCREEN_SIZE or 104 ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE 105 if (lastConfiguration.diff(newConfig) and interestingFlags != 0 ) { 106 uiController.onSizeChange() 107 } 108 lastConfiguration = newConfig 109 } 110 111 override fun onStart() { 112 super.onStart() 113 114 parent = requireViewById(R.id.control_detail_root) 115 parent.alpha = 0f 116 if (featureFlags.isEnabled(Flags.USE_APP_PANELS) && !keyguardStateController.isUnlocked) { 117 controlsSettingsDialogManager.maybeShowDialog(this) { 118 uiController.show(parent, { finishOrReturnToDream() }, this) 119 } 120 } else { 121 uiController.show(parent, { finishOrReturnToDream() }, this) 122 } 123 124 ControlsAnimations.enterAnimation(parent).start() 125 } 126 127 override fun onResume() { 128 super.onResume() 129 mExitToDream = intent.getBooleanExtra(ControlsUiController.EXIT_TO_DREAM, false) 130 } 131 132 fun finishOrReturnToDream() { 133 if (mExitToDream) { 134 try { 135 mExitToDream = false 136 dreamManager.dream() 137 return 138 } catch (e: RemoteException) { 139 // Fall through 140 } 141 } 142 finish() 143 } 144 145 override fun onBackPressed() { 146 finishOrReturnToDream() 147 } 148 149 override fun onStop() { 150 super.onStop() 151 mExitToDream = false 152 153 // parent is set in onStart, so the field is initialized when we get here 154 uiController.hide(parent) 155 controlsSettingsDialogManager.closeDialog() 156 } 157 158 override fun onDestroy() { 159 super.onDestroy() 160 161 broadcastDispatcher.unregisterReceiver(broadcastReceiver) 162 } 163 164 private fun initBroadcastReceiver() { 165 broadcastReceiver = object : BroadcastReceiver() { 166 override fun onReceive(context: Context, intent: Intent) { 167 val action = intent.getAction() 168 if (action == Intent.ACTION_SCREEN_OFF || 169 action == Intent.ACTION_DREAMING_STARTED) { 170 finish() 171 } 172 } 173 } 174 175 val filter = IntentFilter() 176 filter.addAction(Intent.ACTION_SCREEN_OFF) 177 filter.addAction(Intent.ACTION_DREAMING_STARTED) 178 broadcastDispatcher.registerReceiver(broadcastReceiver, filter) 179 } 180 } 181