1 /*
2 * Copyright 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.server.bluetooth
17
18 import android.content.ContentResolver
19 import android.database.ContentObserver
20 import android.os.Handler
21 import android.os.Looper
22 import android.provider.Settings
23
24 private const val TAG = "BluetoothRadioModeListener"
25
26 /**
27 * Listen on radio mode and trigger the callback when it change
28 *
29 * @param radio: The radio to listen for, eg: Settings.Global.AIRPLANE_MODE_RADIOS
30 * @param modeKey: The associated mode key, eg: Settings.Global.AIRPLANE_MODE_ON
31 * @param callback: The callback to trigger when there is a mode change, pass new mode as parameter
32 * @return The initial value of the radio
33 */
initializeRadioModeListenernull34 internal fun initializeRadioModeListener(
35 looper: Looper,
36 resolver: ContentResolver,
37 radio: String,
38 modeKey: String,
39 callback: (m: Boolean) -> Unit
40 ): Boolean {
41 val observer =
42 object : ContentObserver(Handler(looper)) {
43 override fun onChange(selfChange: Boolean) {
44 callback(getRadioModeValue(resolver, radio, modeKey))
45 }
46 }
47
48 val notifyForDescendants = false
49
50 resolver.registerContentObserver(
51 Settings.Global.getUriFor(radio),
52 notifyForDescendants,
53 observer
54 )
55 resolver.registerContentObserver(
56 Settings.Global.getUriFor(modeKey),
57 notifyForDescendants,
58 observer
59 )
60 return getRadioModeValue(resolver, radio, modeKey)
61 }
62
63 /**
64 * Check if Bluetooth is impacted by the radio and fetch global mode status
65 *
66 * @return whether Bluetooth should consider this radio or not
67 */
getRadioModeValuenull68 private fun getRadioModeValue(resolver: ContentResolver, radio: String, modeKey: String): Boolean {
69 return if (isSensitive(resolver, radio)) {
70 isGlobalModeOn(resolver, modeKey)
71 } else {
72 Log.d(TAG, "Not sensitive to " + radio + " change. Forced to false")
73 false
74 }
75 }
76
77 /**
78 * *Do not use outside of this file to avoid async issues*
79 *
80 * @return false if Bluetooth should not listen for mode change related to the {@code radio}
81 */
isSensitivenull82 private fun isSensitive(resolver: ContentResolver, radio: String): Boolean {
83 val radios = Settings.Global.getString(resolver, radio)
84 return radios != null && radios.contains(Settings.Global.RADIO_BLUETOOTH)
85 }
86
87 /**
88 * *Do not use outside of this file to avoid async issues*
89 *
90 * @return whether mode {@code modeKey} is on or off in Global settings
91 */
isGlobalModeOnnull92 private fun isGlobalModeOn(resolver: ContentResolver, modeKey: String): Boolean {
93 return Settings.Global.getInt(resolver, modeKey, 0) == 1
94 }
95