[Audiosharing] Impl of two error dialogs.

Bug: 305620450
Test: manual
Change-Id: I5bd4a4b2ab54c382f325c7a6bb4a3029d47786e0
This commit is contained in:
chelseahao
2024-01-17 14:01:09 +08:00
committed by Chelsea Hao
parent b34e67228f
commit 7bc4ea01d1
4 changed files with 290 additions and 7 deletions

View File

@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2024 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.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/dialog_bg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/broadcast_dialog_margin"
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_gravity="center"
android:src="@drawable/ic_bt_audio_sharing"/>
<TextView
style="@style/BroadcastDialogTitleStyle"
android:id="@+id/dialog_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_gravity="center"/>
<TextView
style="@style/BroadcastDialogBodyStyle"
android:id="@+id/dialog_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_gravity="center"
android:visibility="gone"/>
<TextView
style="@style/BroadcastDialogBodyStyle"
android:id="@+id/dialog_subtitle_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_gravity="center"
android:visibility="gone"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/broadcast_dialog_margin"
android:orientation="horizontal">
<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="gone"/>
<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="gone"/>
</LinearLayout>
</LinearLayout>
</FrameLayout>

View File

@@ -71,6 +71,7 @@ public class AudioStreamsDashboardFragment extends DashboardFragment {
super.onAttach(context);
use(AudioStreamsScanQrCodeController.class).setFragment(this);
mAudioStreamsProgressCategoryController = use(AudioStreamsProgressCategoryController.class);
mAudioStreamsProgressCategoryController.setFragment(this);
}
@Override

View File

@@ -0,0 +1,151 @@
/*
* Copyright (C) 2024 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.audiostreams;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.google.common.base.Strings;
import java.util.function.Consumer;
public class AudioStreamsDialogFragment extends InstrumentedDialogFragment {
private static final String TAG = "AudioStreamsDialogFragment";
private final DialogBuilder mDialogBuilder;
AudioStreamsDialogFragment(DialogBuilder dialogBuilder) {
mDialogBuilder = dialogBuilder;
}
@Override
public int getMetricsCategory() {
// TODO(chelseahao): update metrics id
return 0;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return mDialogBuilder.build();
}
static void show(Fragment host, DialogBuilder dialogBuilder) {
FragmentManager manager = host.getChildFragmentManager();
(new AudioStreamsDialogFragment(dialogBuilder)).show(manager, TAG);
}
static class DialogBuilder {
private final Context mContext;
private final AlertDialog.Builder mBuilder;
private String mTitle;
private String mSubTitle1;
private String mSubTitle2;
private String mLeftButtonText;
private String mRightButtonText;
private Consumer<AlertDialog> mLeftButtonOnClickListener;
private Consumer<AlertDialog> mRightButtonOnClickListener;
DialogBuilder(Context context) {
mContext = context;
mBuilder = new AlertDialog.Builder(context);
}
DialogBuilder setTitle(String title) {
mTitle = title;
return this;
}
DialogBuilder setSubTitle1(String subTitle1) {
mSubTitle1 = subTitle1;
return this;
}
DialogBuilder setSubTitle2(String subTitle2) {
mSubTitle2 = subTitle2;
return this;
}
DialogBuilder setLeftButtonText(String text) {
mLeftButtonText = text;
return this;
}
DialogBuilder setLeftButtonOnClickListener(Consumer<AlertDialog> listener) {
mLeftButtonOnClickListener = listener;
return this;
}
DialogBuilder setRightButtonText(String text) {
mRightButtonText = text;
return this;
}
DialogBuilder setRightButtonOnClickListener(Consumer<AlertDialog> listener) {
mRightButtonOnClickListener = listener;
return this;
}
AlertDialog build() {
View rootView =
LayoutInflater.from(mContext)
.inflate(R.xml.bluetooth_audio_streams_dialog, /* parent= */ null);
AlertDialog dialog = mBuilder.setView(rootView).setCancelable(false).create();
dialog.setCanceledOnTouchOutside(false);
TextView title = rootView.requireViewById(R.id.dialog_title);
title.setText(mTitle);
if (!Strings.isNullOrEmpty(mSubTitle1)) {
TextView subTitle1 = rootView.requireViewById(R.id.dialog_subtitle);
subTitle1.setText(mSubTitle1);
subTitle1.setVisibility(View.VISIBLE);
}
if (!Strings.isNullOrEmpty(mSubTitle2)) {
TextView subTitle2 = rootView.requireViewById(R.id.dialog_subtitle_2);
subTitle2.setText(mSubTitle2);
subTitle2.setVisibility(View.VISIBLE);
}
if (!Strings.isNullOrEmpty(mLeftButtonText)) {
Button leftButton = rootView.requireViewById(R.id.left_button);
leftButton.setText(mLeftButtonText);
leftButton.setVisibility(View.VISIBLE);
leftButton.setOnClickListener(unused -> mLeftButtonOnClickListener.accept(dialog));
}
if (!Strings.isNullOrEmpty(mRightButtonText)) {
Button rightButton = rootView.requireViewById(R.id.right_button);
rightButton.setText(mRightButtonText);
rightButton.setVisibility(View.VISIBLE);
rightButton.setOnClickListener(
unused -> mRightButtonOnClickListener.accept(dialog));
}
return dialog;
}
}
}

View File

@@ -24,8 +24,10 @@ import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.bluetooth.BluetoothLeBroadcastReceiveState;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.provider.Settings;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -92,6 +94,7 @@ public class AudioStreamsProgressCategoryController extends BasePreferenceContro
new ConcurrentHashMap<>();
private TimedSourceFromQrCode mTimedSourceFromQrCode;
private AudioStreamsProgressCategoryPreference mCategoryPreference;
private AudioStreamsDashboardFragment mFragment;
public AudioStreamsProgressCategoryController(Context context, String preferenceKey) {
super(context, preferenceKey);
@@ -135,10 +138,13 @@ public class AudioStreamsProgressCategoryController extends BasePreferenceContro
mExecutor.execute(this::stopScanning);
}
void setFragment(AudioStreamsDashboardFragment fragment) {
mFragment = fragment;
}
void setSourceFromQrCode(BluetoothLeBroadcastMetadata source) {
mTimedSourceFromQrCode =
new TimedSourceFromQrCode(
mContext, source, () -> handleSourceLost(source.getBroadcastId()));
new TimedSourceFromQrCode(source, () -> handleSourceLost(source.getBroadcastId()));
}
void setScanning(boolean isScanning) {
@@ -324,6 +330,8 @@ public class AudioStreamsProgressCategoryController extends BasePreferenceContro
startScanning();
} else {
stopScanning();
ThreadUtils.postOnMainThread(
() -> AudioStreamsDialogFragment.show(mFragment, getNoLeDeviceDialog()));
}
}
@@ -463,15 +471,41 @@ public class AudioStreamsProgressCategoryController extends BasePreferenceContro
alertDialog.show();
}
private static class TimedSourceFromQrCode {
private AudioStreamsDialogFragment.DialogBuilder getNoLeDeviceDialog() {
return new AudioStreamsDialogFragment.DialogBuilder(mContext)
.setTitle("Connect compatible headphones")
.setSubTitle1(
"To listen to an audio stream, first connect headphones that support LE"
+ " Audio to this device. Learn more")
.setLeftButtonText("Close")
.setLeftButtonOnClickListener(AlertDialog::dismiss)
.setRightButtonText("Connect a device")
.setRightButtonOnClickListener(
unused ->
mContext.startActivity(
new Intent(Settings.ACTION_BLUETOOTH_SETTINGS)));
}
private AudioStreamsDialogFragment.DialogBuilder getBroadcastUnavailableDialog(
String broadcastName) {
return new AudioStreamsDialogFragment.DialogBuilder(mContext)
.setTitle("Audio stream isn't available")
.setSubTitle1(broadcastName)
.setSubTitle2("This audio stream isn't playing anything right now")
.setLeftButtonText("Close")
.setLeftButtonOnClickListener(AlertDialog::dismiss)
.setRightButtonText("Retry")
// TODO(chelseahao): Add retry action
.setRightButtonOnClickListener(AlertDialog::dismiss);
}
private class TimedSourceFromQrCode {
private static final int WAIT_FOR_SYNC_TIMEOUT_MILLIS = 15000;
private final CountDownTimer mTimer;
private BluetoothLeBroadcastMetadata mSourceFromQrCode;
private TimedSourceFromQrCode(
Context context,
BluetoothLeBroadcastMetadata sourceFromQrCode,
Runnable timeoutAction) {
BluetoothLeBroadcastMetadata sourceFromQrCode, Runnable timeoutAction) {
mSourceFromQrCode = sourceFromQrCode;
mTimer =
new CountDownTimer(WAIT_FOR_SYNC_TIMEOUT_MILLIS, 1000) {
@@ -481,7 +515,12 @@ public class AudioStreamsProgressCategoryController extends BasePreferenceContro
@Override
public void onFinish() {
timeoutAction.run();
AudioSharingUtils.toastMessage(context, "Audio steam isn't available");
ThreadUtils.postOnMainThread(
() ->
AudioStreamsDialogFragment.show(
mFragment,
getBroadcastUnavailableDialog(
sourceFromQrCode.getBroadcastName())));
}
};
}