Snap for 12765415 from 6c0260c0ec
to 25Q1-release
Change-Id: Ia2d341cf854f697972a42750620a6cc18b7648eb
This commit is contained in:
@@ -28,8 +28,7 @@
|
|||||||
android:title="@string/wifi_hotspot_checkbox_text"
|
android:title="@string/wifi_hotspot_checkbox_text"
|
||||||
android:summary="@string/wifi_hotspot_off_subtext"
|
android:summary="@string/wifi_hotspot_off_subtext"
|
||||||
android:fragment="com.android.settings.wifi.tether.WifiTetherSettings"
|
android:fragment="com.android.settings.wifi.tether.WifiTetherSettings"
|
||||||
settings:allowDividerAbove="true"
|
settings:allowDividerAbove="true"/>
|
||||||
settings:maxLines="2"/>
|
|
||||||
|
|
||||||
<com.android.settingslib.RestrictedSwitchPreference
|
<com.android.settingslib.RestrictedSwitchPreference
|
||||||
android:key="usb_tether_settings"
|
android:key="usb_tether_settings"
|
||||||
|
@@ -18,6 +18,7 @@ package com.android.settings.fuelgauge;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.text.method.LinkMovementMethod;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
@@ -44,6 +45,7 @@ public class BatteryHeaderTextPreference extends Preference implements GroupSect
|
|||||||
public void onBindViewHolder(PreferenceViewHolder view) {
|
public void onBindViewHolder(PreferenceViewHolder view) {
|
||||||
final TextView textView = (TextView) view.findViewById(R.id.text);
|
final TextView textView = (TextView) view.findViewById(R.id.text);
|
||||||
textView.setText(mText);
|
textView.setText(mText);
|
||||||
|
textView.setMovementMethod(LinkMovementMethod.getInstance());
|
||||||
if (!TextUtils.isEmpty(mContentDescription)) {
|
if (!TextUtils.isEmpty(mContentDescription)) {
|
||||||
textView.setContentDescription(mContentDescription);
|
textView.setContentDescription(mContentDescription);
|
||||||
}
|
}
|
||||||
|
@@ -22,6 +22,7 @@ import com.android.settings.PreferenceRestrictionMixin
|
|||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
import com.android.settings.flags.Flags
|
import com.android.settings.flags.Flags
|
||||||
import com.android.settings.network.TetherPreferenceController
|
import com.android.settings.network.TetherPreferenceController
|
||||||
|
import com.android.settings.wifi.tether.WifiHotspotSwitchPreference
|
||||||
import com.android.settingslib.TetherUtil
|
import com.android.settingslib.TetherUtil
|
||||||
import com.android.settingslib.Utils
|
import com.android.settingslib.Utils
|
||||||
import com.android.settingslib.metadata.PreferenceAvailabilityProvider
|
import com.android.settingslib.metadata.PreferenceAvailabilityProvider
|
||||||
@@ -63,7 +64,9 @@ class TetherScreen :
|
|||||||
|
|
||||||
override fun fragmentClass() = TetherSettings::class.java
|
override fun fragmentClass() = TetherSettings::class.java
|
||||||
|
|
||||||
override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {}
|
override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {
|
||||||
|
+WifiHotspotSwitchPreference(context)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val KEY = "tether_settings"
|
const val KEY = "tether_settings"
|
||||||
|
@@ -205,7 +205,9 @@ public class TetherSettings extends RestrictedDashboardFragment
|
|||||||
getPreferenceScreen().removePreference(mUsbTether);
|
getPreferenceScreen().removePreference(mUsbTether);
|
||||||
}
|
}
|
||||||
|
|
||||||
mWifiTetherPreferenceController.displayPreference(getPreferenceScreen());
|
if (!isCatalystEnabled() && mWifiTetherPreferenceController != null) {
|
||||||
|
mWifiTetherPreferenceController.displayPreference(getPreferenceScreen());
|
||||||
|
}
|
||||||
|
|
||||||
if (!isCatalystEnabled()) {
|
if (!isCatalystEnabled()) {
|
||||||
if (!bluetoothAvailable) {
|
if (!bluetoothAvailable) {
|
||||||
@@ -228,8 +230,10 @@ public class TetherSettings extends RestrictedDashboardFragment
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void setupViewModel() {
|
void setupViewModel() {
|
||||||
TetheringManagerModel model = new ViewModelProvider(this).get(TetheringManagerModel.class);
|
TetheringManagerModel model = new ViewModelProvider(this).get(TetheringManagerModel.class);
|
||||||
mWifiTetherPreferenceController =
|
if (!isCatalystEnabled()) {
|
||||||
new WifiTetherPreferenceController(getContext(), getSettingsLifecycle(), model);
|
mWifiTetherPreferenceController =
|
||||||
|
new WifiTetherPreferenceController(getContext(), getSettingsLifecycle(), model);
|
||||||
|
}
|
||||||
mTm = model.getTetheringManager();
|
mTm = model.getTetheringManager();
|
||||||
model.getTetheredInterfaces().observe(this, this::onTetheredInterfacesChanged);
|
model.getTetheredInterfaces().observe(this, this::onTetheredInterfacesChanged);
|
||||||
}
|
}
|
||||||
@@ -266,7 +270,9 @@ public class TetherSettings extends RestrictedDashboardFragment
|
|||||||
@Override
|
@Override
|
||||||
public void onDataSaverChanged(boolean isDataSaving) {
|
public void onDataSaverChanged(boolean isDataSaving) {
|
||||||
mDataSaverEnabled = isDataSaving;
|
mDataSaverEnabled = isDataSaving;
|
||||||
mWifiTetherPreferenceController.setDataSaverEnabled(mDataSaverEnabled);
|
if (!isCatalystEnabled()) {
|
||||||
|
mWifiTetherPreferenceController.setDataSaverEnabled(mDataSaverEnabled);
|
||||||
|
}
|
||||||
mUsbTether.setEnabled(!mDataSaverEnabled);
|
mUsbTether.setEnabled(!mDataSaverEnabled);
|
||||||
if (!isCatalystEnabled()) {
|
if (!isCatalystEnabled()) {
|
||||||
mBluetoothTether.setEnabled(!mDataSaverEnabled);
|
mBluetoothTether.setEnabled(!mDataSaverEnabled);
|
||||||
|
@@ -0,0 +1,241 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.wifi.tether
|
||||||
|
|
||||||
|
import android.app.settings.SettingsEnums
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.TetheringManager
|
||||||
|
import android.net.wifi.WifiClient
|
||||||
|
import android.net.wifi.WifiManager
|
||||||
|
import android.os.UserManager
|
||||||
|
import android.text.BidiFormatter
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.preference.Preference
|
||||||
|
import com.android.settings.PreferenceRestrictionMixin
|
||||||
|
import com.android.settings.R
|
||||||
|
import com.android.settings.Utils
|
||||||
|
import com.android.settings.core.SubSettingLauncher
|
||||||
|
import com.android.settings.datausage.DataSaverBackend
|
||||||
|
import com.android.settings.wifi.WifiUtils.canShowWifiHotspot
|
||||||
|
import com.android.settingslib.PrimarySwitchPreference
|
||||||
|
import com.android.settingslib.TetherUtil
|
||||||
|
import com.android.settingslib.datastore.AbstractKeyedDataObservable
|
||||||
|
import com.android.settingslib.datastore.DataChangeReason
|
||||||
|
import com.android.settingslib.datastore.HandlerExecutor
|
||||||
|
import com.android.settingslib.datastore.KeyValueStore
|
||||||
|
import com.android.settingslib.metadata.PreferenceAvailabilityProvider
|
||||||
|
import com.android.settingslib.metadata.PreferenceLifecycleContext
|
||||||
|
import com.android.settingslib.metadata.PreferenceLifecycleProvider
|
||||||
|
import com.android.settingslib.metadata.PreferenceMetadata
|
||||||
|
import com.android.settingslib.metadata.PreferenceSummaryProvider
|
||||||
|
import com.android.settingslib.metadata.ReadWritePermit
|
||||||
|
import com.android.settingslib.metadata.SensitivityLevel
|
||||||
|
import com.android.settingslib.metadata.SwitchPreference
|
||||||
|
import com.android.settingslib.preference.PreferenceBinding
|
||||||
|
import com.android.settingslib.wifi.WifiUtils.Companion.getWifiTetherSummaryForConnectedDevices
|
||||||
|
|
||||||
|
// LINT.IfChange
|
||||||
|
@Deprecated("Deprecated in Java")
|
||||||
|
@Suppress("MissingPermission", "NewApi", "UNCHECKED_CAST")
|
||||||
|
class WifiHotspotSwitchPreference(context: Context) :
|
||||||
|
SwitchPreference(KEY, R.string.wifi_hotspot_checkbox_text),
|
||||||
|
PreferenceBinding,
|
||||||
|
PreferenceAvailabilityProvider,
|
||||||
|
PreferenceSummaryProvider,
|
||||||
|
PreferenceLifecycleProvider,
|
||||||
|
PreferenceRestrictionMixin {
|
||||||
|
|
||||||
|
private val wifiHotspotStore = WifiHotspotStore(context)
|
||||||
|
|
||||||
|
private val dataSaverBackend = DataSaverBackend(context)
|
||||||
|
private var dataSaverBackendListener: DataSaverBackend.Listener? = null
|
||||||
|
|
||||||
|
override fun isAvailable(context: Context) =
|
||||||
|
canShowWifiHotspot(context) &&
|
||||||
|
TetherUtil.isTetherAvailable(context) &&
|
||||||
|
!Utils.isMonkeyRunning()
|
||||||
|
|
||||||
|
override fun getSummary(context: Context): CharSequence? =
|
||||||
|
when (wifiHotspotStore.sapState) {
|
||||||
|
WifiManager.WIFI_AP_STATE_ENABLING -> context.getString(R.string.wifi_tether_starting)
|
||||||
|
WifiManager.WIFI_AP_STATE_ENABLED ->
|
||||||
|
when (wifiHotspotStore.sapClientsSize) {
|
||||||
|
null ->
|
||||||
|
context.getString(
|
||||||
|
R.string.wifi_tether_enabled_subtext,
|
||||||
|
BidiFormatter.getInstance()
|
||||||
|
.unicodeWrap(context.getSoftApConfiguration()?.ssid),
|
||||||
|
)
|
||||||
|
else ->
|
||||||
|
getWifiTetherSummaryForConnectedDevices(
|
||||||
|
context,
|
||||||
|
wifiHotspotStore.sapClientsSize!!,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
WifiManager.WIFI_AP_STATE_DISABLING -> context.getString(R.string.wifi_tether_stopping)
|
||||||
|
WifiManager.WIFI_AP_STATE_DISABLED ->
|
||||||
|
context.getString(R.string.wifi_hotspot_off_subtext)
|
||||||
|
else ->
|
||||||
|
when (wifiHotspotStore.sapFailureReason) {
|
||||||
|
WifiManager.SAP_START_FAILURE_NO_CHANNEL ->
|
||||||
|
context.getString(R.string.wifi_sap_no_channel_error)
|
||||||
|
else -> context.getString(R.string.wifi_error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun intent(context: Context): Intent? =
|
||||||
|
SubSettingLauncher(context)
|
||||||
|
.apply {
|
||||||
|
setDestination(WifiTetherSettings::class.java.name)
|
||||||
|
setTitleRes(R.string.wifi_hotspot_checkbox_text)
|
||||||
|
setSourceMetricsCategory(SettingsEnums.WIFI_TETHER_SETTINGS)
|
||||||
|
}
|
||||||
|
.toIntent()
|
||||||
|
|
||||||
|
override fun isEnabled(context: Context) =
|
||||||
|
!dataSaverBackend.isDataSaverEnabled && super<PreferenceRestrictionMixin>.isEnabled(context)
|
||||||
|
|
||||||
|
override val restrictionKeys
|
||||||
|
get() = arrayOf(UserManager.DISALLOW_WIFI_TETHERING)
|
||||||
|
|
||||||
|
override fun getReadPermit(context: Context, myUid: Int, callingUid: Int) =
|
||||||
|
ReadWritePermit.ALLOW
|
||||||
|
|
||||||
|
override fun getWritePermit(context: Context, value: Boolean?, myUid: Int, callingUid: Int) =
|
||||||
|
when {
|
||||||
|
dataSaverBackend.isDataSaverEnabled -> ReadWritePermit.DISALLOW
|
||||||
|
else -> ReadWritePermit.ALLOW
|
||||||
|
}
|
||||||
|
|
||||||
|
override val sensitivityLevel
|
||||||
|
get() = SensitivityLevel.HIGH_SENSITIVITY
|
||||||
|
|
||||||
|
override fun createWidget(context: Context) = PrimarySwitchPreference(context)
|
||||||
|
|
||||||
|
override fun storage(context: Context): KeyValueStore = wifiHotspotStore
|
||||||
|
|
||||||
|
private class WifiHotspotStore(private val context: Context) :
|
||||||
|
AbstractKeyedDataObservable<String>(), KeyValueStore {
|
||||||
|
|
||||||
|
private var wifiTetherSoftApManager: WifiTetherSoftApManager? = null
|
||||||
|
var sapState: Int = WifiManager.WIFI_AP_STATE_DISABLED
|
||||||
|
var sapFailureReason: Int? = null
|
||||||
|
var sapClientsSize: Int? = null
|
||||||
|
|
||||||
|
override fun contains(key: String) =
|
||||||
|
key == KEY && context.wifiManager != null && context.tetheringManager != null
|
||||||
|
|
||||||
|
override fun <T : Any> getValue(key: String, valueType: Class<T>): T? {
|
||||||
|
val wifiApState = context.wifiManager?.wifiApState
|
||||||
|
val value =
|
||||||
|
wifiApState == WifiManager.WIFI_AP_STATE_ENABLING ||
|
||||||
|
wifiApState == WifiManager.WIFI_AP_STATE_ENABLED
|
||||||
|
return value as T?
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
|
||||||
|
if (value !is Boolean) return
|
||||||
|
context.tetheringManager?.let {
|
||||||
|
if (value) {
|
||||||
|
val startTetheringCallback =
|
||||||
|
object : TetheringManager.StartTetheringCallback {
|
||||||
|
override fun onTetheringStarted() {
|
||||||
|
Log.d(TAG, "onTetheringStarted()")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTetheringFailed(error: Int) {
|
||||||
|
Log.e(TAG, "onTetheringFailed(),error=$error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
it.startTethering(
|
||||||
|
TetheringManager.TETHERING_WIFI,
|
||||||
|
HandlerExecutor.main,
|
||||||
|
startTetheringCallback,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
it.stopTethering(TetheringManager.TETHERING_WIFI)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFirstObserverAdded() {
|
||||||
|
val wifiSoftApCallback =
|
||||||
|
object : WifiTetherSoftApManager.WifiTetherSoftApCallback {
|
||||||
|
override fun onStateChanged(state: Int, failureReason: Int) {
|
||||||
|
Log.d(TAG, "onStateChanged(),state=$state,failureReason=$failureReason")
|
||||||
|
sapState = state
|
||||||
|
sapFailureReason = failureReason
|
||||||
|
if (state == WifiManager.WIFI_AP_STATE_DISABLED) sapClientsSize = null
|
||||||
|
notifyChange(KEY, DataChangeReason.UPDATE)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onConnectedClientsChanged(clients: List<WifiClient>?) {
|
||||||
|
sapClientsSize = clients?.size ?: 0
|
||||||
|
Log.d(TAG, "onConnectedClientsChanged(),sapClientsSize=$sapClientsSize")
|
||||||
|
notifyChange(KEY, DataChangeReason.UPDATE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wifiTetherSoftApManager =
|
||||||
|
WifiTetherSoftApManager(context.wifiManager, wifiSoftApCallback)
|
||||||
|
wifiTetherSoftApManager?.registerSoftApCallback()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLastObserverRemoved() {
|
||||||
|
wifiTetherSoftApManager?.unRegisterSoftApCallback()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun bind(preference: Preference, metadata: PreferenceMetadata) {
|
||||||
|
super.bind(preference, metadata)
|
||||||
|
(preference as PrimarySwitchPreference).apply {
|
||||||
|
isChecked = preferenceDataStore!!.getBoolean(key, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart(context: PreferenceLifecycleContext) {
|
||||||
|
val listener =
|
||||||
|
DataSaverBackend.Listener { isDataSaving: Boolean ->
|
||||||
|
context.findPreference<PrimarySwitchPreference>(KEY)?.isSwitchEnabled =
|
||||||
|
!isDataSaving
|
||||||
|
context.notifyPreferenceChange(KEY)
|
||||||
|
}
|
||||||
|
dataSaverBackendListener = listener
|
||||||
|
dataSaverBackend.addListener(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop(context: PreferenceLifecycleContext) {
|
||||||
|
dataSaverBackendListener?.let {
|
||||||
|
dataSaverBackend.remListener(it)
|
||||||
|
dataSaverBackendListener = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "WifiHotspotSwitchPreference"
|
||||||
|
const val KEY = "wifi_tether"
|
||||||
|
|
||||||
|
private val Context.wifiManager: WifiManager?
|
||||||
|
get() = applicationContext.getSystemService(WifiManager::class.java)
|
||||||
|
|
||||||
|
private fun Context.getSoftApConfiguration() = wifiManager?.softApConfiguration
|
||||||
|
|
||||||
|
private val Context.tetheringManager: TetheringManager?
|
||||||
|
get() = applicationContext.getSystemService(TetheringManager::class.java)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// LINT.ThenChange(WifiTetherPreferenceController.java)
|
@@ -48,6 +48,7 @@ import com.android.settingslib.wifi.WifiUtils;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
// LINT.IfChange
|
||||||
public class WifiTetherPreferenceController extends AbstractPreferenceController
|
public class WifiTetherPreferenceController extends AbstractPreferenceController
|
||||||
implements PreferenceControllerMixin, LifecycleObserver, OnStart, OnStop,
|
implements PreferenceControllerMixin, LifecycleObserver, OnStart, OnStop,
|
||||||
SwitchWidgetController.OnSwitchChangeListener {
|
SwitchWidgetController.OnSwitchChangeListener {
|
||||||
@@ -251,3 +252,4 @@ public class WifiTetherPreferenceController extends AbstractPreferenceController
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// LINT.ThenChange(WifiHotspotSwitchPreference.kt)
|
||||||
|
@@ -40,6 +40,9 @@ class TetherScreenTest : CatalystScreenTestCase() {
|
|||||||
override val flagName: String
|
override val flagName: String
|
||||||
get() = Flags.FLAG_CATALYST_TETHER_SETTINGS
|
get() = Flags.FLAG_CATALYST_TETHER_SETTINGS
|
||||||
|
|
||||||
|
// TODO: Remove override (See b/368359963#comment7)
|
||||||
|
override fun migration() {}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
ShadowConnectivityManager.getShadow().setTetheringSupported(true)
|
ShadowConnectivityManager.getShadow().setTetheringSupported(true)
|
||||||
|
Reference in New Issue
Block a user