[Audiosharing] Impl of two error dialogs.
Bug: 305620450 Test: manual Change-Id: I5bd4a4b2ab54c382f325c7a6bb4a3029d47786e0
This commit is contained in:
92
res/xml/bluetooth_audio_streams_dialog.xml
Normal file
92
res/xml/bluetooth_audio_streams_dialog.xml
Normal 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>
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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())));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
Reference in New Issue
Block a user