• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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