1 /*
2  * Copyright (C) 2020 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.controller
18 
19 import android.os.IBinder
20 import android.service.controls.Control
21 import android.service.controls.IControlsSubscriber
22 import android.service.controls.IControlsSubscription
23 import android.util.Log
24 import com.android.systemui.util.concurrency.DelayableExecutor
25 
26 /**
27  * A single subscriber, supporting stateful controls for publishers created by
28  * {@link ControlsProviderService#createPublisherFor}. In general, this subscription will remain
29  * active until the SysUi chooses to cancel it.
30  */
31 class StatefulControlSubscriber(
32     private val controller: ControlsController,
33     private val provider: ControlsProviderLifecycleManager,
34     private val bgExecutor: DelayableExecutor,
35     private val requestLimit: Long
36 ) : IControlsSubscriber.Stub() {
37     private var subscriptionOpen = false
38     private var subscription: IControlsSubscription? = null
39 
40     companion object {
41         private const val TAG = "StatefulControlSubscriber"
42     }
43 
runnull44     private fun run(token: IBinder, f: () -> Unit) {
45         if (provider.token == token) {
46             bgExecutor.execute { f() }
47         }
48     }
49 
onSubscribenull50     override fun onSubscribe(token: IBinder, subs: IControlsSubscription) {
51         run(token) {
52             subscriptionOpen = true
53             subscription = subs
54             provider.startSubscription(subs, requestLimit)
55         }
56     }
57 
onNextnull58     override fun onNext(token: IBinder, control: Control) {
59         run(token) {
60             if (!subscriptionOpen) {
61                 Log.w(TAG, "Refresh outside of window for token:$token")
62             } else {
63                 controller.refreshStatus(provider.componentName, control)
64             }
65         }
66     }
onErrornull67     override fun onError(token: IBinder, error: String) {
68         run(token) {
69             if (subscriptionOpen) {
70                 subscriptionOpen = false
71                 Log.e(TAG, "onError receive from '${provider.componentName}': $error")
72             }
73         }
74     }
75 
onCompletenull76     override fun onComplete(token: IBinder) {
77         run(token) {
78             if (subscriptionOpen) {
79                 subscriptionOpen = false
80                 Log.i(TAG, "onComplete receive from '${provider.componentName}'")
81             }
82         }
83     }
84 
cancelnull85     fun cancel() {
86         if (!subscriptionOpen) return
87         bgExecutor.execute {
88             if (subscriptionOpen) {
89                 subscriptionOpen = false
90                 subscription?.let {
91                     provider.cancelSubscription(it)
92                 }
93                 subscription = null
94             }
95         }
96     }
97 }
98