Snap for 11610847 from 14b1831fda to 24Q3-release

Change-Id: Ieb64b8f9d97b63369f83c8dfa7800b8fb8bbee47
This commit is contained in:
Android Build Coastguard Worker
2024-03-21 23:21:11 +00:00
14 changed files with 171 additions and 216 deletions

View File

@@ -143,6 +143,9 @@
<uses-permission android:name="android.permission.MANAGE_GAME_MODE" /> <uses-permission android:name="android.permission.MANAGE_GAME_MODE" />
<uses-permission android:name="android.permission.RESTART_PHONE_PROCESS" /> <uses-permission android:name="android.permission.RESTART_PHONE_PROCESS" />
<uses-permission android:name="android.permission.MANAGE_ENHANCED_CONFIRMATION_STATES" /> <uses-permission android:name="android.permission.MANAGE_ENHANCED_CONFIRMATION_STATES" />
<uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<application <application
android:name=".SettingsApplication" android:name=".SettingsApplication"

View File

@@ -2319,6 +2319,14 @@
<!-- Wi-Fi settings screen, advanced, title of the item to show the randomized Wi-Fi MAC address when disconnected. [CHAR LIMIT=69] --> <!-- Wi-Fi settings screen, advanced, title of the item to show the randomized Wi-Fi MAC address when disconnected. [CHAR LIMIT=69] -->
<string name="wifi_advanced_randomized_mac_address_disconnected_title">Randomized MAC address (last used)</string> <string name="wifi_advanced_randomized_mac_address_disconnected_title">Randomized MAC address (last used)</string>
<!-- Wifi Network Certificates -->
<!-- Wifi certificates summary: More than one certificate -->
<string name="wifi_certificate_summary_Certificates"><xliff:g id="number" example="2">%d</xliff:g> certificates</string>
<!-- Wifi certificates summary: System certificate -->
<string name="wifi_certificate_summary_system">System certificate</string>
<!-- Wifi certificates summary: TOFU certificate -->
<string name="wifi_certificate_summary_pinning">Certificate pinning</string>
<!-- Wifi Network Details --> <!-- Wifi Network Details -->
<!-- Wifi details title--> <!-- Wifi details title-->
<string name="wifi_details_title">Network details</string> <string name="wifi_details_title">Network details</string>
@@ -5838,9 +5846,6 @@
other {# apps restricted} other {# apps restricted}
}</string> }</string>
<!-- Title to display the battery percentage. [CHAR LIMIT=24] -->
<string name="battery_header_title_alternate"><xliff:g id="number" example="88">^1</xliff:g><small> <font size="20"><xliff:g id="unit" example="%">%</xliff:g></font></small></string>
<!-- Summary for top level battery tile if battery is not present. [CHAR LIMIT=NONE] --> <!-- Summary for top level battery tile if battery is not present. [CHAR LIMIT=NONE] -->
<string name="battery_missing_message">Problem reading the battery meter.</string> <string name="battery_missing_message">Problem reading the battery meter.</string>
<!-- Help text if battery is not present. [CHAR LIMIT=NONE] --> <!-- Help text if battery is not present. [CHAR LIMIT=NONE] -->
@@ -6263,6 +6268,10 @@
<string name="credential_for_vpn_and_apps">Installed for VPN and apps</string> <string name="credential_for_vpn_and_apps">Installed for VPN and apps</string>
<!-- Sub-heading for a user credential installed for Wi-Fi configuration. [CHAR LIMIT=NONE]. --> <!-- Sub-heading for a user credential installed for Wi-Fi configuration. [CHAR LIMIT=NONE]. -->
<string name="credential_for_wifi">Installed for Wi\u2011Fi</string> <string name="credential_for_wifi">Installed for Wi\u2011Fi</string>
<!-- Sub-heading for a user credential installed for particular Wi-Fi configuration. [CHAR LIMIT=NONE]. -->
<string name="credential_installed_for_wifi">Installed for <xliff:g id="ssid" example="SSID">%s</xliff:g></string>
<!-- Sub-heading for a user credential using for Wi-Fi configuration. [CHAR LIMIT=NONE]. -->
<string name="credential_using_for_wifi">Using for <xliff:g id="ssid" example="SSID">%s</xliff:g></string>
<!-- Sub-heading for a user credential installed to be used as part of a Wi-Fi configuration. [CHAR LIMIT=NONE]. --> <!-- Sub-heading for a user credential installed to be used as part of a Wi-Fi configuration. [CHAR LIMIT=NONE]. -->
<string name="credential_for_wifi_in_use">Installed for Wi\u2011Fi (In use)</string> <string name="credential_for_wifi_in_use">Installed for Wi\u2011Fi (In use)</string>
<!-- Description of dialog to reset credential storage [CHAR LIMIT=NONE] --> <!-- Description of dialog to reset credential storage [CHAR LIMIT=NONE] -->

View File

@@ -16,11 +16,8 @@
package com.android.settings.bluetooth; package com.android.settings.bluetooth;
import android.bluetooth.BluetoothAdapter;
import android.content.Context; import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@@ -30,27 +27,33 @@ import androidx.preference.PreferenceScreen;
import androidx.preference.TwoStatePreference; import androidx.preference.TwoStatePreference;
import com.android.settings.core.TogglePreferenceController; import com.android.settings.core.TogglePreferenceController;
import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop; import com.android.settingslib.core.lifecycle.events.OnStop;
import com.android.settingslib.flags.Flags;
import com.android.settingslib.utils.ThreadUtils; import com.android.settingslib.utils.ThreadUtils;
public class BluetoothAutoOnPreferenceController extends TogglePreferenceController public class BluetoothAutoOnPreferenceController extends TogglePreferenceController
implements LifecycleObserver, OnStart, OnStop { implements BluetoothCallback, LifecycleObserver, OnStart, OnStop {
private static final String TAG = "BluetoothAutoOnPreferenceController"; private static final String TAG = "BluetoothAutoOnPrefCtlr";
@VisibleForTesting static final String PREF_KEY = "bluetooth_auto_on_settings_toggle"; @VisibleForTesting static final String PREF_KEY = "bluetooth_auto_on_settings_toggle";
static final String SETTING_NAME = "bluetooth_automatic_turn_on"; @VisibleForTesting BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
static final int UNSET = -1; private final LocalBluetoothManager mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
@VisibleForTesting static final int ENABLED = 1; private boolean mAutoOnValue = false;
@VisibleForTesting static final int DISABLED = 0; @Nullable private TwoStatePreference mPreference;
private final ContentObserver mContentObserver =
new ContentObserver(new Handler(/* async= */ true)) { public BluetoothAutoOnPreferenceController(
@NonNull Context context, @NonNull String preferenceKey) {
super(context, preferenceKey);
}
@Override @Override
public void onChange(boolean selfChange) { public void onAutoOnStateChanged(int state) {
var unused = var unused =
ThreadUtils.postOnBackgroundThread( ThreadUtils.postOnBackgroundThread(
() -> { () -> {
Log.i(TAG, "onAutoOnStateChanged() state: " + state);
updateValue(); updateValue();
mContext.getMainExecutor() mContext.getMainExecutor()
.execute( .execute(
@@ -61,36 +64,39 @@ public class BluetoothAutoOnPreferenceController extends TogglePreferenceControl
}); });
}); });
} }
};
private int mAutoOnValue = UNSET;
@Nullable private TwoStatePreference mPreference;
public BluetoothAutoOnPreferenceController(
@NonNull Context context, @NonNull String preferenceKey) {
super(context, preferenceKey);
}
@Override @Override
public void onStart() { public void onStart() {
mContext.getContentResolver() if (mLocalBluetoothManager == null) {
.registerContentObserver( return;
Settings.Secure.getUriFor(SETTING_NAME), }
/* notifyForDescendants= */ false, mLocalBluetoothManager.getEventManager().registerCallback(this);
mContentObserver);
} }
@Override @Override
public void onStop() { public void onStop() {
mContext.getContentResolver().unregisterContentObserver(mContentObserver); if (mLocalBluetoothManager == null) {
return;
}
mLocalBluetoothManager.getEventManager().unregisterCallback(this);
} }
@Override @Override
public int getAvailabilityStatus() { public int getAvailabilityStatus() {
if (!Flags.bluetoothQsTileDialogAutoOnToggle()) { if (mBluetoothAdapter == null) {
return UNSUPPORTED_ON_DEVICE;
}
try {
boolean isSupported = mBluetoothAdapter.isAutoOnSupported();
Log.i(TAG, "getAvailabilityStatus() isSupported: " + isSupported);
if (isSupported) {
var unused = ThreadUtils.postOnBackgroundThread(this::updateValue);
}
return isSupported ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
} catch (Exception e) {
// Server could throw TimeoutException, InterruptedException or ExecutionException
return UNSUPPORTED_ON_DEVICE; return UNSUPPORTED_ON_DEVICE;
} }
updateValue();
return mAutoOnValue != UNSET ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
} }
@Override @Override
@@ -106,26 +112,20 @@ public class BluetoothAutoOnPreferenceController extends TogglePreferenceControl
@Override @Override
public boolean isChecked() { public boolean isChecked() {
return mAutoOnValue == ENABLED; return mAutoOnValue;
} }
@Override @Override
public boolean setChecked(boolean isChecked) { public boolean setChecked(boolean isChecked) {
if (getAvailabilityStatus() != AVAILABLE) {
Log.w(TAG, "Trying to set toggle value while feature not available.");
return false;
}
var unused = var unused =
ThreadUtils.postOnBackgroundThread( ThreadUtils.postOnBackgroundThread(
() -> { () -> {
boolean updated = try {
Settings.Secure.putIntForUser( mBluetoothAdapter.setAutoOnEnabled(isChecked);
mContext.getContentResolver(), } catch (Exception e) {
SETTING_NAME, // Server could throw IllegalStateException, TimeoutException,
isChecked ? ENABLED : DISABLED, // InterruptedException or ExecutionException
UserHandle.myUserId()); Log.e(TAG, "Error calling setAutoOnEnabled()", e);
if (updated) {
updateValue();
} }
}); });
return true; return true;
@@ -137,8 +137,14 @@ public class BluetoothAutoOnPreferenceController extends TogglePreferenceControl
} }
private void updateValue() { private void updateValue() {
mAutoOnValue = if (mBluetoothAdapter == null) {
Settings.Secure.getIntForUser( return;
mContext.getContentResolver(), SETTING_NAME, UNSET, UserHandle.myUserId()); }
try {
mAutoOnValue = mBluetoothAdapter.isAutoOnEnabled();
} catch (Exception e) {
// Server could throw TimeoutException, InterruptedException or ExecutionException
Log.e(TAG, "Error calling isAutoOnEnabled()", e);
}
} }
} }

View File

@@ -15,13 +15,10 @@
*/ */
package com.android.settings.bluetooth; package com.android.settings.bluetooth;
import static com.android.settings.bluetooth.BluetoothAutoOnPreferenceController.SETTING_NAME;
import static com.android.settings.bluetooth.BluetoothAutoOnPreferenceController.UNSET;
import android.app.settings.SettingsEnums; import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothAdapter;
import android.content.Context; import android.content.Context;
import android.os.UserHandle; import android.util.Log;
import android.provider.Settings;
import android.view.View; import android.view.View;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
@@ -34,7 +31,6 @@ import com.android.settings.widget.SwitchWidgetController;
import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop; import com.android.settingslib.core.lifecycle.events.OnStop;
import com.android.settingslib.flags.Flags;
import com.android.settingslib.widget.FooterPreference; import com.android.settingslib.widget.FooterPreference;
/** /**
@@ -47,11 +43,13 @@ public class BluetoothSwitchPreferenceController
OnStop, OnStop,
SwitchWidgetController.OnSwitchChangeListener, SwitchWidgetController.OnSwitchChangeListener,
View.OnClickListener { View.OnClickListener {
private static final String TAG = "BluetoothSwitchPrefCtrl";
private BluetoothEnabler mBluetoothEnabler; private BluetoothEnabler mBluetoothEnabler;
private RestrictionUtils mRestrictionUtils; private RestrictionUtils mRestrictionUtils;
private SwitchWidgetController mSwitch; private SwitchWidgetController mSwitch;
private Context mContext; private Context mContext;
private BluetoothAdapter mBluetoothAdapter;
private FooterPreference mFooterPreference; private FooterPreference mFooterPreference;
private boolean mIsAlwaysDiscoverable; private boolean mIsAlwaysDiscoverable;
@@ -87,6 +85,7 @@ public class BluetoothSwitchPreferenceController
mRestrictionUtils); mRestrictionUtils);
mBluetoothEnabler.setToggleCallback(this); mBluetoothEnabler.setToggleCallback(this);
mAlwaysDiscoverable = new AlwaysDiscoverable(context); mAlwaysDiscoverable = new AlwaysDiscoverable(context);
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
} }
@Override @Override
@@ -157,11 +156,15 @@ public class BluetoothSwitchPreferenceController
} }
private boolean isAutoOnFeatureAvailable() { private boolean isAutoOnFeatureAvailable() {
if (!Flags.bluetoothQsTileDialogAutoOnToggle()) { if (mBluetoothAdapter == null) {
return false;
}
try {
return mBluetoothAdapter.isAutoOnSupported();
} catch (Exception e) {
// Server could throw TimeoutException, InterruptedException or ExecutionException
Log.e(TAG, "Error calling isAutoOnFeatureAvailable()", e);
return false; return false;
} }
return Settings.Secure.getIntForUser(
mContext.getContentResolver(), SETTING_NAME, UNSET, UserHandle.myUserId())
!= UNSET;
} }
} }

View File

@@ -17,10 +17,8 @@ package com.android.settings.fuelgauge;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.icu.text.NumberFormat;
import android.os.BatteryManager; import android.os.BatteryManager;
import android.os.PowerManager; import android.os.PowerManager;
import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
@@ -145,8 +143,6 @@ public class BatteryHeaderPreferenceController extends BasePreferenceController
} }
private CharSequence formatBatteryPercentageText(int batteryLevel) { private CharSequence formatBatteryPercentageText(int batteryLevel) {
return TextUtils.expandTemplate( return com.android.settings.Utils.formatPercentage(batteryLevel);
mContext.getText(R.string.battery_header_title_alternate),
NumberFormat.getIntegerInstance().format(batteryLevel));
} }
} }

View File

@@ -295,7 +295,9 @@ public class MobileNetworkRepository extends SubscriptionManager.OnSubscriptions
} }
public void removeRegister(MobileNetworkCallback mobileNetworkCallback) { public void removeRegister(MobileNetworkCallback mobileNetworkCallback) {
synchronized (this) {
sCallbacks.remove(mobileNetworkCallback); sCallbacks.remove(mobileNetworkCallback);
}
if (sCallbacks.isEmpty()) { if (sCallbacks.isEmpty()) {
mSubscriptionManager.removeOnSubscriptionsChangedListener(this); mSubscriptionManager.removeOnSubscriptionsChangedListener(this);
mAirplaneModeObserver.unRegister(mContext); mAirplaneModeObserver.unRegister(mContext);

View File

@@ -18,6 +18,7 @@ package com.android.settings.network.apn
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.provider.Telephony
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
@@ -142,39 +143,39 @@ fun ApnPage(apnDataInit: ApnData, apnDataCur: MutableState<ApnData>, uriInit: Ur
SettingsOutlinedTextField( SettingsOutlinedTextField(
value = apnData.name, value = apnData.name,
label = stringResource(R.string.apn_name), label = stringResource(R.string.apn_name),
enabled = apnData.nameEnabled, enabled = apnData.isFieldEnabled(Telephony.Carriers.NAME),
errorMessage = validateName(apnData.validEnabled, apnData.name, context) errorMessage = validateName(apnData.validEnabled, apnData.name, context)
) { apnData = apnData.copy(name = it) } ) { apnData = apnData.copy(name = it) }
SettingsOutlinedTextField( SettingsOutlinedTextField(
value = apnData.apn, value = apnData.apn,
label = stringResource(R.string.apn_apn), label = stringResource(R.string.apn_apn),
enabled = apnData.apnEnabled, enabled = apnData.isFieldEnabled(Telephony.Carriers.APN),
errorMessage = validateAPN(apnData.validEnabled, apnData.apn, context) errorMessage = validateAPN(apnData.validEnabled, apnData.apn, context)
) { apnData = apnData.copy(apn = it) } ) { apnData = apnData.copy(apn = it) }
SettingsOutlinedTextField( SettingsOutlinedTextField(
value = apnData.proxy, value = apnData.proxy,
label = stringResource(R.string.apn_http_proxy), label = stringResource(R.string.apn_http_proxy),
enabled = apnData.proxyEnabled enabled = apnData.isFieldEnabled(Telephony.Carriers.PROXY),
) { apnData = apnData.copy(proxy = it) } ) { apnData = apnData.copy(proxy = it) }
SettingsOutlinedTextField( SettingsOutlinedTextField(
value = apnData.port, value = apnData.port,
label = stringResource(R.string.apn_http_port), label = stringResource(R.string.apn_http_port),
enabled = apnData.portEnabled enabled = apnData.isFieldEnabled(Telephony.Carriers.PORT),
) { apnData = apnData.copy(port = it) } ) { apnData = apnData.copy(port = it) }
SettingsOutlinedTextField( SettingsOutlinedTextField(
value = apnData.userName, value = apnData.userName,
label = stringResource(R.string.apn_user), label = stringResource(R.string.apn_user),
enabled = apnData.userNameEnabled enabled = apnData.isFieldEnabled(Telephony.Carriers.USER),
) { apnData = apnData.copy(userName = it) } ) { apnData = apnData.copy(userName = it) }
SettingsTextFieldPassword( SettingsTextFieldPassword(
value = apnData.passWord, value = apnData.passWord,
label = stringResource(R.string.apn_password), label = stringResource(R.string.apn_password),
enabled = apnData.passWordEnabled enabled = apnData.isFieldEnabled(Telephony.Carriers.PASSWORD),
) { apnData = apnData.copy(passWord = it) } ) { apnData = apnData.copy(passWord = it) }
SettingsOutlinedTextField( SettingsOutlinedTextField(
value = apnData.server, value = apnData.server,
label = stringResource(R.string.apn_server), label = stringResource(R.string.apn_server),
enabled = apnData.serverEnabled enabled = apnData.isFieldEnabled(Telephony.Carriers.SERVER),
) { apnData = apnData.copy(server = it) } ) { apnData = apnData.copy(server = it) }
ApnTypeCheckBox( ApnTypeCheckBox(
apnData = apnData, apnData = apnData,
@@ -186,42 +187,45 @@ fun ApnPage(apnDataInit: ApnData, apnDataCur: MutableState<ApnData>, uriInit: Ur
value = apnData.mmsc, value = apnData.mmsc,
label = stringResource(R.string.apn_mmsc), label = stringResource(R.string.apn_mmsc),
errorMessage = validateMMSC(apnData.validEnabled, apnData.mmsc, context), errorMessage = validateMMSC(apnData.validEnabled, apnData.mmsc, context),
enabled = apnData.mmscEnabled enabled = apnData.isFieldEnabled(Telephony.Carriers.MMSC),
) { apnData = apnData.copy(mmsc = it) } ) { apnData = apnData.copy(mmsc = it) }
SettingsOutlinedTextField( SettingsOutlinedTextField(
value = apnData.mmsProxy, value = apnData.mmsProxy,
label = stringResource(R.string.apn_mms_proxy), label = stringResource(R.string.apn_mms_proxy),
enabled = apnData.mmsProxyEnabled enabled = apnData.isFieldEnabled(Telephony.Carriers.MMSPROXY),
) { apnData = apnData.copy(mmsProxy = it) } ) { apnData = apnData.copy(mmsProxy = it) }
SettingsOutlinedTextField( SettingsOutlinedTextField(
value = apnData.mmsPort, value = apnData.mmsPort,
label = stringResource(R.string.apn_mms_port), label = stringResource(R.string.apn_mms_port),
enabled = apnData.mmsPortEnabled enabled = apnData.isFieldEnabled(Telephony.Carriers.MMSPORT),
) { apnData = apnData.copy(mmsPort = it) } ) { apnData = apnData.copy(mmsPort = it) }
} }
SettingsDropdownBox( SettingsDropdownBox(
label = stringResource(R.string.apn_auth_type), label = stringResource(R.string.apn_auth_type),
options = authTypeOptions, options = authTypeOptions,
selectedOptionIndex = apnData.authType, selectedOptionIndex = apnData.authType,
enabled = apnData.authTypeEnabled, enabled = apnData.isFieldEnabled(Telephony.Carriers.AUTH_TYPE),
) { apnData = apnData.copy(authType = it) } ) { apnData = apnData.copy(authType = it) }
SettingsDropdownBox( SettingsDropdownBox(
label = stringResource(R.string.apn_protocol), label = stringResource(R.string.apn_protocol),
options = apnProtocolOptions, options = apnProtocolOptions,
selectedOptionIndex = apnData.apnProtocol, selectedOptionIndex = apnData.apnProtocol,
enabled = apnData.apnProtocolEnabled enabled = apnData.isFieldEnabled(Telephony.Carriers.PROTOCOL),
) { apnData = apnData.copy(apnProtocol = it) } ) { apnData = apnData.copy(apnProtocol = it) }
SettingsDropdownBox( SettingsDropdownBox(
label = stringResource(R.string.apn_roaming_protocol), label = stringResource(R.string.apn_roaming_protocol),
options = apnProtocolOptions, options = apnProtocolOptions,
selectedOptionIndex = apnData.apnRoaming, selectedOptionIndex = apnData.apnRoaming,
enabled = apnData.apnRoamingEnabled enabled = apnData.isFieldEnabled(Telephony.Carriers.ROAMING_PROTOCOL),
) { apnData = apnData.copy(apnRoaming = it) } ) { apnData = apnData.copy(apnRoaming = it) }
ApnNetworkTypeCheckBox(apnData) { apnData = apnData.copy(networkType = it) } ApnNetworkTypeCheckBox(apnData) { apnData = apnData.copy(networkType = it) }
SwitchPreference( SwitchPreference(
object : SwitchPreferenceModel { object : SwitchPreferenceModel {
override val title = context.resources.getString(R.string.carrier_enabled) override val title = stringResource(R.string.carrier_enabled)
override val changeable = { apnData.apnEnableEnabled } override val changeable = {
apnData.apnEnableEnabled &&
apnData.isFieldEnabled(Telephony.Carriers.CARRIER_ENABLED)
}
override val checked = { apnData.apnEnable } override val checked = { apnData.apnEnable }
override val onCheckedChange = { newChecked: Boolean -> override val onCheckedChange = { newChecked: Boolean ->
apnData = apnData.copy(apnEnable = newChecked) apnData = apnData.copy(apnEnable = newChecked)

View File

@@ -16,6 +16,7 @@
package com.android.settings.network.apn package com.android.settings.network.apn
import android.provider.Telephony
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@@ -29,7 +30,11 @@ fun ApnNetworkTypeCheckBox(apnData: ApnData, onNetworkTypeChanged: (Long) -> Uni
label = stringResource(R.string.network_type), label = stringResource(R.string.network_type),
options = options, options = options,
emptyText = stringResource(R.string.network_type_unspecified), emptyText = stringResource(R.string.network_type_unspecified),
enabled = apnData.networkTypeEnabled, enabled = apnData.isFieldEnabled(
Telephony.Carriers.BEARER,
Telephony.Carriers.BEARER_BITMASK,
Telephony.Carriers.NETWORK_TYPE_BITMASK
),
) { ) {
onNetworkTypeChanged(ApnNetworkTypes.optionsToNetworkType(options)) onNetworkTypeChanged(ApnNetworkTypes.optionsToNetworkType(options))
} }

View File

@@ -48,22 +48,7 @@ data class ApnData(
val networkType: Long = 0, val networkType: Long = 0,
val edited: Int = Telephony.Carriers.USER_EDITED, val edited: Int = Telephony.Carriers.USER_EDITED,
val userEditable: Int = 1, val userEditable: Int = 1,
val nameEnabled: Boolean = true,
val apnEnabled: Boolean = true,
val proxyEnabled: Boolean = true,
val portEnabled: Boolean = true,
val userNameEnabled: Boolean = true,
val passWordEnabled: Boolean = true,
val serverEnabled: Boolean = true,
val mmscEnabled: Boolean = true,
val mmsProxyEnabled: Boolean = true,
val mmsPortEnabled: Boolean = true,
val authTypeEnabled: Boolean = true,
val apnTypeEnabled: Boolean = true,
val apnProtocolEnabled: Boolean = true,
val apnRoamingEnabled: Boolean = true,
val apnEnableEnabled: Boolean = true, val apnEnableEnabled: Boolean = true,
val networkTypeEnabled: Boolean = true,
val newApn: Boolean = false, val newApn: Boolean = false,
val subId: Int = -1, val subId: Int = -1,
val validEnabled: Boolean = false, val validEnabled: Boolean = false,
@@ -93,6 +78,10 @@ data class ApnData(
if (newApn) context.getApnIdMap(subId).forEach(::putObject) if (newApn) context.getApnIdMap(subId).forEach(::putObject)
getContentValueMap(context).forEach(::putObject) getContentValueMap(context).forEach(::putObject)
} }
fun isFieldEnabled(vararg fieldName: String): Boolean =
!customizedConfig.readOnlyApn &&
fieldName.all { it !in customizedConfig.readOnlyApnFields }
} }
data class CustomizedConfig( data class CustomizedConfig(
@@ -271,83 +260,17 @@ private fun ApnData.isReadOnly(): Boolean {
fun disableInit(apnDataInit: ApnData): ApnData { fun disableInit(apnDataInit: ApnData): ApnData {
if (apnDataInit.isReadOnly()) { if (apnDataInit.isReadOnly()) {
Log.d(TAG, "disableInit: read-only APN") Log.d(TAG, "disableInit: read-only APN")
val apnData = apnDataInit.copy( return apnDataInit.copy(
customizedConfig = apnDataInit.customizedConfig.copy(readOnlyApn = true) customizedConfig = apnDataInit.customizedConfig.copy(readOnlyApn = true)
) )
return disableAllFields(apnData)
} }
val readOnlyApnFields = apnDataInit.customizedConfig.readOnlyApnFields val readOnlyApnFields = apnDataInit.customizedConfig.readOnlyApnFields
if (readOnlyApnFields.isNotEmpty()) { if (readOnlyApnFields.isNotEmpty()) {
Log.d(TAG, "disableInit: readOnlyApnFields $readOnlyApnFields)") Log.d(TAG, "disableInit: readOnlyApnFields $readOnlyApnFields)")
return disableFields(readOnlyApnFields, apnDataInit)
} }
return apnDataInit return apnDataInit
} }
/**
* Disables all fields so that user cannot modify the APN
*/
private fun disableAllFields(apnDataInit: ApnData): ApnData {
var apnData = apnDataInit
apnData = apnData.copy(nameEnabled = false)
apnData = apnData.copy(apnEnabled = false)
apnData = apnData.copy(proxyEnabled = false)
apnData = apnData.copy(portEnabled = false)
apnData = apnData.copy(userNameEnabled = false)
apnData = apnData.copy(passWordEnabled = false)
apnData = apnData.copy(serverEnabled = false)
apnData = apnData.copy(mmscEnabled = false)
apnData = apnData.copy(mmsProxyEnabled = false)
apnData = apnData.copy(mmsPortEnabled = false)
apnData = apnData.copy(authTypeEnabled = false)
apnData = apnData.copy(apnTypeEnabled = false)
apnData = apnData.copy(apnProtocolEnabled = false)
apnData = apnData.copy(apnRoamingEnabled = false)
apnData = apnData.copy(apnEnableEnabled = false)
apnData = apnData.copy(networkTypeEnabled = false)
return apnData
}
/**
* Disables given fields so that user cannot modify them
*
* @param apnFields fields to be disabled
*/
private fun disableFields(apnFields: List<String>, apnDataInit: ApnData): ApnData {
var apnData = apnDataInit
for (apnField in apnFields) {
apnData = disableByFieldName(apnField, apnDataInit)
}
return apnData
}
private fun disableByFieldName(apnField: String, apnDataInit: ApnData): ApnData {
var apnData = apnDataInit
when (apnField) {
Telephony.Carriers.NAME -> apnData = apnData.copy(nameEnabled = false)
Telephony.Carriers.APN -> apnData = apnData.copy(apnEnabled = false)
Telephony.Carriers.PROXY -> apnData = apnData.copy(proxyEnabled = false)
Telephony.Carriers.PORT -> apnData = apnData.copy(portEnabled = false)
Telephony.Carriers.USER -> apnData = apnData.copy(userNameEnabled = false)
Telephony.Carriers.SERVER -> apnData = apnData.copy(serverEnabled = false)
Telephony.Carriers.PASSWORD -> apnData = apnData.copy(passWordEnabled = false)
Telephony.Carriers.MMSPROXY -> apnData = apnData.copy(mmsProxyEnabled = false)
Telephony.Carriers.MMSPORT -> apnData = apnData.copy(mmsPortEnabled = false)
Telephony.Carriers.MMSC -> apnData = apnData.copy(mmscEnabled = false)
Telephony.Carriers.TYPE -> apnData = apnData.copy(apnTypeEnabled = false)
Telephony.Carriers.AUTH_TYPE -> apnData = apnData.copy(authTypeEnabled = false)
Telephony.Carriers.PROTOCOL -> apnData = apnData.copy(apnProtocolEnabled = false)
Telephony.Carriers.ROAMING_PROTOCOL -> apnData = apnData.copy(apnRoamingEnabled = false)
Telephony.Carriers.CARRIER_ENABLED -> apnData = apnData.copy(apnEnableEnabled = false)
Telephony.Carriers.BEARER, Telephony.Carriers.BEARER_BITMASK,
Telephony.Carriers.NETWORK_TYPE_BITMASK -> apnData = apnData.copy(
networkTypeEnabled =
false
)
}
return apnData
}
fun deleteApn(uri: Uri, context: Context) { fun deleteApn(uri: Uri, context: Context) {
val contentResolver = context.contentResolver val contentResolver = context.contentResolver
contentResolver.delete(uri, null, null) contentResolver.delete(uri, null, null)

View File

@@ -16,6 +16,7 @@
package com.android.settings.network.apn package com.android.settings.network.apn
import android.provider.Telephony
import android.telephony.data.ApnSetting import android.telephony.data.ApnSetting
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
@@ -45,7 +46,7 @@ fun ApnTypeCheckBox(
SettingsDropdownCheckBox( SettingsDropdownCheckBox(
label = stringResource(R.string.apn_type), label = stringResource(R.string.apn_type),
options = apnTypeOptions, options = apnTypeOptions,
enabled = apnData.apnTypeEnabled, enabled = apnData.isFieldEnabled(Telephony.Carriers.TYPE),
) { ) {
onTypeChanged(apnTypeOptions.toApnType()) onTypeChanged(apnTypeOptions.toApnType())
updateMmsSelected() updateMmsSelected()

View File

@@ -16,82 +16,62 @@
package com.android.settings.bluetooth; package com.android.settings.bluetooth;
import static com.android.settings.bluetooth.BluetoothAutoOnPreferenceController.DISABLED;
import static com.android.settings.bluetooth.BluetoothAutoOnPreferenceController.ENABLED;
import static com.android.settings.bluetooth.BluetoothAutoOnPreferenceController.PREF_KEY; import static com.android.settings.bluetooth.BluetoothAutoOnPreferenceController.PREF_KEY;
import static com.android.settings.bluetooth.BluetoothAutoOnPreferenceController.SETTING_NAME;
import static com.android.settings.bluetooth.BluetoothAutoOnPreferenceController.UNSET;
import static com.android.settings.core.BasePreferenceController.AVAILABLE; import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
import static com.android.settingslib.flags.Flags.FLAG_BLUETOOTH_QS_TILE_DIALOG_AUTO_ON_TOGGLE;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import android.bluetooth.BluetoothAdapter;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class BluetoothAutoOnPreferenceControllerTest { public class BluetoothAutoOnPreferenceControllerTest {
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private Context mContext; private Context mContext;
private ContentResolver mContentResolver; private ContentResolver mContentResolver;
private BluetoothAutoOnPreferenceController mController; private BluetoothAutoOnPreferenceController mController;
private BluetoothAdapter mBluetoothAdapter;
@Before @Before
public void setUp() { public void setUp() {
mSetFlagsRule.enableFlags(FLAG_BLUETOOTH_QS_TILE_DIALOG_AUTO_ON_TOGGLE);
mContext = spy(ApplicationProvider.getApplicationContext()); mContext = spy(ApplicationProvider.getApplicationContext());
mContentResolver = mContext.getContentResolver(); mContentResolver = mContext.getContentResolver();
mController = new BluetoothAutoOnPreferenceController(mContext, PREF_KEY); mController = new BluetoothAutoOnPreferenceController(mContext, PREF_KEY);
mBluetoothAdapter = spy(BluetoothAdapter.getDefaultAdapter());
mController.mBluetoothAdapter = mBluetoothAdapter;
} }
@Test @Test
public void getAvailability_valueUnset_returnUnsupported() { public void getAvailability_valueUnset_returnUnsupported() {
Settings.Secure.putInt(mContentResolver, SETTING_NAME, UNSET); doReturn(false).when(mBluetoothAdapter).isAutoOnSupported();
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
} }
@Test @Test
public void getAvailability_valueSet_returnAvailable() { public void getAvailability_valueSet_returnAvailable() {
Settings.Secure.putInt(mContentResolver, SETTING_NAME, DISABLED); doReturn(true).when(mBluetoothAdapter).isAutoOnSupported();
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
} }
@Test @Test
public void isChecked_valueEnabled_returnTrue() { public void isChecked_valueEnabled_returnTrue() {
Settings.Secure.putInt(mContentResolver, SETTING_NAME, ENABLED); doReturn(true).when(mBluetoothAdapter).isAutoOnSupported();
doReturn(true).when(mBluetoothAdapter).isAutoOnEnabled();
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
assertThat(mController.isChecked()).isEqualTo(true); assertThat(mController.isChecked()).isEqualTo(true);
} }
@Test
public void setChecked_returnTrue() {
Settings.Secure.putInt(mContentResolver, SETTING_NAME, DISABLED);
mController.setChecked(true);
assertThat(mController.isChecked()).isEqualTo(true);
}
@Test
public void setChecked_returnFalse() {
Settings.Secure.putInt(mContentResolver, SETTING_NAME, ENABLED);
mController.setChecked(false);
assertThat(mController.isChecked()).isEqualTo(false);
}
} }

View File

@@ -28,10 +28,8 @@ import android.content.Intent;
import android.hardware.usb.UsbManager; import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbPort; import android.hardware.usb.UsbPort;
import android.hardware.usb.UsbPortStatus; import android.hardware.usb.UsbPortStatus;
import android.icu.text.NumberFormat;
import android.os.BatteryManager; import android.os.BatteryManager;
import android.os.PowerManager; import android.os.PowerManager;
import android.text.TextUtils;
import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceScreen;
@@ -320,9 +318,7 @@ public class BatteryHeaderPreferenceControllerTest {
} }
private CharSequence formatBatteryPercentageText() { private CharSequence formatBatteryPercentageText() {
return TextUtils.expandTemplate( return com.android.settings.Utils.formatPercentage(BATTERY_LEVEL);
mContext.getText(R.string.battery_header_title_alternate),
NumberFormat.getIntegerInstance().format(BATTERY_LEVEL));
} }
private void setChargingState(boolean isDischarging, boolean updatedByStatusFeature) { private void setChargingState(boolean isDischarging, boolean updatedByStatusFeature) {

View File

@@ -19,12 +19,9 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="com.android.settings.tests.spa_unit"> package="com.android.settings.tests.spa_unit">
<uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
<uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" /> <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" />
<uses-permission android:name="android.permission.MANAGE_APPOPS" /> <uses-permission android:name="android.permission.MANAGE_APPOPS" />
<uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
<uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" /> <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" /> <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
<uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" /> <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" />

View File

@@ -17,8 +17,10 @@
package com.android.settings.network.apn package com.android.settings.network.apn
import android.os.PersistableBundle import android.os.PersistableBundle
import android.provider.Telephony
import android.telephony.CarrierConfigManager import android.telephony.CarrierConfigManager
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.kotlin.doReturn import org.mockito.kotlin.doReturn
@@ -26,11 +28,8 @@ import org.mockito.kotlin.mock
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class ApnStatusTest { class ApnStatusTest {
private val apnData = mock<ApnData> { private val apnData = ApnData(subId = 1)
on {
it.subId
} doReturn 1
}
private val configManager = mock<CarrierConfigManager> { private val configManager = mock<CarrierConfigManager> {
val p = PersistableBundle() val p = PersistableBundle()
p.putBoolean(CarrierConfigManager.KEY_ALLOW_ADDING_APNS_BOOL, true) p.putBoolean(CarrierConfigManager.KEY_ALLOW_ADDING_APNS_BOOL, true)
@@ -51,4 +50,35 @@ class ApnStatusTest {
fun getCarrierCustomizedConfig_test() { fun getCarrierCustomizedConfig_test() {
assert(getCarrierCustomizedConfig(apnData, configManager).isAddApnAllowed) assert(getCarrierCustomizedConfig(apnData, configManager).isAddApnAllowed)
} }
@Test
fun isFieldEnabled_default() {
val apnData = ApnData()
val enabled = apnData.isFieldEnabled(Telephony.Carriers.NAME)
assertThat(enabled).isTrue()
}
@Test
fun isFieldEnabled_readOnlyApn() {
val apnData = ApnData(customizedConfig = CustomizedConfig(readOnlyApn = true))
val enabled = apnData.isFieldEnabled(Telephony.Carriers.NAME)
assertThat(enabled).isFalse()
}
@Test
fun isFieldEnabled_readOnlyApnFields() {
val apnData = ApnData(
customizedConfig = CustomizedConfig(
readOnlyApnFields = listOf(Telephony.Carriers.NAME, Telephony.Carriers.PROXY),
),
)
assertThat(apnData.isFieldEnabled(Telephony.Carriers.NAME)).isFalse()
assertThat(apnData.isFieldEnabled(Telephony.Carriers.PROXY)).isFalse()
assertThat(apnData.isFieldEnabled(Telephony.Carriers.APN)).isTrue()
}
} }