Merge "Show LE audio toggle summary as default connection is classic" into main
diff --git a/res/layout-v34/settingslib_main_switch.xml b/res/layout-v34/settingslib_main_switch.xml
deleted file mode 100644
index 5ce4581..0000000
--- a/res/layout-v34/settingslib_main_switch.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2023 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.
- -->
-
-<com.google.android.material.materialswitch.MaterialSwitch
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/switch_widget"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:background="@null"
- android:clickable="false"
- android:focusable="false"
- android:theme="@style/Theme.Material3.DynamicColors.DayNight" />
diff --git a/res/layout-v34/settingslib_main_switch_bar.xml b/res/layout-v34/settingslib_main_switch_bar.xml
new file mode 100644
index 0000000..3a44d2a
--- /dev/null
+++ b/res/layout-v34/settingslib_main_switch_bar.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2023 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.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingTop="@dimen/settingslib_switchbar_margin"
+ android:paddingBottom="@dimen/settingslib_switchbar_margin"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:id="@+id/frame"
+ android:minHeight="@dimen/settingslib_min_switch_bar_height"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:paddingStart="@dimen/settingslib_switchbar_padding_left"
+ android:paddingEnd="@dimen/settingslib_switchbar_padding_right"
+ android:background="@drawable/settingslib_switch_bar_bg">
+
+ <TextView
+ android:id="@+id/switch_text"
+ android:layout_height="wrap_content"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_marginEnd="@dimen/settingslib_switch_title_margin"
+ android:layout_marginVertical="@dimen/settingslib_switch_title_margin"
+ android:layout_gravity="center_vertical"
+ android:ellipsize="end"
+ android:textAppearance="?android:attr/textAppearanceListItem"
+ android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
+ style="@style/MainSwitchText.Settingslib" />
+
+ <com.google.android.material.materialswitch.MaterialSwitch
+ android:id="@android:id/switch_widget"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:background="@null"
+ android:clickable="false"
+ android:focusable="false"
+ android:theme="@style/Theme.Material3.DynamicColors.DayNight" />
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/res/xml/bluetooth_audio_streams_qr_code.xml b/res/xml/bluetooth_audio_streams_qr_code.xml
new file mode 100644
index 0000000..c750963
--- /dev/null
+++ b/res/xml/bluetooth_audio_streams_qr_code.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 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.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipToPadding="false"
+ android:paddingLeft="25dp"
+ android:paddingRight="25dp"
+ android:gravity="center_horizontal"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="start"
+ android:textSize="15sp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:text="Scan this QR code with another device connected to LE audio headphones to start sharing audio"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:orientation="vertical"
+ android:paddingTop="70dp">
+
+ <ImageView
+ android:id="@+id/qrcode_view"
+ android:layout_width="@dimen/qrcode_size"
+ android:layout_height="@dimen/qrcode_size"
+ android:src="@android:color/transparent"/>
+ </LinearLayout>
+
+ </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/xml/wifi_network_details_fragment2.xml b/res/xml/wifi_network_details_fragment2.xml
index 56e7b04..daff20f 100644
--- a/res/xml/wifi_network_details_fragment2.xml
+++ b/res/xml/wifi_network_details_fragment2.xml
@@ -169,15 +169,11 @@
settings:enableCopying="true"/>
</PreferenceCategory>
- <!-- IPv6 Details -->
- <PreferenceCategory
- android:key="ipv6_category"
- android:title="@string/wifi_details_ipv6_address_header"
- android:selectable="false">
- <Preference
- android:key="ipv6_addresses"
- android:selectable="false"
- settings:enableCopying="true"/>
- </PreferenceCategory>
+ <!-- IPv6 address -->
+ <Preference
+ android:title="@string/wifi_details_ipv6_address_header"
+ android:key="ipv6_addresses"
+ android:selectable="false"
+ settings:enableCopying="true"/>
</PreferenceScreen>
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java
index d4803c6..0a6795f 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java
@@ -16,10 +16,12 @@
package com.android.settings.connecteddevice.audiosharing;
+import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeBroadcastAssistant;
import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.bluetooth.BluetoothLeBroadcastReceiveState;
+import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.pm.PackageManager;
import android.util.Log;
@@ -38,9 +40,14 @@
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.flags.Flags;
import com.android.settingslib.bluetooth.BluetoothCallback;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.LeAudioProfile;
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfile;
+import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@@ -53,11 +60,13 @@
"connected_device_audio_sharing_settings";
private final LocalBluetoothManager mLocalBtManager;
+ private final LocalBluetoothLeBroadcast mBroadcast;
private final LocalBluetoothLeBroadcastAssistant mAssistant;
private final Executor mExecutor;
private PreferenceGroup mPreferenceGroup;
private Preference mAudioSharingSettingsPreference;
private BluetoothDeviceUpdater mBluetoothDeviceUpdater;
+ private DashboardFragment mFragment;
private BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback =
new BluetoothLeBroadcastAssistant.Callback() {
@@ -149,6 +158,7 @@
public AudioSharingDevicePreferenceController(Context context) {
super(context, KEY);
mLocalBtManager = Utils.getLocalBtManager(mContext);
+ mBroadcast = mLocalBtManager.getProfileManager().getLeAudioBroadcastProfile();
mAssistant = mLocalBtManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
mExecutor = Executors.newSingleThreadExecutor();
}
@@ -156,15 +166,15 @@
@Override
public void onStart(@NonNull LifecycleOwner owner) {
if (mLocalBtManager == null) {
- Log.e(TAG, "onStart() Bluetooth is not supported on this device");
+ Log.d(TAG, "onStart() Bluetooth is not supported on this device");
return;
}
if (mAssistant == null) {
- Log.e(TAG, "onStart() Broadcast assistant is not supported on this device");
+ Log.d(TAG, "onStart() Broadcast assistant is not supported on this device");
return;
}
if (mBluetoothDeviceUpdater == null) {
- Log.e(TAG, "onStart() Bluetooth device updater is not initialized");
+ Log.d(TAG, "onStart() Bluetooth device updater is not initialized");
return;
}
mLocalBtManager.getEventManager().registerCallback(this);
@@ -176,15 +186,15 @@
@Override
public void onStop(@NonNull LifecycleOwner owner) {
if (mLocalBtManager == null) {
- Log.e(TAG, "onStop() Bluetooth is not supported on this device");
+ Log.d(TAG, "onStop() Bluetooth is not supported on this device");
return;
}
if (mAssistant == null) {
- Log.e(TAG, "onStop() Broadcast assistant is not supported on this device");
+ Log.d(TAG, "onStop() Broadcast assistant is not supported on this device");
return;
}
if (mBluetoothDeviceUpdater == null) {
- Log.e(TAG, "onStop() Bluetooth device updater is not initialized");
+ Log.d(TAG, "onStop() Bluetooth device updater is not initialized");
return;
}
mLocalBtManager.getEventManager().unregisterCallback(this);
@@ -244,17 +254,60 @@
}
}
+ @Override
+ public void onProfileConnectionStateChanged(
+ @NonNull CachedBluetoothDevice cachedDevice,
+ @ConnectionState int state,
+ int bluetoothProfile) {
+ if (state != BluetoothAdapter.STATE_CONNECTED || !cachedDevice.getDevice().isConnected()) {
+ Log.d(TAG, "Ignore onProfileConnectionStateChanged, not connected state");
+ return;
+ }
+ List<LocalBluetoothProfile> supportedProfiles = cachedDevice.getProfiles();
+ boolean isLeAudioSupported = false;
+ for (LocalBluetoothProfile profile : supportedProfiles) {
+ if (profile instanceof LeAudioProfile && profile.isEnabled(cachedDevice.getDevice())) {
+ isLeAudioSupported = true;
+ }
+ if (profile.getProfileId() != bluetoothProfile
+ && profile.getConnectionStatus(cachedDevice.getDevice())
+ == BluetoothProfile.STATE_CONNECTED) {
+ Log.d(
+ TAG,
+ "Ignore onProfileConnectionStateChanged, not the first connected profile");
+ return;
+ }
+ }
+ // Show stop audio sharing dialog when an ineligible (not le audio) remote device connected
+ // during a sharing session.
+ if (isBroadcasting() && !isLeAudioSupported) {
+ if (mFragment != null) {
+ AudioSharingStopDialogFragment.show(
+ mFragment,
+ cachedDevice.getName(),
+ () -> {
+ mBroadcast.stopBroadcast(mBroadcast.getLatestBroadcastId());
+ });
+ }
+ }
+ }
+
/**
* Initialize the controller.
*
* @param fragment The fragment to provide the context and metrics category for {@link
- * AudioSharingBluetoothDeviceUpdater}.
+ * AudioSharingBluetoothDeviceUpdater} and provide the host for dialogs.
*/
public void init(DashboardFragment fragment) {
+ mFragment = fragment;
mBluetoothDeviceUpdater =
new AudioSharingBluetoothDeviceUpdater(
fragment.getContext(),
AudioSharingDevicePreferenceController.this,
fragment.getMetricsCategory());
}
+
+ private boolean isBroadcasting() {
+ return mBroadcast != null && mBroadcast.isEnabled(null);
+ }
}
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreference.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreference.java
index 387ab7e..b36ea54 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreference.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreference.java
@@ -16,6 +16,7 @@
package com.android.settings.connecteddevice.audiosharing;
+import android.app.settings.SettingsEnums;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageButton;
@@ -23,6 +24,7 @@
import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
+import com.android.settings.core.SubSettingLauncher;
import com.android.settings.widget.ValidatedEditTextPreference;
public class AudioSharingNamePreference extends ValidatedEditTextPreference {
@@ -60,5 +62,12 @@
super.onBindViewHolder(holder);
final ImageButton shareButton = (ImageButton) holder.findViewById(R.id.button_icon);
shareButton.setImageDrawable(getContext().getDrawable(R.drawable.ic_qrcode_24dp));
+ shareButton.setOnClickListener(
+ unused ->
+ new SubSettingLauncher(getContext())
+ .setTitleText("Audio sharing QR code")
+ .setDestination(AudioStreamsQrCodeFragment.class.getName())
+ .setSourceMetricsCategory(SettingsEnums.AUDIO_SHARING_SETTINGS)
+ .launch());
}
}
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragment.java
new file mode 100644
index 0000000..495fad3
--- /dev/null
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragment.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2023 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.connecteddevice.audiosharing;
+
+import android.app.Dialog;
+import android.app.settings.SettingsEnums;
+import android.os.Bundle;
+
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+import com.android.settings.flags.Flags;
+
+public class AudioSharingStopDialogFragment extends InstrumentedDialogFragment {
+ private static final String TAG = "AudioSharingStopDialog";
+
+ private static final String BUNDLE_KEY_NEW_DEVICE_NAME = "bundle_key_new_device_name";
+
+ // The host creates an instance of this dialog fragment must implement this interface to receive
+ // event callbacks.
+ public interface DialogEventListener {
+ /** Called when users click the stop sharing button in the dialog. */
+ void onStopSharingClick();
+ }
+
+ private static DialogEventListener sListener;
+
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.DIALOG_STOP_AUDIO_SHARING;
+ }
+
+ /**
+ * Display the {@link AudioSharingStopDialogFragment} dialog.
+ *
+ * @param host The Fragment this dialog will be hosted.
+ */
+ public static void show(Fragment host, String newDeviceName, DialogEventListener listener) {
+ if (!Flags.enableLeAudioSharing()) return;
+ final FragmentManager manager = host.getChildFragmentManager();
+ sListener = listener;
+ if (manager.findFragmentByTag(TAG) == null) {
+ final Bundle bundle = new Bundle();
+ bundle.putString(BUNDLE_KEY_NEW_DEVICE_NAME, newDeviceName);
+ AudioSharingStopDialogFragment dialog = new AudioSharingStopDialogFragment();
+ dialog.setArguments(bundle);
+ dialog.show(manager, TAG);
+ }
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ Bundle arguments = requireArguments();
+ String newDeviceName = arguments.getString(BUNDLE_KEY_NEW_DEVICE_NAME);
+ final AlertDialog.Builder builder =
+ new AlertDialog.Builder(getActivity())
+ .setTitle("Stop sharing audio?")
+ .setCancelable(false);
+ builder.setMessage(
+ newDeviceName + " is connected, devices in audio sharing will disconnect.");
+ builder.setPositiveButton(
+ "Stop sharing",
+ (dialog, which) -> {
+ sListener.onStopSharingClick();
+ });
+ builder.setNegativeButton(
+ "Cancel",
+ (dialog, which) -> {
+ dismiss();
+ });
+ AlertDialog dialog = builder.create();
+ dialog.setCanceledOnTouchOutside(false);
+ return dialog;
+ }
+}
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioStreamsQrCodeFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioStreamsQrCodeFragment.java
new file mode 100644
index 0000000..edf2bd3
--- /dev/null
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioStreamsQrCodeFragment.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2023 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.connecteddevice.audiosharing;
+
+import android.bluetooth.BluetoothLeBroadcastMetadata;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+
+import com.android.settings.R;
+import com.android.settings.bluetooth.Utils;
+import com.android.settings.core.InstrumentedFragment;
+import com.android.settingslib.bluetooth.BluetoothLeBroadcastMetadataExt;
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
+import com.android.settingslib.qrcode.QrCodeGenerator;
+
+import com.google.zxing.WriterException;
+
+import java.util.Optional;
+
+public class AudioStreamsQrCodeFragment extends InstrumentedFragment {
+ private static final String TAG = "AudioStreamsQrCodeFragment";
+
+ @Override
+ public int getMetricsCategory() {
+ // TODO(chelseahao): update metrics id
+ return 0;
+ }
+
+ @Override
+ public final View onCreateView(
+ LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View view = inflater.inflate(R.xml.bluetooth_audio_streams_qr_code, container, false);
+ getQrCodeBitmap().ifPresent(
+ bm -> ((ImageView) view.requireViewById(R.id.qrcode_view)).setImageBitmap(bm));
+ return view;
+ }
+
+ private Optional<Bitmap> getQrCodeBitmap() {
+ String broadcastMetadata = getBroadcastMetadataQrCode();
+ if (broadcastMetadata.isEmpty()) {
+ Log.d(TAG, "onCreateView: broadcastMetadata is empty!");
+ return Optional.empty();
+ }
+
+ try {
+ int qrcodeSize = getContext().getResources().getDimensionPixelSize(R.dimen.qrcode_size);
+ Bitmap bitmap = QrCodeGenerator.encodeQrCode(broadcastMetadata, qrcodeSize);
+ return Optional.of(bitmap);
+ } catch (WriterException e) {
+ Log.d(TAG, "onCreateView: broadcastMetadata "
+ + broadcastMetadata
+ + " qrCode generation exception "
+ + e);
+ }
+
+ return Optional.empty();
+ }
+
+ private String getBroadcastMetadataQrCode() {
+ LocalBluetoothLeBroadcast localBluetoothLeBroadcast =
+ Utils.getLocalBtManager(getActivity())
+ .getProfileManager()
+ .getLeAudioBroadcastProfile();
+ if (localBluetoothLeBroadcast == null) {
+ Log.d(TAG, "getBroadcastMetadataQrCode: localBluetoothLeBroadcast is null!");
+ return "";
+ }
+
+ BluetoothLeBroadcastMetadata metadata =
+ localBluetoothLeBroadcast.getLatestBluetoothLeBroadcastMetadata();
+ if (metadata == null) {
+ Log.d(TAG, "getBroadcastMetadataQrCode: metadata is null!");
+ return "";
+ }
+
+ return BluetoothLeBroadcastMetadataExt.INSTANCE.toQrCodeString(metadata);
+ }
+}
diff --git a/src/com/android/settings/slices/VolumeSliceHelper.java b/src/com/android/settings/slices/VolumeSliceHelper.java
index 1ba1778..8947cc4 100644
--- a/src/com/android/settings/slices/VolumeSliceHelper.java
+++ b/src/com/android/settings/slices/VolumeSliceHelper.java
@@ -24,7 +24,6 @@
import android.content.IntentFilter;
import android.media.AudioManager;
import android.net.Uri;
-import android.util.ArrayMap;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
@@ -32,6 +31,7 @@
import com.android.settingslib.SliceBroadcastRelay;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
/**
* This helper is to handle the broadcasts of volume slices
@@ -41,7 +41,7 @@
private static final String TAG = "VolumeSliceHelper";
@VisibleForTesting
- static Map<Uri, Integer> sRegisteredUri = new ArrayMap<>();
+ static Map<Uri, Integer> sRegisteredUri = new ConcurrentHashMap<>();
@VisibleForTesting
static IntentFilter sIntentFilter;
@@ -133,23 +133,19 @@
}
private static void handleStreamChanged(Context context, int inputType) {
- synchronized (sRegisteredUri) {
- for (Map.Entry<Uri, Integer> entry : sRegisteredUri.entrySet()) {
- if (entry.getValue() == inputType) {
- context.getContentResolver().notifyChange(entry.getKey(), null /* observer */);
- if (inputType != AudioManager.STREAM_RING) { // Two URIs are mapped to ring
- break;
- }
+ for (Map.Entry<Uri, Integer> entry : sRegisteredUri.entrySet()) {
+ if (entry.getValue() == inputType) {
+ context.getContentResolver().notifyChange(entry.getKey(), null /* observer */);
+ if (inputType != AudioManager.STREAM_RING) { // Two URIs are mapped to ring
+ break;
}
}
}
}
private static void notifyAllStreamsChanged(Context context) {
- synchronized (sRegisteredUri) {
- sRegisteredUri.forEach((uri, audioStream) -> {
- context.getContentResolver().notifyChange(uri, null /* observer */);
- });
- }
+ sRegisteredUri.keySet().forEach(uri -> {
+ context.getContentResolver().notifyChange(uri, null /* observer */);
+ });
}
}
diff --git a/src/com/android/settings/spa/SettingsSpaEnvironment.kt b/src/com/android/settings/spa/SettingsSpaEnvironment.kt
index 6b96460..7ab836b 100644
--- a/src/com/android/settings/spa/SettingsSpaEnvironment.kt
+++ b/src/com/android/settings/spa/SettingsSpaEnvironment.kt
@@ -82,35 +82,41 @@
allProviders = getTogglePermissionAppListProviders()
)
SettingsPageProviderRepository(
- allPageProviders = listOf(
- HomePageProvider,
- AppsMainPageProvider,
- AllAppListPageProvider,
- AppInfoSettingsProvider,
- SpecialAppAccessPageProvider,
- NotificationMainPageProvider,
- AppListNotificationsPageProvider,
- SystemMainPageProvider,
- LanguageAndInputPageProvider,
- AppLanguagesPageProvider,
- UsageStatsPageProvider,
- PlatformCompatAppListPageProvider,
- BackgroundInstalledAppsPageProvider,
- UserAspectRatioAppsPageProvider,
- CloneAppInfoSettingsProvider,
- NetworkAndInternetPageProvider,
- AboutPhonePageProvider,
- StorageAppListPageProvider.Apps,
- StorageAppListPageProvider.Games,
- ApnEditPageProvider,
- ) + togglePermissionAppListTemplate.createPageProviders(),
+ allPageProviders = settingsPageProviders()
+ + togglePermissionAppListTemplate.createPageProviders(),
rootPages = listOf(
HomePageProvider.createSettingsPage()
),
)
}
- override val logger =
- if (FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_ENABLE_SPA_METRICS))
- SpaLogProvider
- else object : SpaLogger {}
+
+
+ open fun settingsPageProviders() = listOf(
+ HomePageProvider,
+ AppsMainPageProvider,
+ AllAppListPageProvider,
+ AppInfoSettingsProvider,
+ SpecialAppAccessPageProvider,
+ NotificationMainPageProvider,
+ AppListNotificationsPageProvider,
+ SystemMainPageProvider,
+ LanguageAndInputPageProvider,
+ AppLanguagesPageProvider,
+ UsageStatsPageProvider,
+ PlatformCompatAppListPageProvider,
+ BackgroundInstalledAppsPageProvider,
+ UserAspectRatioAppsPageProvider,
+ CloneAppInfoSettingsProvider,
+ NetworkAndInternetPageProvider,
+ AboutPhonePageProvider,
+ StorageAppListPageProvider.Apps,
+ StorageAppListPageProvider.Games,
+ ApnEditPageProvider,
+ )
+
+ override val logger = if (FeatureFlagUtils.isEnabled(
+ context, FeatureFlagUtils.SETTINGS_ENABLE_SPA_METRICS
+ )
+ ) SpaLogProvider
+ else object : SpaLogger {}
}
diff --git a/src/com/android/settings/vpn2/ConfigDialogFragment.java b/src/com/android/settings/vpn2/ConfigDialogFragment.java
index b8825fe..e38f92a 100644
--- a/src/com/android/settings/vpn2/ConfigDialogFragment.java
+++ b/src/com/android/settings/vpn2/ConfigDialogFragment.java
@@ -207,6 +207,10 @@
mService.startLegacyVpn(profile);
} catch (IllegalStateException e) {
Toast.makeText(mContext, R.string.vpn_no_network, Toast.LENGTH_LONG).show();
+ } catch (UnsupportedOperationException e) {
+ Log.e(TAG, "Attempted to start an unsupported VPN type.");
+ Toast.makeText(mContext, R.string.vpn_insecure_dialog_subtitle, Toast.LENGTH_LONG)
+ .show();
}
}
}
diff --git a/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java b/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java
index 5ab8807..faa0c3b 100644
--- a/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java
+++ b/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java
@@ -59,7 +59,6 @@
import androidx.annotation.VisibleForTesting;
import androidx.core.text.BidiFormatter;
import androidx.preference.Preference;
-import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceScreen;
import androidx.recyclerview.widget.RecyclerView;
@@ -184,7 +183,6 @@
private Preference mSubnetPref;
private Preference mDnsPref;
private Preference mTypePref;
- private PreferenceCategory mIpv6Category;
private Preference mIpv6AddressPref;
private final IconInjector mIconInjector;
private final Clock mClock;
@@ -376,8 +374,6 @@
mSubnetPref = screen.findPreference(KEY_SUBNET_MASK_PREF);
mDnsPref = screen.findPreference(KEY_DNS_PREF);
mTypePref = screen.findPreference(KEY_WIFI_TYPE_PREF);
-
- mIpv6Category = screen.findPreference(KEY_IPV6_CATEGORY);
mIpv6AddressPref = screen.findPreference(KEY_IPV6_ADDRESSES_PREF);
}
@@ -824,7 +820,7 @@
mSubnetPref.setVisible(false);
mGatewayPref.setVisible(false);
mDnsPref.setVisible(false);
- mIpv6Category.setVisible(false);
+ mIpv6AddressPref.setVisible(false);
return;
}
@@ -864,11 +860,11 @@
updatePreference(mDnsPref, dnsServers);
if (ipv6Addresses.length() > 0) {
+ mIpv6AddressPref.setVisible(true);
mIpv6AddressPref.setSummary(
BidiFormatter.getInstance().unicodeWrap(ipv6Addresses.toString()));
- mIpv6Category.setVisible(true);
} else {
- mIpv6Category.setVisible(false);
+ mIpv6AddressPref.setVisible(false);
}
}
diff --git a/tests/robotests/src/com/android/settings/display/ControlsTrivialPrivacyPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/ControlsTrivialPrivacyPreferenceControllerTest.java
index a82e1f1..03bf763 100644
--- a/tests/robotests/src/com/android/settings/display/ControlsTrivialPrivacyPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/ControlsTrivialPrivacyPreferenceControllerTest.java
@@ -20,6 +20,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.spy;
@@ -220,7 +221,7 @@
final ResolveInfo resolveInfo = new ResolveInfo();
resolveInfo.activityInfo = activityInfo;
- when(mPackageManager.resolveActivity(any(), any())).thenReturn(resolveInfo);
+ when(mPackageManager.resolveActivity(any(), anyInt())).thenReturn(resolveInfo);
}
}
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/IncompatibleChargerDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/IncompatibleChargerDetectorTest.java
index 3f65a67..c0f6108 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/IncompatibleChargerDetectorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/IncompatibleChargerDetectorTest.java
@@ -81,6 +81,7 @@
when(mUsbPort.getStatus()).thenReturn(mUsbPortStatus);
when(mUsbPort.supportsComplianceWarnings()).thenReturn(true);
when(mUsbPortStatus.isConnected()).thenReturn(true);
- when(mUsbPortStatus.getComplianceWarnings()).thenReturn(new int[] {1});
+ when(mUsbPortStatus.getComplianceWarnings())
+ .thenReturn(new int[] {UsbPortStatus.COMPLIANCE_WARNING_DEBUG_ACCESSORY});
}
}