1 /*
2  * Copyright (C) 2023 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.statusbar.notification.shelf.ui.viewbinder
18 
19 import android.view.View
20 import androidx.lifecycle.Lifecycle
21 import androidx.lifecycle.repeatOnLifecycle
22 import com.android.systemui.dagger.SysUISingleton
23 import com.android.systemui.flags.FeatureFlags
24 import com.android.systemui.lifecycle.repeatWhenAttached
25 import com.android.systemui.plugins.FalsingManager
26 import com.android.systemui.statusbar.LegacyNotificationShelfControllerImpl
27 import com.android.systemui.statusbar.NotificationShelf
28 import com.android.systemui.statusbar.NotificationShelfController
29 import com.android.systemui.statusbar.notification.row.ui.viewbinder.ActivatableNotificationViewBinder
30 import com.android.systemui.statusbar.notification.shelf.ui.viewmodel.NotificationShelfViewModel
31 import com.android.systemui.statusbar.notification.stack.AmbientState
32 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
33 import com.android.systemui.statusbar.phone.NotificationIconAreaController
34 import com.android.systemui.statusbar.phone.NotificationIconContainer
35 import javax.inject.Inject
36 import kotlinx.coroutines.awaitCancellation
37 import kotlinx.coroutines.launch
38 
39 /**
40  * Controller class for [NotificationShelf]. This implementation serves as a temporary wrapper
41  * around a [NotificationShelfViewBinder], so that external code can continue to depend on the
42  * [NotificationShelfController] interface. Once the [LegacyNotificationShelfControllerImpl] is
43  * removed, this class can go away and the ViewBinder can be used directly.
44  */
45 @SysUISingleton
46 class NotificationShelfViewBinderWrapperControllerImpl @Inject constructor() :
47     NotificationShelfController {
48 
49     override val view: NotificationShelf
50         get() = unsupported
51 
52     override val intrinsicHeight: Int
53         get() = unsupported
54 
55     override val shelfIcons: NotificationIconContainer
56         get() = unsupported
57 
58     override fun canModifyColorOfNotifications(): Boolean = unsupported
59 
60     override fun bind(
61         ambientState: AmbientState,
62         notificationStackScrollLayoutController: NotificationStackScrollLayoutController,
63     ) = unsupported
64 
65     override fun setOnClickListener(listener: View.OnClickListener) = unsupported
66 
67     companion object {
68         val unsupported: Nothing
69             get() = error("Code path not supported when NOTIFICATION_SHELF_REFACTOR is disabled")
70     }
71 }
72 
73 /** Binds a [NotificationShelf] to its [view model][NotificationShelfViewModel]. */
74 object NotificationShelfViewBinder {
75     fun bind(
76         shelf: NotificationShelf,
77         viewModel: NotificationShelfViewModel,
78         falsingManager: FalsingManager,
79         featureFlags: FeatureFlags,
80         notificationIconAreaController: NotificationIconAreaController,
81     ) {
82         ActivatableNotificationViewBinder.bind(viewModel, shelf, falsingManager)
83         shelf.apply {
84             // TODO(278765923): Replace with eventual NotificationIconContainerViewBinder#bind()
85             notificationIconAreaController.setShelfIcons(shelfIcons)
86             repeatWhenAttached {
87                 repeatOnLifecycle(Lifecycle.State.STARTED) {
88                     launch {
89                         viewModel.canModifyColorOfNotifications.collect(
90                             ::setCanModifyColorOfNotifications
91                         )
92                     }
93                     launch { viewModel.isClickable.collect(::setCanInteract) }
94                     registerViewListenersWhileAttached(shelf, viewModel)
95                 }
96             }
97         }
98     }
99 
100     private suspend fun registerViewListenersWhileAttached(
101         shelf: NotificationShelf,
102         viewModel: NotificationShelfViewModel,
103     ) {
104         try {
105             shelf.setOnClickListener { viewModel.onShelfClicked() }
106             awaitCancellation()
107         } finally {
108             shelf.setOnClickListener(null)
109         }
110     }
111 }
112