• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * 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.qs.tiles
18 
19 import android.content.ComponentName
20 import android.content.Intent
21 import android.os.Handler
22 import android.os.Looper
23 import android.service.quicksettings.Tile
24 import android.view.View
25 import androidx.annotation.VisibleForTesting
26 import com.android.internal.jank.InteractionJankMonitor
27 import com.android.internal.logging.MetricsLogger
28 import com.android.systemui.R
29 import com.android.systemui.animation.ActivityLaunchAnimator
30 import com.android.systemui.controls.ControlsServiceInfo
31 import com.android.systemui.controls.dagger.ControlsComponent
32 import com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE
33 import com.android.systemui.controls.management.ControlsListingController
34 import com.android.systemui.controls.ui.ControlsUiController
35 import com.android.systemui.controls.ui.SelectedItem
36 import com.android.systemui.dagger.qualifiers.Background
37 import com.android.systemui.dagger.qualifiers.Main
38 import com.android.systemui.plugins.ActivityStarter
39 import com.android.systemui.plugins.FalsingManager
40 import com.android.systemui.plugins.qs.QSTile
41 import com.android.systemui.plugins.statusbar.StatusBarStateController
42 import com.android.systemui.qs.QSHost
43 import com.android.systemui.qs.logging.QSLogger
44 import com.android.systemui.qs.tileimpl.QSTileImpl
45 import java.util.concurrent.atomic.AtomicBoolean
46 import javax.inject.Inject
47 
48 class DeviceControlsTile @Inject constructor(
49     host: QSHost,
50     @Background backgroundLooper: Looper,
51     @Main mainHandler: Handler,
52     falsingManager: FalsingManager,
53     metricsLogger: MetricsLogger,
54     statusBarStateController: StatusBarStateController,
55     activityStarter: ActivityStarter,
56     qsLogger: QSLogger,
57     private val controlsComponent: ControlsComponent
58 ) : QSTileImpl<QSTile.State>(
59         host,
60         backgroundLooper,
61         mainHandler,
62         falsingManager,
63         metricsLogger,
64         statusBarStateController,
65         activityStarter,
66         qsLogger
67 ) {
68 
69     private var hasControlsApps = AtomicBoolean(false)
70 
71     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
72     val icon: QSTile.Icon
73         get() = ResourceIcon.get(controlsComponent.getTileImageId())
74 
75     private val listingCallback = object : ControlsListingController.ControlsListingCallback {
onServicesUpdatednull76         override fun onServicesUpdated(serviceInfos: List<ControlsServiceInfo>) {
77             if (hasControlsApps.compareAndSet(serviceInfos.isEmpty(), serviceInfos.isNotEmpty())) {
78                 refreshState()
79             }
80         }
81     }
82 
83     init {
<lambda>null84         controlsComponent.getControlsListingController().ifPresent {
85             it.observe(this, listingCallback)
86         }
87     }
88 
isAvailablenull89     override fun isAvailable(): Boolean {
90         return controlsComponent.getControlsController().isPresent
91     }
92 
newTileStatenull93     override fun newTileState(): QSTile.State {
94         return QSTile.State().also {
95             it.state = Tile.STATE_UNAVAILABLE // Start unavailable matching `hasControlsApps`
96             it.handlesLongClick = false
97         }
98     }
99 
handleClicknull100     override fun handleClick(view: View?) {
101         if (state.state == Tile.STATE_UNAVAILABLE) {
102             return
103         }
104 
105         val intent = Intent().apply {
106             component = ComponentName(mContext, controlsComponent.getControlsUiController().get()
107                 .resolveActivity())
108             addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
109             putExtra(ControlsUiController.EXTRA_ANIMATE, true)
110         }
111         val animationController = view?.let {
112             ActivityLaunchAnimator.Controller.fromView(
113                     it, InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE)
114         }
115 
116         mUiHandler.post {
117             val showOverLockscreenWhenLocked = state.state == Tile.STATE_ACTIVE
118             mActivityStarter.startActivity(
119                 intent, true /* dismissShade */, animationController, showOverLockscreenWhenLocked)
120         }
121     }
122 
handleUpdateStatenull123     override fun handleUpdateState(state: QSTile.State, arg: Any?) {
124         state.label = tileLabel
125         state.contentDescription = state.label
126         state.icon = icon
127         if (controlsComponent.isEnabled() && hasControlsApps.get()) {
128             if (controlsComponent.getVisibility() == AVAILABLE) {
129                 val selection = controlsComponent
130                     .getControlsController().get().getPreferredSelection()
131                 state.state = if (selection is SelectedItem.StructureItem &&
132                         selection.structure.controls.isEmpty()) {
133                     Tile.STATE_INACTIVE
134                 } else {
135                     Tile.STATE_ACTIVE
136                 }
137                 val label = selection.name
138                 state.secondaryLabel = if (label == tileLabel) null else label
139             } else {
140                 state.state = Tile.STATE_INACTIVE
141                 state.secondaryLabel = mContext.getText(R.string.controls_tile_locked)
142             }
143             state.stateDescription = state.secondaryLabel
144         } else {
145             state.state = Tile.STATE_UNAVAILABLE
146         }
147     }
148 
getMetricsCategorynull149     override fun getMetricsCategory(): Int {
150         return 0
151     }
152 
getLongClickIntentnull153     override fun getLongClickIntent(): Intent? {
154         return null
155     }
156 
handleLongClicknull157     override fun handleLongClick(view: View?) {}
158 
getTileLabelnull159     override fun getTileLabel(): CharSequence {
160         return mContext.getText(controlsComponent.getTileTitleId())
161     }
162 
163     companion object {
164         const val TILE_SPEC = "controls"
165     }
166 }
167