• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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.wifi.calling
18 
19 import android.Manifest.permission.MODIFY_PHONE_STATE
20 import android.Manifest.permission.READ_PRECISE_PHONE_STATE
21 import android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE
22 import android.app.settings.SettingsEnums.ACTION_WIFI_CALLING
23 import android.content.Context
24 import android.telephony.SubscriptionManager
25 import android.telephony.TelephonyManager
26 import android.telephony.ims.ImsMmTelManager
27 import android.util.Log
28 import com.android.settings.R
29 import com.android.settings.contract.KEY_WIFI_CALLING
30 import com.android.settings.metrics.PreferenceActionMetricsProvider
31 import com.android.settings.network.ims.WifiCallingQueryImsState
32 import com.android.settings.network.telephony.wificalling.WifiCallingRepository
33 import com.android.settings.widget.SettingsMainSwitchPreference
34 import com.android.settings.wifi.calling.WifiCallingSettingsForSub.getCarrierActivityIntent
35 import com.android.settingslib.datastore.KeyValueStore
36 import com.android.settingslib.datastore.NoOpKeyedObservable
37 import com.android.settingslib.datastore.Permissions
38 import com.android.settingslib.datastore.and
39 import com.android.settingslib.metadata.BooleanValuePreference
40 import com.android.settingslib.metadata.PreferenceAvailabilityProvider
41 import com.android.settingslib.metadata.ReadWritePermit
42 import com.android.settingslib.metadata.SensitivityLevel
43 import com.android.settingslib.preference.BooleanValuePreferenceBinding
44 import kotlinx.coroutines.flow.first
45 import kotlinx.coroutines.runBlocking
46 
47 /**
48  * Metadata of the "Use Wi-Fi calling" preference.
49  *
50  * TODO(b/372732219): apply metadata to UI
51  */
52 class WifiCallingMainSwitchPreference(private val subId: Int) :
53     BooleanValuePreference,
54     BooleanValuePreferenceBinding,
55     PreferenceActionMetricsProvider,
56     PreferenceAvailabilityProvider {
57 
58     override val key: String
59         get() = KEY
60 
61     override val title: Int
62         get() = R.string.wifi_calling_main_switch_title
63 
64     override val preferenceActionMetrics: Int
65         get() = ACTION_WIFI_CALLING
66 
tagsnull67     override fun tags(context: Context) = arrayOf(KEY_WIFI_CALLING)
68 
69     override fun isEnabled(context: Context) =
70         context.isCallStateIdle(subId) &&
71             WifiCallingQueryImsState(context, subId).isAllowUserControl
72 
73     override fun isAvailable(context: Context) =
74         SubscriptionManager.isValidSubscriptionId(subId) &&
75             runBlocking { WifiCallingRepository(context, subId).wifiCallingReadyFlow().first() }
76 
createWidgetnull77     override fun createWidget(context: Context) = SettingsMainSwitchPreference(context)
78 
79     override fun getReadPermissions(context: Context) =
80         Permissions.anyOf(READ_PRIVILEGED_PHONE_STATE, READ_PRECISE_PHONE_STATE)
81 
82     override fun getReadPermit(context: Context, callingPid: Int, callingUid: Int) =
83         ReadWritePermit.ALLOW
84 
85     override fun getWritePermissions(context: Context) =
86         Permissions.anyOf(READ_PRIVILEGED_PHONE_STATE, READ_PRECISE_PHONE_STATE) and
87             MODIFY_PHONE_STATE
88 
89     override fun getWritePermit(
90         context: Context,
91         value: Boolean?,
92         callingPid: Int,
93         callingUid: Int,
94     ) =
95         when {
96             value == true &&
97                 (DisclaimerItemFactory.create(context, subId).isNotEmpty() ||
98                     getCarrierActivityIntent(context, subId) != null) ->
99                 ReadWritePermit.REQUIRE_USER_AGREEMENT
100             else -> ReadWritePermit.ALLOW
101         }
102 
103     override val sensitivityLevel
104         get() = SensitivityLevel.NO_SENSITIVITY
105 
storagenull106     override fun storage(context: Context): KeyValueStore = WifiCallingStore(context, subId)
107 
108     @Suppress("UNCHECKED_CAST")
109     private class WifiCallingStore(context: Context, private val subId: Int) :
110         NoOpKeyedObservable<String>(), KeyValueStore {
111         private val queryIms = WifiCallingQueryImsState(context, subId)
112 
113         override fun contains(key: String) = key == KEY
114 
115         override fun <T : Any> getValue(key: String, valueType: Class<T>) =
116             (queryIms.isEnabledByUser && queryIms.isAllowUserControl) as T
117 
118         override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
119             if (value is Boolean) {
120                 try {
121                     ImsMmTelManager.createForSubscriptionId(subId).isVoWiFiSettingEnabled = value
122                 } catch (e: Exception) {
123                     Log.w(TAG, "fail to enable wifi calling", e)
124                 }
125             }
126         }
127     }
128 
129     companion object {
130         // TODO(b/372732219): The key is different from XML to avoid applying metadata to UI.
131         const val KEY = "wifi_calling_switch"
132         const val TAG = KEY
133 
Contextnull134         private fun Context.isCallStateIdle(subId: Int) =
135             getSystemService(TelephonyManager::class.java)?.getCallState(subId) ==
136                 TelephonyManager.CALL_STATE_IDLE
137     }
138 }
139