[Audiosharing] Implement name and password row.
Bug: 308368124 Test: manual Change-Id: I86d0e771ece0ea7003a50ee0cc9305814d85fecb
This commit is contained in:
@@ -45,9 +45,15 @@
|
|||||||
|
|
||||||
<com.android.settings.connecteddevice.audiosharing.AudioSharingNamePreference
|
<com.android.settings.connecteddevice.audiosharing.AudioSharingNamePreference
|
||||||
android:key="audio_sharing_stream_name"
|
android:key="audio_sharing_stream_name"
|
||||||
android:summary="********"
|
android:title="Name"
|
||||||
android:title="Stream name"
|
|
||||||
settings:controller="com.android.settings.connecteddevice.audiosharing.AudioSharingNamePreferenceController" />
|
settings:controller="com.android.settings.connecteddevice.audiosharing.AudioSharingNamePreferenceController" />
|
||||||
|
|
||||||
|
<com.android.settings.widget.ValidatedEditTextPreference
|
||||||
|
android:key="audio_sharing_stream_password"
|
||||||
|
android:summary="********"
|
||||||
|
android:title="Password"
|
||||||
|
settings:controller="com.android.settings.connecteddevice.audiosharing.AudioSharingPasswordPreferenceController" />
|
||||||
|
|
||||||
<SwitchPreferenceCompat
|
<SwitchPreferenceCompat
|
||||||
android:key="audio_sharing_stream_compatibility"
|
android:key="audio_sharing_stream_compatibility"
|
||||||
android:title="Improve compatibility"
|
android:title="Improve compatibility"
|
||||||
|
@@ -19,6 +19,8 @@ package com.android.settings.connecteddevice.audiosharing;
|
|||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
|
|
||||||
import androidx.preference.PreferenceViewHolder;
|
import androidx.preference.PreferenceViewHolder;
|
||||||
@@ -30,6 +32,7 @@ import com.android.settings.widget.ValidatedEditTextPreference;
|
|||||||
|
|
||||||
public class AudioSharingNamePreference extends ValidatedEditTextPreference {
|
public class AudioSharingNamePreference extends ValidatedEditTextPreference {
|
||||||
private static final String TAG = "AudioSharingNamePreference";
|
private static final String TAG = "AudioSharingNamePreference";
|
||||||
|
private boolean mShowQrCodeIcon = false;
|
||||||
|
|
||||||
public AudioSharingNamePreference(
|
public AudioSharingNamePreference(
|
||||||
Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||||
@@ -58,17 +61,50 @@ public class AudioSharingNamePreference extends ValidatedEditTextPreference {
|
|||||||
setWidgetLayoutResource(R.layout.preference_widget_qrcode);
|
setWidgetLayoutResource(R.layout.preference_widget_qrcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setShowQrCodeIcon(boolean show) {
|
||||||
|
mShowQrCodeIcon = show;
|
||||||
|
notifyChanged();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(PreferenceViewHolder holder) {
|
public void onBindViewHolder(PreferenceViewHolder holder) {
|
||||||
super.onBindViewHolder(holder);
|
super.onBindViewHolder(holder);
|
||||||
final ImageButton shareButton = (ImageButton) holder.findViewById(R.id.button_icon);
|
|
||||||
|
ImageButton shareButton = (ImageButton) holder.findViewById(R.id.button_icon);
|
||||||
|
View divider =
|
||||||
|
holder.findViewById(
|
||||||
|
com.android.settingslib.widget.preference.twotarget.R.id
|
||||||
|
.two_target_divider);
|
||||||
|
|
||||||
|
if (shareButton != null && divider != null) {
|
||||||
|
if (mShowQrCodeIcon) {
|
||||||
|
configureVisibleStateForQrCodeIcon(shareButton, divider);
|
||||||
|
} else {
|
||||||
|
configureInvisibleStateForQrCodeIcon(shareButton, divider);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "onBindViewHolder() : shareButton or divider is null!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void configureVisibleStateForQrCodeIcon(ImageButton shareButton, View divider) {
|
||||||
|
divider.setVisibility(View.VISIBLE);
|
||||||
|
shareButton.setVisibility(View.VISIBLE);
|
||||||
shareButton.setImageDrawable(getContext().getDrawable(R.drawable.ic_qrcode_24dp));
|
shareButton.setImageDrawable(getContext().getDrawable(R.drawable.ic_qrcode_24dp));
|
||||||
shareButton.setOnClickListener(
|
shareButton.setOnClickListener(unused -> launchAudioSharingQrCodeFragment());
|
||||||
unused ->
|
}
|
||||||
|
|
||||||
|
private void configureInvisibleStateForQrCodeIcon(ImageButton shareButton, View divider) {
|
||||||
|
divider.setVisibility(View.INVISIBLE);
|
||||||
|
shareButton.setVisibility(View.INVISIBLE);
|
||||||
|
shareButton.setOnClickListener(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void launchAudioSharingQrCodeFragment() {
|
||||||
new SubSettingLauncher(getContext())
|
new SubSettingLauncher(getContext())
|
||||||
.setTitleText("Audio sharing QR code")
|
.setTitleText("Audio sharing QR code")
|
||||||
.setDestination(AudioStreamsQrCodeFragment.class.getName())
|
.setDestination(AudioStreamsQrCodeFragment.class.getName())
|
||||||
.setSourceMetricsCategory(SettingsEnums.AUDIO_SHARING_SETTINGS)
|
.setSourceMetricsCategory(SettingsEnums.AUDIO_SHARING_SETTINGS)
|
||||||
.launch());
|
.launch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -16,25 +16,128 @@
|
|||||||
|
|
||||||
package com.android.settings.connecteddevice.audiosharing;
|
package com.android.settings.connecteddevice.audiosharing;
|
||||||
|
|
||||||
|
import static com.android.settings.connecteddevice.audiosharing.AudioSharingUtils.isBroadcasting;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothLeBroadcast;
|
||||||
|
import android.bluetooth.BluetoothLeBroadcastMetadata;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.lifecycle.DefaultLifecycleObserver;
|
||||||
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
|
import com.android.settings.bluetooth.Utils;
|
||||||
import com.android.settings.core.BasePreferenceController;
|
import com.android.settings.core.BasePreferenceController;
|
||||||
import com.android.settings.widget.ValidatedEditTextPreference;
|
import com.android.settings.widget.ValidatedEditTextPreference;
|
||||||
|
import com.android.settingslib.bluetooth.BluetoothUtils;
|
||||||
|
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
|
||||||
|
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||||
|
import com.android.settingslib.utils.ThreadUtils;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
public class AudioSharingNamePreferenceController extends BasePreferenceController
|
public class AudioSharingNamePreferenceController extends BasePreferenceController
|
||||||
implements ValidatedEditTextPreference.Validator, Preference.OnPreferenceChangeListener {
|
implements ValidatedEditTextPreference.Validator,
|
||||||
|
Preference.OnPreferenceChangeListener,
|
||||||
|
DefaultLifecycleObserver {
|
||||||
|
|
||||||
private static final String TAG = "AudioSharingNamePreferenceController";
|
private static final String TAG = "AudioSharingNamePreferenceController";
|
||||||
|
private static final boolean DEBUG = BluetoothUtils.D;
|
||||||
private static final String PREF_KEY = "audio_sharing_stream_name";
|
private static final String PREF_KEY = "audio_sharing_stream_name";
|
||||||
|
|
||||||
private AudioSharingNameTextValidator mAudioSharingNameTextValidator;
|
private final BluetoothLeBroadcast.Callback mBroadcastCallback =
|
||||||
|
new BluetoothLeBroadcast.Callback() {
|
||||||
|
@Override
|
||||||
|
public void onBroadcastMetadataChanged(
|
||||||
|
int broadcastId, BluetoothLeBroadcastMetadata metadata) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(
|
||||||
|
TAG,
|
||||||
|
"onBroadcastMetadataChanged() broadcastId : "
|
||||||
|
+ broadcastId
|
||||||
|
+ " metadata: "
|
||||||
|
+ metadata);
|
||||||
|
}
|
||||||
|
updateQrCodeIcon(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBroadcastStartFailed(int reason) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBroadcastStarted(int reason, int broadcastId) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBroadcastStopFailed(int reason) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBroadcastStopped(int reason, int broadcastId) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(
|
||||||
|
TAG,
|
||||||
|
"onBroadcastStopped() reason : "
|
||||||
|
+ reason
|
||||||
|
+ " broadcastId: "
|
||||||
|
+ broadcastId);
|
||||||
|
}
|
||||||
|
updateQrCodeIcon(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBroadcastUpdateFailed(int reason, int broadcastId) {
|
||||||
|
Log.w(TAG, "onBroadcastUpdateFailed() reason : " + reason);
|
||||||
|
// Do nothing if update failed.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBroadcastUpdated(int reason, int broadcastId) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "onBroadcastUpdated() reason : " + reason);
|
||||||
|
}
|
||||||
|
updateBroadcastName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPlaybackStarted(int reason, int broadcastId) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPlaybackStopped(int reason, int broadcastId) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Nullable private final LocalBluetoothManager mLocalBtManager;
|
||||||
|
@Nullable private final LocalBluetoothLeBroadcast mBroadcast;
|
||||||
|
private final Executor mExecutor;
|
||||||
|
private final AudioSharingNameTextValidator mAudioSharingNameTextValidator;
|
||||||
|
@Nullable private AudioSharingNamePreference mPreference;
|
||||||
|
|
||||||
public AudioSharingNamePreferenceController(Context context, String preferenceKey) {
|
public AudioSharingNamePreferenceController(Context context, String preferenceKey) {
|
||||||
super(context, preferenceKey);
|
super(context, preferenceKey);
|
||||||
|
mLocalBtManager = Utils.getLocalBluetoothManager(context);
|
||||||
|
mBroadcast =
|
||||||
|
(mLocalBtManager != null)
|
||||||
|
? mLocalBtManager.getProfileManager().getLeAudioBroadcastProfile()
|
||||||
|
: null;
|
||||||
mAudioSharingNameTextValidator = new AudioSharingNameTextValidator();
|
mAudioSharingNameTextValidator = new AudioSharingNameTextValidator();
|
||||||
|
mExecutor = Executors.newSingleThreadExecutor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart(@NonNull LifecycleOwner owner) {
|
||||||
|
if (mBroadcast != null) {
|
||||||
|
mBroadcast.registerServiceCallBack(mExecutor, mBroadcastCallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStop(@NonNull LifecycleOwner owner) {
|
||||||
|
if (mBroadcast != null) {
|
||||||
|
mBroadcast.unregisterServiceCallBack(mBroadcastCallback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -42,6 +145,17 @@ public class AudioSharingNamePreferenceController extends BasePreferenceControll
|
|||||||
return AudioSharingUtils.isFeatureEnabled() ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
|
return AudioSharingUtils.isFeatureEnabled() ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void displayPreference(PreferenceScreen screen) {
|
||||||
|
super.displayPreference(screen);
|
||||||
|
mPreference = screen.findPreference(getPreferenceKey());
|
||||||
|
if (mPreference != null) {
|
||||||
|
mPreference.setValidator(this);
|
||||||
|
updateBroadcastName();
|
||||||
|
updateQrCodeIcon(isBroadcasting(mLocalBtManager));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getPreferenceKey() {
|
public String getPreferenceKey() {
|
||||||
return PREF_KEY;
|
return PREF_KEY;
|
||||||
@@ -49,10 +163,59 @@ public class AudioSharingNamePreferenceController extends BasePreferenceControll
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
// TODO: update broadcast when name is changed.
|
if (mPreference != null
|
||||||
|
&& mPreference.getSummary() != null
|
||||||
|
&& ((String) newValue).contentEquals(mPreference.getSummary())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var unused =
|
||||||
|
ThreadUtils.postOnBackgroundThread(
|
||||||
|
() -> {
|
||||||
|
if (mBroadcast != null) {
|
||||||
|
mBroadcast.setProgramInfo((String) newValue);
|
||||||
|
if (isBroadcasting(mLocalBtManager)) {
|
||||||
|
// Update broadcast, UI update will be handled after callback
|
||||||
|
mBroadcast.updateBroadcast();
|
||||||
|
} else {
|
||||||
|
// Directly update UI if no ongoing broadcast
|
||||||
|
updateBroadcastName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateBroadcastName() {
|
||||||
|
if (mPreference != null) {
|
||||||
|
var unused =
|
||||||
|
ThreadUtils.postOnBackgroundThread(
|
||||||
|
() -> {
|
||||||
|
if (mBroadcast != null) {
|
||||||
|
String name = mBroadcast.getProgramInfo();
|
||||||
|
ThreadUtils.postOnMainThread(
|
||||||
|
() -> {
|
||||||
|
if (mPreference != null) {
|
||||||
|
mPreference.setText(name);
|
||||||
|
mPreference.setSummary(name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateQrCodeIcon(boolean show) {
|
||||||
|
if (mPreference != null) {
|
||||||
|
ThreadUtils.postOnMainThread(
|
||||||
|
() -> {
|
||||||
|
if (mPreference != null) {
|
||||||
|
mPreference.setShowQrCodeIcon(show);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isTextValid(String value) {
|
public boolean isTextValid(String value) {
|
||||||
return mAudioSharingNameTextValidator.isTextValid(value);
|
return mAudioSharingNameTextValidator.isTextValid(value);
|
||||||
|
@@ -18,10 +18,27 @@ package com.android.settings.connecteddevice.audiosharing;
|
|||||||
|
|
||||||
import com.android.settings.widget.ValidatedEditTextPreference;
|
import com.android.settings.widget.ValidatedEditTextPreference;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validator for Audio Sharing Name, which should be a UTF-8 encoded string containing a minimum of
|
||||||
|
* 4 characters and a maximum of 32 human-readable characters.
|
||||||
|
*/
|
||||||
public class AudioSharingNameTextValidator implements ValidatedEditTextPreference.Validator {
|
public class AudioSharingNameTextValidator implements ValidatedEditTextPreference.Validator {
|
||||||
|
private static final int MIN_LENGTH = 4;
|
||||||
|
private static final int MAX_LENGTH = 32;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isTextValid(String value) {
|
public boolean isTextValid(String value) {
|
||||||
// TODO: Add validate rule if applicable.
|
if (value == null || value.length() < MIN_LENGTH || value.length() > MAX_LENGTH) {
|
||||||
return true;
|
return false;
|
||||||
|
}
|
||||||
|
return isValidUTF8(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isValidUTF8(String value) {
|
||||||
|
byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
|
||||||
|
String reconstructedString = new String(bytes, StandardCharsets.UTF_8);
|
||||||
|
return value.equals(reconstructedString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* 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.BluetoothLeBroadcast;
|
||||||
|
import android.bluetooth.BluetoothLeBroadcastMetadata;
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.lifecycle.DefaultLifecycleObserver;
|
||||||
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
|
import com.android.settings.bluetooth.Utils;
|
||||||
|
import com.android.settings.core.BasePreferenceController;
|
||||||
|
import com.android.settings.widget.ValidatedEditTextPreference;
|
||||||
|
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
public class AudioSharingPasswordPreferenceController extends BasePreferenceController
|
||||||
|
implements ValidatedEditTextPreference.Validator,
|
||||||
|
Preference.OnPreferenceChangeListener,
|
||||||
|
DefaultLifecycleObserver {
|
||||||
|
private static final String PREF_KEY = "audio_sharing_stream_password";
|
||||||
|
|
||||||
|
private final BluetoothLeBroadcast.Callback mBroadcastCallback =
|
||||||
|
new BluetoothLeBroadcast.Callback() {
|
||||||
|
@Override
|
||||||
|
public void onBroadcastMetadataChanged(
|
||||||
|
int broadcastId, BluetoothLeBroadcastMetadata metadata) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBroadcastStartFailed(int reason) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBroadcastStarted(int reason, int broadcastId) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBroadcastStopFailed(int reason) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBroadcastStopped(int reason, int broadcastId) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBroadcastUpdateFailed(int reason, int broadcastId) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBroadcastUpdated(int reason, int broadcastId) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPlaybackStarted(int reason, int broadcastId) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPlaybackStopped(int reason, int broadcastId) {}
|
||||||
|
};
|
||||||
|
@Nullable private final LocalBluetoothLeBroadcast mBroadcast;
|
||||||
|
private final Executor mExecutor;
|
||||||
|
private final AudioSharingPasswordValidator mAudioSharingPasswordValidator;
|
||||||
|
@Nullable private ValidatedEditTextPreference mPreference;
|
||||||
|
|
||||||
|
public AudioSharingPasswordPreferenceController(Context context, String preferenceKey) {
|
||||||
|
super(context, preferenceKey);
|
||||||
|
mBroadcast =
|
||||||
|
Utils.getLocalBtManager(context).getProfileManager().getLeAudioBroadcastProfile();
|
||||||
|
mAudioSharingPasswordValidator = new AudioSharingPasswordValidator();
|
||||||
|
mExecutor = Executors.newSingleThreadExecutor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart(@NonNull LifecycleOwner owner) {
|
||||||
|
if (mBroadcast != null) {
|
||||||
|
mBroadcast.registerServiceCallBack(mExecutor, mBroadcastCallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStop(@NonNull LifecycleOwner owner) {
|
||||||
|
if (mBroadcast != null) {
|
||||||
|
mBroadcast.unregisterServiceCallBack(mBroadcastCallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAvailabilityStatus() {
|
||||||
|
return AudioSharingUtils.isFeatureEnabled() ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void displayPreference(PreferenceScreen screen) {
|
||||||
|
super.displayPreference(screen);
|
||||||
|
mPreference = screen.findPreference(getPreferenceKey());
|
||||||
|
if (mPreference != null) {
|
||||||
|
mPreference.setValidator(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPreferenceKey() {
|
||||||
|
return PREF_KEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
|
// TODO(chelseahao): implement
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTextValid(String value) {
|
||||||
|
return mAudioSharingPasswordValidator.isTextValid(value);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* 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 com.android.settings.widget.ValidatedEditTextPreference;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validator for Audio Sharing Password, which should be a UTF-8 string that has at least 4 octets
|
||||||
|
* and should not exceed 16 octets.
|
||||||
|
*/
|
||||||
|
public class AudioSharingPasswordValidator implements ValidatedEditTextPreference.Validator {
|
||||||
|
private static final int MIN_OCTETS = 4;
|
||||||
|
private static final int MAX_OCTETS = 16;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTextValid(String value) {
|
||||||
|
if (value == null
|
||||||
|
|| getOctetsCount(value) < MIN_OCTETS
|
||||||
|
|| getOctetsCount(value) > MAX_OCTETS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isValidUTF8(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getOctetsCount(String value) {
|
||||||
|
return value.getBytes(StandardCharsets.UTF_8).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isValidUTF8(String value) {
|
||||||
|
byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
|
||||||
|
String reconstructedString = new String(bytes, StandardCharsets.UTF_8);
|
||||||
|
return value.equals(reconstructedString);
|
||||||
|
}
|
||||||
|
}
|
@@ -336,7 +336,7 @@ public class AudioSharingUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Returns if the broadcast is on-going. */
|
/** Returns if the broadcast is on-going. */
|
||||||
public static boolean isBroadcasting(LocalBluetoothManager manager) {
|
public static boolean isBroadcasting(@Nullable LocalBluetoothManager manager) {
|
||||||
if (manager == null) return false;
|
if (manager == null) return false;
|
||||||
LocalBluetoothLeBroadcast broadcast =
|
LocalBluetoothLeBroadcast broadcast =
|
||||||
manager.getProfileManager().getLeAudioBroadcastProfile();
|
manager.getProfileManager().getLeAudioBroadcastProfile();
|
||||||
|
Reference in New Issue
Block a user