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