From e7477028796ec3bd493088a846b9b02143fdc896 Mon Sep 17 00:00:00 2001 From: SongFerngWang Date: Tue, 6 Sep 2022 12:08:57 +0800 Subject: [PATCH] [LE boradcast] save the data into ContentProvider The settings and systemUI use the LocalBluetoothLeBroadcast and they use different sharedPreferences since the context is different. It causes the data are not consistent. Solution: Add data into ContentProvider, and listen the data changed by the ContentObserver. Bug: 243107842 Test: build pass. manual test in local. atest SettingsBackupTest atest SettingsValidatorsTest Change-Id: I5f8367f3eb8e2dafa2986004dd8540de41409192 Merged-In: I5f8367f3eb8e2dafa2986004dd8540de41409192 --- core/java/android/provider/Settings.java | 20 ++ .../bluetooth/LocalBluetoothLeBroadcast.java | 221 +++++++++++++----- .../settings/backup/SecureSettings.java | 5 +- .../validators/SecureSettingsValidators.java | 3 + 4 files changed, 185 insertions(+), 64 deletions(-) diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 1fcdd608c5a21..b964e1c326a47 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -6659,6 +6659,26 @@ public final class Settings { @SuppressLint("NoSettingsProvider") public static final String BLUETOOTH_ADDR_VALID = "bluetooth_addr_valid"; + /** + * This is used by LocalBluetoothLeBroadcast to store the broadcast program info. + * @hide + */ + public static final String BLUETOOTH_LE_BROADCAST_PROGRAM_INFO = + "bluetooth_le_broadcast_program_info"; + + /** + * This is used by LocalBluetoothLeBroadcast to store the broadcast code. + * @hide + */ + public static final String BLUETOOTH_LE_BROADCAST_CODE = "bluetooth_le_broadcast_code"; + + /** + * This is used by LocalBluetoothLeBroadcast to store the app source name. + * @hide + */ + public static final String BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME = + "bluetooth_le_broadcast_app_source_name"; + /** * Setting to indicate that on device captions are enabled. * diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java index 01d581ed28dbc..123c01b6e12f7 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java @@ -26,11 +26,17 @@ import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothLeAudioContentMetadata; import android.bluetooth.BluetoothLeBroadcast; import android.bluetooth.BluetoothLeBroadcastMetadata; +import android.bluetooth.BluetoothLeBroadcastSubgroup; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothProfile.ServiceListener; +import android.content.ContentResolver; import android.content.Context; -import android.content.SharedPreferences; +import android.database.ContentObserver; +import android.net.Uri; import android.os.Build; +import android.os.Handler; +import android.os.Looper; +import android.provider.Settings; import android.text.TextUtils; import android.util.Log; @@ -40,6 +46,7 @@ import com.android.settingslib.R; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.UUID; @@ -54,19 +61,20 @@ import java.util.concurrent.ThreadLocalRandom; */ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { private static final String TAG = "LocalBluetoothLeBroadcast"; - private static final int UNKNOWN_VALUE_PLACEHOLDER = -1; private static final boolean DEBUG = BluetoothUtils.D; static final String NAME = "LE_AUDIO_BROADCAST"; + private static final String UNDERLINE = "_"; + private static final int DEFAULT_CODE_MAX = 9999; + private static final int DEFAULT_CODE_MIN = 1000; // Order of this profile in device profiles list private static final int ORDINAL = 1; - private static final String PREF_NAME = "LocalBluetoothLeBroadcast"; - private static final String PREF_PROGRAM_INFO = "PrefProgramInfo"; - private static final String PREF_BROADCAST_CODE = "PrefBroadcastCode"; - private static final String PREF_APP_SOURCE_NAME = "PrefAppSourceName"; - private static final String UNDERLINE = "_"; - private static final int DEFAULT_CODE_MIN = 1000; - private static final int DEFAULT_CODE_MAX = 9999; + private static final int UNKNOWN_VALUE_PLACEHOLDER = -1; + private static final Uri[] SETTINGS_URIS = new Uri[]{ + Settings.Secure.getUriFor(Settings.Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO), + Settings.Secure.getUriFor(Settings.Secure.BLUETOOTH_LE_BROADCAST_CODE), + Settings.Secure.getUriFor(Settings.Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME), + }; private BluetoothLeBroadcast mService; private BluetoothLeAudioContentMetadata mBluetoothLeAudioContentMetadata; @@ -78,8 +86,9 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { private boolean mIsProfileReady; private String mProgramInfo; private byte[] mBroadcastCode; - private SharedPreferences mSharedPref; private Executor mExecutor; + private ContentResolver mContentResolver; + private ContentObserver mSettingsObserver; private final ServiceListener mServiceListener = new ServiceListener() { @Override @@ -91,6 +100,11 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { mService = (BluetoothLeBroadcast) proxy; mIsProfileReady = true; registerServiceCallBack(mExecutor, mBroadcastCallback); + List metadata = getAllBroadcastMetadata(); + if (!metadata.isEmpty()) { + updateBroadcastInfoFromBroadcastMetadata(metadata.get(0)); + } + registerContentObserver(); } } @@ -102,6 +116,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { if(mIsProfileReady) { mIsProfileReady = false; unregisterServiceCallBack(mBroadcastCallback); + unregisterContentObserver(); } } }; @@ -116,7 +131,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { + broadcastId); } setLatestBroadcastId(broadcastId); - setAppSourceName(mNewAppSourceName); + setAppSourceName(mNewAppSourceName, /*updateContentResolver=*/ true); } @Override @@ -160,7 +175,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { + broadcastId); } setLatestBroadcastId(broadcastId); - setAppSourceName(mNewAppSourceName); + setAppSourceName(mNewAppSourceName, /*updateContentResolver=*/ true); } @Override @@ -181,30 +196,27 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { } }; + private class BroadcastSettingsObserver extends ContentObserver { + BroadcastSettingsObserver(Handler h) { + super(h); + } + + @Override + public void onChange(boolean selfChange) { + Log.d(TAG, "BroadcastSettingsObserver: onChange"); + updateBroadcastInfoFromContentProvider(); + } + } + LocalBluetoothLeBroadcast(Context context) { mExecutor = Executors.newSingleThreadExecutor(); BluetoothAdapter.getDefaultAdapter(). getProfileProxy(context, mServiceListener, BluetoothProfile.LE_AUDIO_BROADCAST); mBuilder = new BluetoothLeAudioContentMetadata.Builder(); - mSharedPref = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); - if (mSharedPref != null) { - String programInfo = mSharedPref.getString(PREF_PROGRAM_INFO, ""); - if (programInfo.isEmpty()) { - programInfo = getDefaultValueOfProgramInfo(); - } - setProgramInfo(programInfo); - - String prefBroadcastCode = mSharedPref.getString(PREF_BROADCAST_CODE, ""); - byte[] broadcastCode; - if (prefBroadcastCode.isEmpty()) { - broadcastCode = getDefaultValueOfBroadcastCode(); - } else { - broadcastCode = prefBroadcastCode.getBytes(StandardCharsets.UTF_8); - } - setBroadcastCode(broadcastCode); - - mAppSourceName = mSharedPref.getString(PREF_APP_SOURCE_NAME, ""); - } + mContentResolver = context.getContentResolver(); + Handler handler = new Handler(Looper.getMainLooper()); + mSettingsObserver = new BroadcastSettingsObserver(handler); + updateBroadcastInfoFromContentProvider(); } /** @@ -217,11 +229,12 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { Log.d(TAG, "The BluetoothLeBroadcast is null when starting the broadcast."); return; } + String programInfo = getProgramInfo(); if (DEBUG) { Log.d(TAG, - "startBroadcast: language = " + language + " ,programInfo = " + mProgramInfo); + "startBroadcast: language = " + language + " ,programInfo = " + programInfo); } - buildContentMetadata(language, mProgramInfo); + buildContentMetadata(language, programInfo); mService.startBroadcast(mBluetoothLeAudioContentMetadata, mBroadcastCode); } @@ -230,21 +243,28 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { } public void setProgramInfo(String programInfo) { - if (programInfo == null || programInfo.isEmpty()) { + setProgramInfo(programInfo, /*updateContentResolver=*/ true); + } + + private void setProgramInfo(String programInfo, boolean updateContentResolver) { + if (TextUtils.isEmpty(programInfo)) { Log.d(TAG, "setProgramInfo: programInfo is null or empty"); return; } + if (mProgramInfo != null && TextUtils.equals(mProgramInfo, programInfo)) { + Log.d(TAG, "setProgramInfo: programInfo is not changed"); + return; + } Log.d(TAG, "setProgramInfo: " + programInfo); mProgramInfo = programInfo; - - if (mSharedPref == null) { - Log.d(TAG, "setProgramInfo: sharedPref is null"); - return; + if (updateContentResolver) { + if (mContentResolver == null) { + Log.d(TAG, "mContentResolver is null"); + return; + } + Settings.Secure.putString(mContentResolver, + Settings.Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO, programInfo); } - SharedPreferences.Editor editor = mSharedPref.edit(); - editor.putString(PREF_PROGRAM_INFO, mProgramInfo); - editor.apply(); - } public byte[] getBroadcastCode() { @@ -252,22 +272,31 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { } public void setBroadcastCode(byte[] broadcastCode) { - if (broadcastCode == null || broadcastCode.length == 0) { - Log.d(TAG, "setBroadcastCode: broadcastCode is null or empty"); + setBroadcastCode(broadcastCode, /*updateContentResolver=*/ true); + } + + private void setBroadcastCode(byte[] broadcastCode, boolean updateContentResolver) { + if (broadcastCode == null) { + Log.d(TAG, "setBroadcastCode: broadcastCode is null"); + return; + } + if (mBroadcastCode != null && Arrays.equals(broadcastCode, mBroadcastCode)) { + Log.d(TAG, "setBroadcastCode: broadcastCode is not changed"); return; } mBroadcastCode = broadcastCode; - - if (mSharedPref == null) { - Log.d(TAG, "setBroadcastCode: sharedPref is null"); - return; + if (updateContentResolver) { + if (mContentResolver == null) { + Log.d(TAG, "mContentResolver is null"); + return; + } + Settings.Secure.putString(mContentResolver, Settings.Secure.BLUETOOTH_LE_BROADCAST_CODE, + new String(broadcastCode, StandardCharsets.UTF_8)); } - SharedPreferences.Editor editor = mSharedPref.edit(); - editor.putString(PREF_BROADCAST_CODE, new String(broadcastCode, StandardCharsets.UTF_8)); - editor.apply(); } private void setLatestBroadcastId(int broadcastId) { + Log.d(TAG, "setLatestBroadcastId: mBroadcastId is " + broadcastId); mBroadcastId = broadcastId; } @@ -275,19 +304,24 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { return mBroadcastId; } - private void setAppSourceName(String appSourceName) { + private void setAppSourceName(String appSourceName, boolean updateContentResolver) { if (TextUtils.isEmpty(appSourceName)) { appSourceName = ""; } - mAppSourceName = appSourceName; - mNewAppSourceName = ""; - if (mSharedPref == null) { - Log.d(TAG, "setBroadcastCode: sharedPref is null"); + if (mAppSourceName != null && TextUtils.equals(mAppSourceName, appSourceName)) { + Log.d(TAG, "setAppSourceName: appSourceName is not changed"); return; } - SharedPreferences.Editor editor = mSharedPref.edit(); - editor.putString(PREF_APP_SOURCE_NAME, appSourceName); - editor.apply(); + mAppSourceName = appSourceName; + mNewAppSourceName = ""; + if (updateContentResolver) { + if (mContentResolver == null) { + Log.d(TAG, "mContentResolver is null"); + return; + } + Settings.Secure.putString(mContentResolver, + Settings.Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME, mAppSourceName); + } } public String getAppSourceName() { @@ -299,6 +333,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { if (bluetoothLeBroadcastMetadata != null && bluetoothLeBroadcastMetadata.getBroadcastId() == mBroadcastId) { mBluetoothLeBroadcastMetadata = bluetoothLeBroadcastMetadata; + updateBroadcastInfoFromBroadcastMetadata(bluetoothLeBroadcastMetadata); } } @@ -318,6 +353,48 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { return mBluetoothLeBroadcastMetadata; } + private void updateBroadcastInfoFromContentProvider() { + if (mContentResolver == null) { + Log.d(TAG, "updateBroadcastInfoFromContentProvider: mContentResolver is null"); + return; + } + String programInfo = Settings.Secure.getString(mContentResolver, + Settings.Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO); + if (programInfo == null) { + programInfo = getDefaultValueOfProgramInfo(); + } + setProgramInfo(programInfo, /*updateContentResolver=*/ false); + + String prefBroadcastCode = Settings.Secure.getString(mContentResolver, + Settings.Secure.BLUETOOTH_LE_BROADCAST_CODE); + byte[] broadcastCode = (prefBroadcastCode == null) ? getDefaultValueOfBroadcastCode() + : prefBroadcastCode.getBytes(StandardCharsets.UTF_8); + setBroadcastCode(broadcastCode, /*updateContentResolver=*/ false); + + String appSourceName = Settings.Secure.getString(mContentResolver, + Settings.Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME); + setAppSourceName(appSourceName, /*updateContentResolver=*/ false); + } + + private void updateBroadcastInfoFromBroadcastMetadata( + BluetoothLeBroadcastMetadata bluetoothLeBroadcastMetadata) { + if (bluetoothLeBroadcastMetadata == null) { + Log.d(TAG, "The bluetoothLeBroadcastMetadata is null"); + return; + } + setBroadcastCode(bluetoothLeBroadcastMetadata.getBroadcastCode()); + setLatestBroadcastId(bluetoothLeBroadcastMetadata.getBroadcastId()); + + List subgroup = bluetoothLeBroadcastMetadata.getSubgroups(); + if (subgroup == null || subgroup.size() < 1) { + Log.d(TAG, "The subgroup is not valid value"); + return; + } + BluetoothLeAudioContentMetadata contentMetadata = subgroup.get(0).getContentMetadata(); + setProgramInfo(contentMetadata.getProgramInfo()); + setAppSourceName(getAppSourceName(), /*updateContentResolver=*/ true); + } + /** * Stop the latest LE Broadcast. If the system stopped the LE Broadcast, then the system * calls the corresponding callback {@link BluetoothLeBroadcast.Callback}. @@ -350,12 +427,13 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { Log.d(TAG, "The BluetoothLeBroadcast is null when updating the broadcast."); return; } + String programInfo = getProgramInfo(); if (DEBUG) { Log.d(TAG, - "updateBroadcast: language = " + language + " ,programInfo = " + mProgramInfo); + "updateBroadcast: language = " + language + " ,programInfo = " + programInfo); } mNewAppSourceName = appSourceName; - mBluetoothLeAudioContentMetadata = mBuilder.setProgramInfo(mProgramInfo).build(); + mBluetoothLeAudioContentMetadata = mBuilder.setProgramInfo(programInfo).build(); mService.updateBroadcast(mBroadcastId, mBluetoothLeAudioContentMetadata); } @@ -517,8 +595,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { if (DEBUG) { Log.d(TAG, "resetCacheInfo:"); } - mNewAppSourceName = ""; - mAppSourceName = ""; + setAppSourceName("", /*updateContentResolver=*/ true); mBluetoothLeBroadcastMetadata = null; mBroadcastId = UNKNOWN_VALUE_PLACEHOLDER; } @@ -528,4 +605,22 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { //first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx return randomUUID.substring(0, 8) + randomUUID.substring(9, 13); } + + private void registerContentObserver() { + if (mContentResolver == null) { + Log.d(TAG, "mContentResolver is null"); + return; + } + for (Uri uri : SETTINGS_URIS) { + mContentResolver.registerContentObserver(uri, false, mSettingsObserver); + } + } + + private void unregisterContentObserver() { + if (mContentResolver == null) { + Log.d(TAG, "mContentResolver is null"); + return; + } + mContentResolver.unregisterContentObserver(mSettingsObserver); + } } diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java index 36fbf8f850d33..453a71327b50d 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java @@ -212,6 +212,9 @@ public class SecureSettings { Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED, - Settings.Secure.ASSIST_LONG_PRESS_HOME_ENABLED + Settings.Secure.ASSIST_LONG_PRESS_HOME_ENABLED, + Settings.Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO, + Settings.Secure.BLUETOOTH_LE_BROADCAST_CODE, + Settings.Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME }; } diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java index 6a70230701f62..a39735ffe2c70 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java @@ -344,5 +344,8 @@ public class SecureSettingsValidators { return true; }); VALIDATORS.put(Secure.ODI_CAPTIONS_VOLUME_UI_ENABLED, BOOLEAN_VALIDATOR); + VALIDATORS.put(Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO, ANY_STRING_VALIDATOR); + VALIDATORS.put(Secure.BLUETOOTH_LE_BROADCAST_CODE, ANY_STRING_VALIDATOR); + VALIDATORS.put(Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME, ANY_STRING_VALIDATOR); } }