Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5e7c054b authored by Chelsea Hao's avatar Chelsea Hao Committed by Android (Google) Code Review
Browse files

Merge changes I99011feb,Ie066077f,I44e631cb into main

* changes:
  [Audiosharing] Handle source remove plus small refactor.
  [Audiosharing] Some UI tweaks (e.g, sort by RSSI)
  [Audiosharing] Add button action in detail page.
parents 57290578 a6680963
Loading
Loading
Loading
Loading
+5 −20
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
@@ -26,36 +25,22 @@
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="3"
        android:layout_marginBottom="35dp">
        android:layout_marginBottom="55dp">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingStart="40dp"
            android:paddingEnd="40dp"
            android:layout_gravity="bottom"
            android:gravity="center"
            android:orientation="vertical">
            <ImageView
                android:src="@drawable/ic_qr_code_scanner"
                android:tint="?androidprv:attr/materialColorPrimaryContainer"
                android:layout_width="@dimen/qrcode_icon_size"
                android:layout_height="@dimen/qrcode_icon_size"
                android:contentDescription="@null"/>

            <TextView
                style="@style/QrCodeScanner"
                android:textSize="24sp"
                android:text="@string/bluetooth_find_broadcast_button_scan"
                android:gravity="center"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="19dp"/>

            <TextView
                style="@style/QrCodeScanner"
                android:text="@string/bt_le_audio_scan_qr_code_scanner"
                android:text="Scan an audio stream QR code to listen with the active LE device"
                android:gravity="center"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"/>
                android:layout_marginTop="20dp"/>
        </LinearLayout>
    </LinearLayout>

+18 −10
Original line number Diff line number Diff line
@@ -18,23 +18,31 @@
<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:settings="http://schemas.android.com/apk/res-auto"
    android:title="@string/audio_streams_title">
    android:title="Find an audio stream">

    <Preference
        android:key="audio_streams_scan_qr_code"
        android:title="@string/bluetooth_find_broadcast_button_scan"
        android:icon="@drawable/ic_add_24dp"
        android:summary="@string/audio_streams_qr_code_summary"
        settings:controller="com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsScanQrCodeController" />
    <com.android.settingslib.widget.TopIntroPreference
        android:key="audio_streams_top_intro"
        android:title="Listen to a device that's sharing audio or to a nearby Auracast broadcast"
        settings:searchable="false"/>

    <Preference
        android:key="audio_streams_active_device"
        android:title="Listen with"
        android:title="Your audio device"
        settings:controller="com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsActiveDeviceController" />

    <com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsProgressCategoryPreference
        android:key="audio_streams_nearby_category"
        android:title="@string/audio_streams_pref_title"
        settings:controller="com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsProgressCategoryController" />
        android:title="Audio streams nearby"
        settings:controller="com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsProgressCategoryController">

    <Preference
        android:key="audio_streams_scan_qr_code"
        android:title="Scan a QR code"
        android:icon="@drawable/ic_add_24dp"
        android:summary="Start listening by scanning a stream's QR code"
        android:order="0"
        settings:controller="com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsScanQrCodeController" />

    </com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsProgressCategoryPreference>

</PreferenceScreen>
 No newline at end of file
+27 −18
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
  -->

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

@@ -23,70 +24,78 @@
        android:id="@+id/dialog_bg"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingStart="25dp"
        android:paddingEnd="25dp"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="@dimen/broadcast_dialog_margin"
            android:layout_marginBottom="25dp"
            android:orientation="vertical">

            <ImageView
                android:id="@+id/dialog_icon"
                android:layout_width="36dp"
                android:layout_height="36dp"
                android:layout_marginTop="@dimen/broadcast_dialog_icon_margin_top"
                android:layout_marginBottom="@dimen/broadcast_dialog_title_img_margin_top"
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:layout_marginTop="24dp"
                android:layout_gravity="center"
                android:src="@drawable/ic_bt_audio_sharing"/>

            <TextView
                style="@style/BroadcastDialogTitleStyle"
                android:id="@+id/dialog_title"
                android:textAppearance="@android:style/TextAppearance.DeviceDefault.Headline"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="15dp"
                android:gravity="center"
                android:layout_gravity="center"/>

            <TextView
                style="@style/BroadcastDialogBodyStyle"
                android:id="@+id/dialog_subtitle"
                android:textAppearance="@android:style/TextAppearance.DeviceDefault.Small"
                android:textStyle="bold"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="15dp"
                android:gravity="center"
                android:layout_gravity="center"
                android:visibility="gone"/>

            <TextView
                style="@style/BroadcastDialogBodyStyle"
                android:id="@+id/dialog_subtitle_2"
                android:textAppearance="@android:style/TextAppearance.DeviceDefault.Small"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="15dp"
                android:gravity="center"
                android:layout_gravity="center"
                android:visibility="gone"/>
        </LinearLayout>

        <LinearLayout
        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="@dimen/broadcast_dialog_margin"
            android:orientation="horizontal">
            android:layout_marginBottom="@dimen/broadcast_dialog_margin">
            <Button
                android:id="@+id/left_button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="16dp"
                android:layout_weight="1"
                android:visibility="invisible"/>
                android:visibility="gone"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                style="@style/BroadcastActionButton"/>
            <Button
                android:id="@+id/right_button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:layout_marginRight="16dp"
                android:visibility="invisible"/>
        </LinearLayout>
                android:visibility="gone"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                style="@style/BroadcastActionButton"/>
        </androidx.constraintlayout.widget.ConstraintLayout>

    </LinearLayout>
</FrameLayout>
 No newline at end of file
+8 −1
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@
            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"/>
            android:text="To listen to this audio stream, other people can connect compatible headphones to their Android device. They can then scan this QR code."/>

        <LinearLayout
            android:layout_width="match_parent"
@@ -50,6 +50,13 @@
                android:layout_width="@dimen/qrcode_size"
                android:layout_height="@dimen/qrcode_size"
                android:src="@android:color/transparent"/>

            <TextView
                android:id="@+id/password"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="15sp"
                android:textColor="?android:attr/textColorPrimary"/>
        </LinearLayout>

    </LinearLayout>
+137 −6
Original line number Diff line number Diff line
@@ -16,37 +16,168 @@

package com.android.settings.connecteddevice.audiosharing.audiostreams;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeBroadcastAssistant;
import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.bluetooth.BluetoothLeBroadcastReceiveState;
import android.content.Context;
import android.util.Log;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.preference.PreferenceScreen;

import com.android.settings.R;
import com.android.settings.bluetooth.Utils;
import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
import com.android.settingslib.utils.ThreadUtils;
import com.android.settingslib.widget.ActionButtonsPreference;

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class AudioStreamButtonController extends BasePreferenceController
        implements DefaultLifecycleObserver {
    private static final String TAG = "AudioStreamButtonController";
    private static final String KEY = "audio_stream_button";
    private final BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback =
            new AudioStreamsBroadcastAssistantCallback() {
                @Override
                public void onSourceRemoved(BluetoothDevice sink, int sourceId, int reason) {
                    super.onSourceRemoved(sink, sourceId, reason);
                    updateButton();
                }

                @Override
                public void onSourceRemoveFailed(BluetoothDevice sink, int sourceId, int reason) {
                    super.onSourceRemoveFailed(sink, sourceId, reason);
                    updateButton();
                }

                @Override
                public void onReceiveStateChanged(
                        BluetoothDevice sink,
                        int sourceId,
                        BluetoothLeBroadcastReceiveState state) {
                    super.onReceiveStateChanged(sink, sourceId, state);
                    if (mAudioStreamsHelper.isConnected(state)) {
                        updateButton();
                    }
                }

                @Override
                public void onSourceAddFailed(
                        BluetoothDevice sink, BluetoothLeBroadcastMetadata source, int reason) {
                    super.onSourceAddFailed(sink, source, reason);
                    updateButton();
                }

                @Override
                public void onSourceLost(int broadcastId) {
                    super.onSourceLost(broadcastId);
                    updateButton();
                }
            };

    private final AudioStreamsRepository mAudioStreamsRepository =
            AudioStreamsRepository.getInstance();
    private final Executor mExecutor;
    private final AudioStreamsHelper mAudioStreamsHelper;
    private final @Nullable LocalBluetoothLeBroadcastAssistant mLeBroadcastAssistant;
    private @Nullable ActionButtonsPreference mPreference;
    private int mBroadcastId = -1;

    public AudioStreamButtonController(Context context, String preferenceKey) {
        super(context, preferenceKey);
        mExecutor = Executors.newSingleThreadExecutor();
        mAudioStreamsHelper = new AudioStreamsHelper(Utils.getLocalBtManager(context));
        mLeBroadcastAssistant = mAudioStreamsHelper.getLeBroadcastAssistant();
    }

    @Override
    public void onStart(@NonNull LifecycleOwner owner) {
        if (mLeBroadcastAssistant == null) {
            Log.w(TAG, "onStart(): LeBroadcastAssistant is null!");
            return;
        }
        mLeBroadcastAssistant.registerServiceCallBack(mExecutor, mBroadcastAssistantCallback);
    }

    @Override
    public void onStop(@NonNull LifecycleOwner owner) {
        if (mLeBroadcastAssistant == null) {
            Log.w(TAG, "onStop(): LeBroadcastAssistant is null!");
            return;
        }
        mLeBroadcastAssistant.unregisterServiceCallBack(mBroadcastAssistantCallback);
    }

    @Override
    public final void displayPreference(PreferenceScreen screen) {
        mPreference = screen.findPreference(getPreferenceKey());
        updateButton();
        super.displayPreference(screen);
    }

    private void updateButton() {
        if (mPreference != null) {
            if (mAudioStreamsHelper.getAllConnectedSources().stream()
                    .map(BluetoothLeBroadcastReceiveState::getBroadcastId)
                    .anyMatch(connectedBroadcastId -> connectedBroadcastId == mBroadcastId)) {
                ThreadUtils.postOnMainThread(
                        () -> {
                            if (mPreference != null) {
                                mPreference.setButton1Enabled(true);
            // TODO(chelseahao): update this based on stream connection state
                                mPreference
                    .setButton1Text(R.string.bluetooth_device_context_disconnect)
                    .setButton1Icon(R.drawable.ic_settings_close);
                                        .setButton1Text(
                                                R.string.bluetooth_device_context_disconnect)
                                        .setButton1Icon(R.drawable.ic_settings_close)
                                        .setButton1OnClickListener(
                                                unused -> {
                                                    if (mPreference != null) {
                                                        mPreference.setButton1Enabled(false);
                                                    }
                                                    mAudioStreamsHelper.removeSource(mBroadcastId);
                                                });
                            }
                        });
            } else {
                View.OnClickListener clickToRejoin =
                        unused ->
                                ThreadUtils.postOnBackgroundThread(
                                        () -> {
                                            var metadata =
                                                    mAudioStreamsRepository.getSavedMetadata(
                                                            mContext, mBroadcastId);
                                            if (metadata != null) {
                                                mAudioStreamsHelper.addSource(metadata);
                                                ThreadUtils.postOnMainThread(
                                                        () -> {
                                                            if (mPreference != null) {
                                                                mPreference.setButton1Enabled(
                                                                        false);
                                                            }
                                                        });
                                            }
                                        });
                ThreadUtils.postOnMainThread(
                        () -> {
                            if (mPreference != null) {
                                mPreference.setButton1Enabled(true);
                                mPreference
                                        .setButton1Text(R.string.bluetooth_device_context_connect)
                                        .setButton1Icon(R.drawable.ic_add_24dp)
                                        .setButton1OnClickListener(clickToRejoin);
                            }
                        });
            }
        } else {
            Log.w(TAG, "updateButton(): preference is null!");
        }
        super.displayPreference(screen);
    }

    @Override
Loading