[LE broadcast sink] Add the source list in boradcast sink UI.
Add the source list in boradcast sink UI. Add the password dialog. hsv link1: https://hsv.googleplex.com/6256032201310208 hsv link2: https://hsv.googleplex.com/5934966820044800 hsv link3: https://hsv.googleplex.com/6238095344140288 Bug: 228258236 Test: manual test Change-Id: I698c2f7aba9baa9f143a98629b8796eda57fb379
This commit is contained in:
committed by
SongFerng Wang
parent
74b1027fe2
commit
1709c80eff
26
res/drawable/bluetooth_broadcast_dialog_done.xml
Normal file
26
res/drawable/bluetooth_broadcast_dialog_done.xml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright (C) 2022 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.
|
||||||
|
-->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M9.55,18 L3.85,12.3 5.275,10.875 9.55,15.15 18.725,5.975 20.15,7.4Z"/>
|
||||||
|
</vector>
|
43
res/layout/bluetooth_find_broadcast_password_dialog.xml
Normal file
43
res/layout/bluetooth_find_broadcast_password_dialog.xml
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright (C) 2022 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="wrap_content"
|
||||||
|
android:paddingLeft="?android:attr/dialogPreferredPadding"
|
||||||
|
android:paddingRight="?android:attr/dialogPreferredPadding"
|
||||||
|
android:orientation="vertical">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/broadcast_name_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="48dp"
|
||||||
|
android:textAlignment="viewStart"/>
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/broadcast_edit_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="48dp"
|
||||||
|
android:textAlignment="viewStart"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/broadcast_error_message"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="6dp"
|
||||||
|
style="@style/TextAppearance.ErrorText"
|
||||||
|
android:visibility="invisible"/>
|
||||||
|
</LinearLayout>
|
@@ -14139,4 +14139,10 @@
|
|||||||
<string name="bluetooth_find_broadcast_button_leave">Leave broadcast</string>
|
<string name="bluetooth_find_broadcast_button_leave">Leave broadcast</string>
|
||||||
<!-- The Button of the action to scan QR code [CHAR LIMIT=none] -->
|
<!-- The Button of the action to scan QR code [CHAR LIMIT=none] -->
|
||||||
<string name="bluetooth_find_broadcast_button_scan">Scan QR code</string>
|
<string name="bluetooth_find_broadcast_button_scan">Scan QR code</string>
|
||||||
|
<!-- The title of enter password dialog in bluetooth find broadcast page. [CHAR LIMIT=none] -->
|
||||||
|
<string name="find_broadcast_password_dialog_title">Enter password</string>
|
||||||
|
<!-- The error message of enter password dialog in bluetooth find broadcast page [CHAR LIMIT=none] -->
|
||||||
|
<string name="find_broadcast_password_dialog_connection_error">Can\u2019t connect. Try again.</string>
|
||||||
|
<!-- The error message of enter password dialog in bluetooth find broadcast page [CHAR LIMIT=none] -->
|
||||||
|
<string name="find_broadcast_password_dialog_password_error">Wrong password</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.bluetooth;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothLeBroadcastMetadata;
|
||||||
|
import android.bluetooth.BluetoothLeBroadcastSubgroup;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.PreferenceViewHolder;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settingslib.Utils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preference to display a broadcast source in the Broadcast Source List.
|
||||||
|
*/
|
||||||
|
class BluetoothBroadcastSourcePreference extends Preference {
|
||||||
|
|
||||||
|
private static final int RESOURCE_ID_UNKNOWN_PROGRAM_INFO = R.string.device_info_default;
|
||||||
|
private static final int RESOURCE_ID_ICON = R.drawable.settings_input_antenna;
|
||||||
|
|
||||||
|
private BluetoothLeBroadcastMetadata mBluetoothLeBroadcastMetadata;
|
||||||
|
private ImageView mFrictionImageView;
|
||||||
|
private String mTitle;
|
||||||
|
private boolean mStatus;
|
||||||
|
private boolean mIsEncrypted;
|
||||||
|
|
||||||
|
BluetoothBroadcastSourcePreference(@NonNull Context context,
|
||||||
|
@NonNull BluetoothLeBroadcastMetadata source) {
|
||||||
|
super(context);
|
||||||
|
initUi();
|
||||||
|
updateMetadataAndRefreshUi(source, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(final PreferenceViewHolder view) {
|
||||||
|
super.onBindViewHolder(view);
|
||||||
|
view.findViewById(R.id.two_target_divider).setVisibility(View.INVISIBLE);
|
||||||
|
final ImageButton imageButton = (ImageButton) view.findViewById(R.id.icon_button);
|
||||||
|
imageButton.setVisibility(View.GONE);
|
||||||
|
mFrictionImageView = (ImageView) view.findViewById(R.id.friction_icon);
|
||||||
|
updateStatusButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initUi() {
|
||||||
|
setLayoutResource(R.layout.preference_access_point);
|
||||||
|
setWidgetLayoutResource(R.layout.access_point_friction_widget);
|
||||||
|
|
||||||
|
mStatus = false;
|
||||||
|
final Drawable drawable = getContext().getDrawable(RESOURCE_ID_ICON);
|
||||||
|
if (drawable != null) {
|
||||||
|
drawable.setTint(Utils.getColorAttrDefaultColor(getContext(),
|
||||||
|
android.R.attr.colorControlNormal));
|
||||||
|
setIcon(drawable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateStatusButton() {
|
||||||
|
if (mFrictionImageView == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mStatus || mIsEncrypted) {
|
||||||
|
Drawable drawable;
|
||||||
|
if (mStatus) {
|
||||||
|
drawable = getContext().getDrawable(R.drawable.bluetooth_broadcast_dialog_done);
|
||||||
|
} else {
|
||||||
|
drawable = getContext().getDrawable(R.drawable.ic_friction_lock_closed);
|
||||||
|
}
|
||||||
|
if (drawable != null) {
|
||||||
|
drawable.setTint(Utils.getColorAttrDefaultColor(getContext(),
|
||||||
|
android.R.attr.colorControlNormal));
|
||||||
|
mFrictionImageView.setImageDrawable(drawable);
|
||||||
|
}
|
||||||
|
mFrictionImageView.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
mFrictionImageView.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the title and status from BluetoothLeBroadcastMetadata.
|
||||||
|
*/
|
||||||
|
public void updateMetadataAndRefreshUi(BluetoothLeBroadcastMetadata source, boolean status) {
|
||||||
|
mBluetoothLeBroadcastMetadata = source;
|
||||||
|
mTitle = getBroadcastMetadataProgramInfo();
|
||||||
|
mIsEncrypted = mBluetoothLeBroadcastMetadata.isEncrypted();
|
||||||
|
mStatus = status;
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the BluetoothLeBroadcastMetadata.
|
||||||
|
*/
|
||||||
|
public BluetoothLeBroadcastMetadata getBluetoothLeBroadcastMetadata() {
|
||||||
|
return mBluetoothLeBroadcastMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refresh() {
|
||||||
|
setTitle(mTitle);
|
||||||
|
updateStatusButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getBroadcastMetadataProgramInfo() {
|
||||||
|
if (mBluetoothLeBroadcastMetadata == null) {
|
||||||
|
return getContext().getString(RESOURCE_ID_UNKNOWN_PROGRAM_INFO);
|
||||||
|
}
|
||||||
|
final List<BluetoothLeBroadcastSubgroup> subgroups =
|
||||||
|
mBluetoothLeBroadcastMetadata.getSubgroups();
|
||||||
|
if (subgroups.isEmpty()) {
|
||||||
|
return getContext().getString(RESOURCE_ID_UNKNOWN_PROGRAM_INFO);
|
||||||
|
}
|
||||||
|
return subgroups.stream()
|
||||||
|
.map(i -> i.getContentMetadata().getProgramInfo())
|
||||||
|
.filter(i -> !TextUtils.isEmpty(i))
|
||||||
|
.findFirst().orElse(getContext().getString(RESOURCE_ID_UNKNOWN_PROGRAM_INFO));
|
||||||
|
}
|
||||||
|
}
|
@@ -19,33 +19,53 @@ package com.android.settings.bluetooth;
|
|||||||
import static android.bluetooth.BluetoothDevice.BOND_NONE;
|
import static android.bluetooth.BluetoothDevice.BOND_NONE;
|
||||||
import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
|
import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
import android.bluetooth.BluetoothLeBroadcastAssistant;
|
||||||
|
import android.bluetooth.BluetoothLeBroadcastMetadata;
|
||||||
|
import android.bluetooth.BluetoothLeBroadcastReceiveState;
|
||||||
|
import android.bluetooth.le.ScanFilter;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.PreferenceCategory;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.dashboard.RestrictedDashboardFragment;
|
import com.android.settings.dashboard.RestrictedDashboardFragment;
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||||
|
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||||
|
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
|
||||||
import com.android.settingslib.core.AbstractPreferenceController;
|
import com.android.settingslib.core.AbstractPreferenceController;
|
||||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This fragment allowed users to find the nearby broadcast sources.
|
* This fragment allowed users to find the nearby broadcast sources.
|
||||||
*/
|
*/
|
||||||
public class BluetoothFindBroadcastsFragment extends RestrictedDashboardFragment {
|
public class BluetoothFindBroadcastsFragment extends RestrictedDashboardFragment {
|
||||||
|
|
||||||
private static final String TAG = "BTFindBroadcastsFrg";
|
private static final String TAG = "BtFindBroadcastsFrg";
|
||||||
|
|
||||||
public static final String KEY_DEVICE_ADDRESS = "device_address";
|
public static final String KEY_DEVICE_ADDRESS = "device_address";
|
||||||
|
public static final String PREF_KEY_BROADCAST_SOURCE_LIST = "broadcast_source_list";
|
||||||
public static final String PREF_KEY_BROADCAST_SOURCE = "broadcast_source";
|
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
String mDeviceAddress;
|
String mDeviceAddress;
|
||||||
@@ -53,6 +73,91 @@ public class BluetoothFindBroadcastsFragment extends RestrictedDashboardFragment
|
|||||||
LocalBluetoothManager mManager;
|
LocalBluetoothManager mManager;
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
CachedBluetoothDevice mCachedDevice;
|
CachedBluetoothDevice mCachedDevice;
|
||||||
|
@VisibleForTesting
|
||||||
|
PreferenceCategory mBroadcastSourceListCategory;
|
||||||
|
private LocalBluetoothLeBroadcastAssistant mLeBroadcastAssistant;
|
||||||
|
private BluetoothBroadcastSourcePreference mSelectedPreference;
|
||||||
|
private Executor mExecutor;
|
||||||
|
private int mSourceId;
|
||||||
|
|
||||||
|
private BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback =
|
||||||
|
new BluetoothLeBroadcastAssistant.Callback() {
|
||||||
|
@Override
|
||||||
|
public void onSearchStarted(int reason) {
|
||||||
|
Log.d(TAG, "onSearchStarted: " + reason);
|
||||||
|
|
||||||
|
getActivity().runOnUiThread(
|
||||||
|
() -> cacheRemoveAllPrefs(mBroadcastSourceListCategory));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSearchStartFailed(int reason) {
|
||||||
|
Log.d(TAG, "onSearchStartFailed: " + reason);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSearchStopped(int reason) {
|
||||||
|
Log.d(TAG, "onSearchStopped: " + reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSearchStopFailed(int reason) {
|
||||||
|
Log.d(TAG, "onSearchStopFailed: " + reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSourceFound(@NonNull BluetoothLeBroadcastMetadata source) {
|
||||||
|
Log.d(TAG, "onSourceFound:");
|
||||||
|
getActivity().runOnUiThread(() -> updateListCategory(source, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSourceAdded(@NonNull BluetoothDevice sink, int sourceId, int reason) {
|
||||||
|
setSourceId(sourceId);
|
||||||
|
if (mSelectedPreference == null) {
|
||||||
|
Log.w(TAG, "onSourceAdded: mSelectedPreference == null!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getActivity().runOnUiThread(() -> updateListCategory(
|
||||||
|
mSelectedPreference.getBluetoothLeBroadcastMetadata(), true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSourceAddFailed(@NonNull BluetoothDevice sink,
|
||||||
|
@NonNull BluetoothLeBroadcastMetadata source, int reason) {
|
||||||
|
mSelectedPreference = null;
|
||||||
|
Log.d(TAG, "onSourceAddFailed: clear the mSelectedPreference.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSourceModified(@NonNull BluetoothDevice sink, int sourceId,
|
||||||
|
int reason) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSourceModifyFailed(@NonNull BluetoothDevice sink, int sourceId,
|
||||||
|
int reason) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSourceRemoved(@NonNull BluetoothDevice sink, int sourceId,
|
||||||
|
int reason) {
|
||||||
|
Log.d(TAG, "onSourceRemoved:");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSourceRemoveFailed(@NonNull BluetoothDevice sink, int sourceId,
|
||||||
|
int reason) {
|
||||||
|
Log.d(TAG, "onSourceRemoveFailed:");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceiveStateChanged(@NonNull BluetoothDevice sink, int sourceId,
|
||||||
|
@NonNull BluetoothLeBroadcastReceiveState state) {
|
||||||
|
Log.d(TAG, "onReceiveStateChanged:");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public BluetoothFindBroadcastsFragment() {
|
public BluetoothFindBroadcastsFragment() {
|
||||||
super(DISALLOW_CONFIG_BLUETOOTH);
|
super(DISALLOW_CONFIG_BLUETOOTH);
|
||||||
@@ -75,19 +180,50 @@ public class BluetoothFindBroadcastsFragment extends RestrictedDashboardFragment
|
|||||||
mDeviceAddress = getArguments().getString(KEY_DEVICE_ADDRESS);
|
mDeviceAddress = getArguments().getString(KEY_DEVICE_ADDRESS);
|
||||||
mManager = getLocalBluetoothManager(context);
|
mManager = getLocalBluetoothManager(context);
|
||||||
mCachedDevice = getCachedDevice(mDeviceAddress);
|
mCachedDevice = getCachedDevice(mDeviceAddress);
|
||||||
|
mLeBroadcastAssistant = getLeBroadcastAssistant();
|
||||||
|
mExecutor = Executors.newSingleThreadExecutor();
|
||||||
|
|
||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
if (mCachedDevice == null) {
|
if (mCachedDevice == null || mLeBroadcastAssistant == null) {
|
||||||
//Close this page if device is null with invalid device mac address
|
//Close this page if device is null with invalid device mac address
|
||||||
Log.w(TAG, "onAttach() CachedDevice is null!");
|
//or if the device does not have LeBroadcastAssistant profile
|
||||||
|
Log.w(TAG, "onAttach() CachedDevice or LeBroadcastAssistant is null!");
|
||||||
finish();
|
finish();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle icicle) {
|
||||||
|
super.onCreate(icicle);
|
||||||
|
|
||||||
|
mBroadcastSourceListCategory = findPreference(PREF_KEY_BROADCAST_SOURCE_LIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
if (mLeBroadcastAssistant != null) {
|
||||||
|
mLeBroadcastAssistant.registerServiceCallBack(mExecutor, mBroadcastAssistantCallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
finishFragmentIfNecessary();
|
finishFragmentIfNecessary();
|
||||||
|
//check assistant status. Start searching...
|
||||||
|
if (mLeBroadcastAssistant != null && !mLeBroadcastAssistant.isSearchInProgress()) {
|
||||||
|
mLeBroadcastAssistant.startSearchingForSources(getScanFilter());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStop() {
|
||||||
|
super.onStop();
|
||||||
|
if (mLeBroadcastAssistant != null) {
|
||||||
|
mLeBroadcastAssistant.unregisterServiceCallBack(mBroadcastAssistantCallback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -125,4 +261,110 @@ public class BluetoothFindBroadcastsFragment extends RestrictedDashboardFragment
|
|||||||
}
|
}
|
||||||
return controllers;
|
return controllers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private LocalBluetoothLeBroadcastAssistant getLeBroadcastAssistant() {
|
||||||
|
if (mManager == null) {
|
||||||
|
Log.w(TAG, "getLeBroadcastAssistant: LocalBluetoothManager is null!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalBluetoothProfileManager profileManager = mManager.getProfileManager();
|
||||||
|
if (profileManager == null) {
|
||||||
|
Log.w(TAG, "getLeBroadcastAssistant: LocalBluetoothProfileManager is null!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return profileManager.getLeAudioBroadcastAssistantProfile();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ScanFilter> getScanFilter() {
|
||||||
|
// Currently there is no function for setting the ScanFilter. It may have this function
|
||||||
|
// in the further.
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateListCategory(BluetoothLeBroadcastMetadata source, boolean isConnected) {
|
||||||
|
BluetoothBroadcastSourcePreference item = mBroadcastSourceListCategory.findPreference(
|
||||||
|
Integer.toString(source.getBroadcastId()));
|
||||||
|
if (item == null) {
|
||||||
|
item = createBluetoothBroadcastSourcePreference(source);
|
||||||
|
mBroadcastSourceListCategory.addPreference(item);
|
||||||
|
}
|
||||||
|
item.updateMetadataAndRefreshUi(source, isConnected);
|
||||||
|
item.setOrder(isConnected ? 0 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BluetoothBroadcastSourcePreference createBluetoothBroadcastSourcePreference(
|
||||||
|
BluetoothLeBroadcastMetadata source) {
|
||||||
|
BluetoothBroadcastSourcePreference pref = new BluetoothBroadcastSourcePreference(
|
||||||
|
getContext(), source);
|
||||||
|
pref.setKey(Integer.toString(source.getBroadcastId()));
|
||||||
|
pref.setOnPreferenceClickListener(preference -> {
|
||||||
|
if (source.isEncrypted()) {
|
||||||
|
launchBroadcastCodeDialog(pref);
|
||||||
|
} else {
|
||||||
|
addSource(pref);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
return pref;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addSource(BluetoothBroadcastSourcePreference pref) {
|
||||||
|
if (mLeBroadcastAssistant == null || mCachedDevice == null) {
|
||||||
|
Log.w(TAG, "addSource: LeBroadcastAssistant or CachedDevice is null!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mSelectedPreference != null) {
|
||||||
|
// The previous preference status set false after user selects the new Preference.
|
||||||
|
getActivity().runOnUiThread(
|
||||||
|
() -> {
|
||||||
|
mSelectedPreference.updateMetadataAndRefreshUi(
|
||||||
|
mSelectedPreference.getBluetoothLeBroadcastMetadata(), false);
|
||||||
|
mSelectedPreference.setOrder(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
mSelectedPreference = pref;
|
||||||
|
mLeBroadcastAssistant.addSource(mCachedDevice.getDevice(),
|
||||||
|
pref.getBluetoothLeBroadcastMetadata(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addBroadcastCodeIntoPreference(BluetoothBroadcastSourcePreference pref,
|
||||||
|
String broadcastCode) {
|
||||||
|
BluetoothLeBroadcastMetadata metadata =
|
||||||
|
new BluetoothLeBroadcastMetadata.Builder(pref.getBluetoothLeBroadcastMetadata())
|
||||||
|
.setBroadcastCode(broadcastCode.getBytes(StandardCharsets.UTF_8))
|
||||||
|
.build();
|
||||||
|
pref.updateMetadataAndRefreshUi(metadata, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void launchBroadcastCodeDialog(BluetoothBroadcastSourcePreference pref) {
|
||||||
|
final View layout = LayoutInflater.from(getContext()).inflate(
|
||||||
|
R.layout.bluetooth_find_broadcast_password_dialog, null);
|
||||||
|
final TextView broadcastName = layout.requireViewById(R.id.broadcast_name_text);
|
||||||
|
final EditText editText = layout.requireViewById(R.id.broadcast_edit_text);
|
||||||
|
broadcastName.setText(pref.getTitle());
|
||||||
|
AlertDialog alertDialog = new AlertDialog.Builder(getContext())
|
||||||
|
.setTitle(R.string.find_broadcast_password_dialog_title)
|
||||||
|
.setView(layout)
|
||||||
|
.setNeutralButton(android.R.string.cancel, null)
|
||||||
|
.setPositiveButton(R.string.bluetooth_connect_access_dialog_positive,
|
||||||
|
(d, w) -> {
|
||||||
|
Log.d(TAG, "setPositiveButton: clicked");
|
||||||
|
addBroadcastCodeIntoPreference(pref, editText.getText().toString());
|
||||||
|
addSource(pref);
|
||||||
|
})
|
||||||
|
.create();
|
||||||
|
|
||||||
|
alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
|
||||||
|
alertDialog.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSourceId() {
|
||||||
|
return mSourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSourceId(int sourceId) {
|
||||||
|
mSourceId = sourceId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user