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.settings.network
18 
19 import android.content.Context
20 import android.net.TetheringManager
21 import android.os.UserHandle
22 import android.os.UserManager
23 import androidx.annotation.StringRes
24 import androidx.annotation.VisibleForTesting
25 import androidx.lifecycle.Lifecycle
26 import androidx.lifecycle.LifecycleOwner
27 import androidx.lifecycle.lifecycleScope
28 import androidx.lifecycle.repeatOnLifecycle
29 import androidx.preference.Preference
30 import androidx.preference.PreferenceScreen
31 import com.android.settings.R
32 import com.android.settings.core.BasePreferenceController
33 import com.android.settingslib.RestrictedLockUtilsInternal
34 import com.android.settingslib.TetherUtil
35 import com.android.settingslib.Utils
36 import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
37 import kotlinx.coroutines.Dispatchers
38 import kotlinx.coroutines.launch
39 import kotlinx.coroutines.withContext
40 
41 class TetherPreferenceController(context: Context, key: String) :
42     BasePreferenceController(context, key) {
43 
44     private val tetheredRepository = TetheredRepository(context)
45     private val tetheringManager = mContext.getSystemService(TetheringManager::class.java)!!
46 
47     private var preference: Preference? = null
48 
getAvailabilityStatusnull49     override fun getAvailabilityStatus() =
50         if (TetherUtil.isTetherAvailable(mContext)) AVAILABLE else CONDITIONALLY_UNAVAILABLE
51 
52     override fun displayPreference(screen: PreferenceScreen) {
53         super.displayPreference(screen)
54         preference = screen.findPreference(preferenceKey)
55     }
56 
onViewCreatednull57     override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) {
58         viewLifecycleOwner.lifecycleScope.launch {
59             viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
60                 getTitleResId()?.let { preference?.setTitle(it) }
61             }
62         }
63 
64         tetheredRepository.tetheredTypesFlow().collectLatestWithLifecycle(viewLifecycleOwner) {
65             preference?.setSummary(getSummaryResId(it))
66         }
67     }
68 
<lambda>null69     private suspend fun getTitleResId(): Int? = withContext(Dispatchers.Default) {
70         if (isTetherConfigDisallowed(mContext)) null
71         else Utils.getTetheringLabel(tetheringManager)
72     }
73 
74     @VisibleForTesting
75     @StringRes
getSummaryResIdnull76     fun getSummaryResId(tetheredTypes: Set<Int>): Int {
77         val hotSpotOn = TetheringManager.TETHERING_WIFI in tetheredTypes
78         val tetherOn = tetheredTypes.any { it != TetheringManager.TETHERING_WIFI }
79         return when {
80             hotSpotOn && tetherOn -> R.string.tether_settings_summary_hotspot_on_tether_on
81             hotSpotOn -> R.string.tether_settings_summary_hotspot_on_tether_off
82             tetherOn -> R.string.tether_settings_summary_hotspot_off_tether_on
83             else -> R.string.tether_preference_summary_off
84         }
85     }
86 
87     companion object {
88         @JvmStatic
isTetherConfigDisallowednull89         fun isTetherConfigDisallowed(context: Context?): Boolean =
90             RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
91                 context, UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.myUserId()
92             ) != null
93     }
94 }
95