• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * 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.details2
18 
19 import android.content.Context
20 import android.net.wifi.WifiManager
21 import android.os.Bundle
22 import android.os.Handler
23 import android.os.HandlerThread
24 import android.os.Looper
25 import android.os.Process
26 import android.os.SimpleClock
27 import androidx.compose.foundation.layout.Column
28 import androidx.compose.runtime.Composable
29 import androidx.compose.runtime.getValue
30 import androidx.compose.runtime.mutableIntStateOf
31 import androidx.compose.runtime.mutableStateOf
32 import androidx.compose.runtime.remember
33 import androidx.compose.runtime.saveable.rememberSaveable
34 import androidx.compose.runtime.setValue
35 import androidx.compose.ui.platform.LocalContext
36 import androidx.compose.ui.platform.LocalLifecycleOwner
37 import androidx.compose.ui.res.stringArrayResource
38 import androidx.compose.ui.res.stringResource
39 import androidx.navigation.NavType
40 import androidx.navigation.navArgument
41 import com.android.settings.R
42 import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
43 import com.android.settingslib.spa.framework.common.SettingsPageProvider
44 import com.android.settingslib.spa.widget.preference.ListPreferenceModel
45 import com.android.settingslib.spa.widget.preference.ListPreferenceOption
46 import com.android.settingslib.spa.widget.preference.RadioPreferences
47 import com.android.settingslib.spa.widget.preference.SwitchPreference
48 import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
49 import com.android.settingslib.spa.widget.scaffold.RegularScaffold
50 import com.android.settingslib.spa.widget.ui.Category
51 import com.android.wifitrackerlib.WifiEntry
52 import java.time.Clock
53 import java.time.ZoneOffset
54 import java.util.Base64
55 
56 const val WIFI_ENTRY_KEY = "wifiEntryKey"
57 
58 object WifiPrivacyPageProvider : SettingsPageProvider {
59     override val name = "WifiPrivacy"
60     const val TAG = "WifiPrivacyPageProvider"
61 
62     override val parameter = listOf(
63         navArgument(WIFI_ENTRY_KEY) { type = NavType.StringType },
64     )
65 
66     @Composable
67     override fun Page(arguments: Bundle?) {
68         val wifiEntryKey =
69             String(Base64.getUrlDecoder().decode(arguments!!.getString(WIFI_ENTRY_KEY)))
70         if (wifiEntryKey != null) {
71             val context = LocalContext.current
72             val lifecycle = LocalLifecycleOwner.current.lifecycle
73             val wifiEntry = remember {
74                 getWifiEntry(context, wifiEntryKey, lifecycle)
75             }
76             WifiPrivacyPage(wifiEntry)
77         }
78     }
79 
80     fun getRoute(
81         wifiEntryKey: String,
82     ): String = "${name}/${Base64.getUrlEncoder().encodeToString(wifiEntryKey.toByteArray())}"
83 }
84 
85 @Composable
WifiPrivacyPagenull86 fun WifiPrivacyPage(wifiEntry: WifiEntry) {
87     val isSelectable: Boolean = wifiEntry.canSetPrivacy()
88     RegularScaffold(
89         title = stringResource(id = R.string.wifi_privacy_settings)
90     ) {
91         Column {
92             val title = stringResource(id = R.string.wifi_privacy_mac_settings)
93             val wifiPrivacyEntries = stringArrayResource(R.array.wifi_privacy_entries)
94             val wifiPrivacyValues = stringArrayResource(R.array.wifi_privacy_values)
95             val textsSelectedId = rememberSaveable { mutableIntStateOf(wifiEntry.privacy) }
96             val dataList = remember {
97                 wifiPrivacyEntries.mapIndexed { index, text ->
98                     ListPreferenceOption(id = wifiPrivacyValues[index].toInt(), text = text)
99                 }
100             }
101             RadioPreferences(remember {
102                 object : ListPreferenceModel {
103                     override val title = title
104                     override val options = dataList
105                     override val selectedId = textsSelectedId
106                     override val onIdSelected: (Int) -> Unit = {
107                         textsSelectedId.intValue = it
108                         onSelectedChange(wifiEntry, it)
109                     }
110                     override val enabled = { isSelectable }
111                 }
112             })
113             wifiEntry.wifiConfiguration?.let {
114                 DeviceNameSwitchPreference(wifiEntry)
115             }
116         }
117     }
118 }
119 
120 @Composable
DeviceNameSwitchPreferencenull121 fun DeviceNameSwitchPreference(wifiEntry: WifiEntry) {
122     val title = stringResource(id = R.string.wifi_privacy_device_name_settings)
123     Category(title = title) {
124         var checked by remember {
125             mutableStateOf(wifiEntry.wifiConfiguration?.isSendDhcpHostnameEnabled)
126         }
127         val context = LocalContext.current
128         val wifiManager = context.getSystemService(WifiManager::class.java)!!
129         SwitchPreference(object : SwitchPreferenceModel {
130             override val title =
131                 context.resources.getString(
132                     R.string.wifi_privacy_send_device_name_toggle_title
133                 )
134             override val summary =
135                 {
136                     context.resources.getString(
137                         R.string.wifi_privacy_send_device_name_toggle_summary
138                     )
139                 }
140             override val checked = { checked }
141             override val onCheckedChange: (Boolean) -> Unit = { newChecked ->
142                 wifiEntry.wifiConfiguration?.let {
143                     it.isSendDhcpHostnameEnabled = newChecked
144                     wifiManager.save(it, null /* listener */)
145                     checked = newChecked
146                 }
147             }
148         })
149     }
150 }
151 
onSelectedChangenull152 fun onSelectedChange(wifiEntry: WifiEntry, privacy: Int) {
153     if (wifiEntry.privacy == privacy) {
154         // Prevent disconnection + reconnection if settings not changed.
155         return
156     }
157     wifiEntry.setPrivacy(privacy)
158 
159     // To activate changing, we need to reconnect network. WiFi will auto connect to
160     // current network after disconnect(). Only needed when this is connected network.
161 
162     // To activate changing, we need to reconnect network. WiFi will auto connect to
163     // current network after disconnect(). Only needed when this is connected network.
164     if (wifiEntry.getConnectedState() == WifiEntry.CONNECTED_STATE_CONNECTED) {
165         wifiEntry.disconnect(null /* callback */)
166         wifiEntry.connect(null /* callback */)
167     }
168 }
169 
getWifiEntrynull170 fun getWifiEntry(
171     context: Context,
172     wifiEntryKey: String,
173     liftCycle: androidx.lifecycle.Lifecycle
174 ): WifiEntry {
175     // Max age of tracked WifiEntries
176     val MAX_SCAN_AGE_MILLIS: Long = 15000
177     // Interval between initiating SavedNetworkTracker scans
178     val SCAN_INTERVAL_MILLIS: Long = 10000
179     val mWorkerThread = HandlerThread(
180         WifiPrivacyPageProvider.TAG,
181         Process.THREAD_PRIORITY_BACKGROUND
182     )
183     mWorkerThread.start()
184     val elapsedRealtimeClock: Clock = object : SimpleClock(ZoneOffset.UTC) {
185         override fun millis(): Long {
186             return android.os.SystemClock.elapsedRealtime()
187         }
188     }
189     val mNetworkDetailsTracker = featureFactory
190         .wifiTrackerLibProvider
191         .createNetworkDetailsTracker(
192             liftCycle,
193             context,
194             Handler(Looper.getMainLooper()),
195             mWorkerThread.getThreadHandler(),
196             elapsedRealtimeClock,
197             MAX_SCAN_AGE_MILLIS,
198             SCAN_INTERVAL_MILLIS,
199             wifiEntryKey
200         )
201     return mNetworkDetailsTracker.wifiEntry
202 }
203