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 package com.android.settings.network.telephony
17 
18 import android.util.Log
19 import androidx.lifecycle.Lifecycle
20 import androidx.lifecycle.coroutineScope
21 import com.android.settings.core.BasePreferenceController
22 import com.android.settingslib.core.AbstractPreferenceController
23 import com.google.common.collect.Sets
24 import kotlinx.coroutines.Dispatchers
25 import kotlinx.coroutines.Job
26 import kotlinx.coroutines.launch
27 import kotlinx.coroutines.yield
28 
29 /**
30  * Session for controlling the status of TelephonyPreferenceController(s).
31  *
32  * Within this session, result of [BasePreferenceController.getAvailabilityStatus]
33  * would be under control.
34  */
35 class TelephonyStatusControlSession(
36     private val controllers: Collection<AbstractPreferenceController>,
37     lifecycle: Lifecycle,
38 ) : AutoCloseable {
39     private var job: Job? = null
40     private val controllerSet = Sets.newConcurrentHashSet<TelephonyAvailabilityHandler>()
41 
42     init {
<lambda>null43         job = lifecycle.coroutineScope.launch(Dispatchers.Default) {
44             for (controller in controllers) {
45                 launch {
46                     setupAvailabilityStatus(controller)
47                 }
48             }
49         }
50     }
51 
52     /**
53      * Close the session.
54      *
55      * No longer control the status.
56      */
closenull57     override fun close() {
58         job?.cancel()
59         unsetAvailabilityStatus()
60     }
61 
setupAvailabilityStatusnull62     private suspend fun setupAvailabilityStatus(controller: AbstractPreferenceController): Boolean =
63         try {
64             if (controller is TelephonyAvailabilityHandler) {
65                 val status = (controller as BasePreferenceController).availabilityStatus
66                 yield() // prompt cancellation guarantee
67                 if (controllerSet.add(controller)) {
68                     controller.setAvailabilityStatus(status)
69                 }
70             }
71             true
72         } catch (exception: Exception) {
73             Log.e(LOG_TAG, "Setup availability status failed!", exception)
74             false
75         }
76 
unsetAvailabilityStatusnull77     private fun unsetAvailabilityStatus() {
78         for (controller in controllerSet) {
79             controller.unsetAvailabilityStatus()
80         }
81     }
82 
83     companion object {
84         private const val LOG_TAG = "TelephonyStatusControlSS"
85     }
86 }
87