Merge "[Output Switcher] Add switch confirm dialog" into udc-dev

This commit is contained in:
Shaowei Shen
2023-05-05 07:44:39 +00:00
committed by Android (Google) Code Review
6 changed files with 226 additions and 0 deletions

View File

@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:id="@+id/end_session_dialog"
android:layout_width="@dimen/large_dialog_width"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/Widget.SliceView.Panel"
android:gravity="center_vertical|center_horizontal"
android:layout_marginTop="@dimen/dialog_top_padding"
android:layout_marginBottom="@dimen/dialog_bottom_padding"
android:orientation="vertical">
<ImageView
android:id="@+id/end_icon"
android:gravity="center_vertical|center_horizontal"
android:layout_width="36dp"
android:layout_height="36dp"
android:importantForAccessibility="no"/>
<TextView
android:id="@+id/end_session_dialog_title"
android:text="@string/media_output_end_session_dialog_summary"
android:layout_marginTop="16dp"
android:layout_marginBottom="@dimen/dialog_side_padding"
android:layout_marginStart="@dimen/dialog_side_padding"
android:layout_marginEnd="@dimen/dialog_bottom_padding"
android:ellipsize="end"
android:gravity="center_vertical|center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?android:attr/textColorPrimary"
android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
android:textSize="24sp"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end|center_vertical"
android:layout_marginTop="8dp"
android:layout_marginStart="@dimen/dialog_side_padding"
android:layout_marginEnd="@dimen/dialog_side_padding"
android:layout_marginBottom="@dimen/dialog_bottom_padding"
android:orientation="horizontal">
<Button
android:id="@+id/cancel_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:text="@string/cancel"
android:ellipsize="end"
android:layout_gravity="end|center_vertical"
android:singleLine="true"
style="@style/Widget.Dialog.Button.BorderButton"
android:clickable="true"
android:focusable="true"/>
<Button
android:id="@+id/stop_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:text="@string/media_output_end_session_dialog_stop"
style="@style/Widget.Dialog.Button"
android:singleLine="true"
android:ellipsize="end"
android:clickable="true"
android:focusable="true"/>
</LinearLayout>
</LinearLayout>

View File

@@ -2684,6 +2684,10 @@
<string name="media_output_group_title_speakers_and_displays">Speakers &amp; Displays</string>
<!-- Title for Suggested Devices group. [CHAR LIMIT=NONE] -->
<string name="media_output_group_title_suggested_device">Suggested Devices</string>
<!-- Summary for end session dialog. [CHAR LIMIT=NONE] -->
<string name="media_output_end_session_dialog_summary">Stop your shared session to move media to another device</string>
<!-- Button text for stopping session [CHAR LIMIT=60] -->
<string name="media_output_end_session_dialog_stop">Stop</string>
<!-- Media Output Broadcast Dialog -->

View File

@@ -37,6 +37,7 @@ import androidx.annotation.RequiresApi;
import androidx.core.widget.CompoundButtonCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.media.LocalMediaManager.MediaDeviceState;
import com.android.settingslib.media.MediaDevice;
import com.android.systemui.R;
@@ -482,6 +483,14 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
}
private void onItemClick(View view, MediaDevice device) {
if (mController.isCurrentOutputDeviceHasSessionOngoing()) {
showCustomEndSessionDialog(device);
} else {
transferOutput(device);
}
}
private void transferOutput(MediaDevice device) {
if (mController.isAnyDeviceTransferring()) {
return;
}
@@ -496,6 +505,14 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
notifyDataSetChanged();
}
@VisibleForTesting
void showCustomEndSessionDialog(MediaDevice device) {
MediaSessionReleaseDialog mediaSessionReleaseDialog = new MediaSessionReleaseDialog(
mContext, () -> transferOutput(device), mController.getColorButtonBackground(),
mController.getColorItemContent());
mediaSessionReleaseDialog.show();
}
private void cancelMuteAwaitConnection() {
mController.cancelMuteAwaitConnection();
notifyDataSetChanged();

View File

@@ -783,6 +783,12 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
currentConnectedMediaDevice);
}
boolean isCurrentOutputDeviceHasSessionOngoing() {
MediaDevice currentConnectedMediaDevice = getCurrentConnectedMediaDevice();
return currentConnectedMediaDevice != null
&& (currentConnectedMediaDevice.isHostForOngoingSession());
}
public boolean isAdvancedLayoutSupported() {
return mFeatureFlags.isEnabled(Flags.OUTPUT_SWITCHER_ADVANCED_LAYOUT);
}

View File

@@ -0,0 +1,89 @@
/*
* 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.systemui.media.dialog;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.ColorFilter;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.SystemUIDialog;
/**
* Confirmation dialog for releasing media session
*/
public class MediaSessionReleaseDialog extends SystemUIDialog {
private View mDialogView;
private final Context mContext;
private final View.OnClickListener mPositiveButtonListener;
private final ColorFilter mButtonColorFilter;
private final int mIconColor;
public MediaSessionReleaseDialog(Context context, Runnable runnable, int buttonColor,
int iconColor) {
super(context, R.style.Theme_SystemUI_Dialog_Media);
mContext = getContext();
mPositiveButtonListener = (v) -> {
runnable.run();
dismiss();
};
mButtonColorFilter = new PorterDuffColorFilter(
buttonColor,
PorterDuff.Mode.SRC_IN);
mIconColor = iconColor;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDialogView = LayoutInflater.from(mContext).inflate(R.layout.media_session_end_dialog,
null);
final Window window = getWindow();
window.setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL);
window.setContentView(mDialogView);
final WindowManager.LayoutParams lp = window.getAttributes();
lp.gravity = Gravity.CENTER;
lp.width = (int) (mContext.getResources().getDisplayMetrics().widthPixels * 0.90);
ImageView headerIcon = mDialogView.requireViewById(R.id.end_icon);
headerIcon.setImageDrawable(mContext.getDrawable(R.drawable.media_output_status_failed));
headerIcon.setImageTintList(
ColorStateList.valueOf(mIconColor));
Button stopButton = mDialogView.requireViewById(R.id.stop_button);
stopButton.setOnClickListener(mPositiveButtonListener);
stopButton.getBackground().setColorFilter(mButtonColorFilter);
Button cancelButton = mDialogView.requireViewById(R.id.cancel_button);
cancelButton.setOnClickListener((v) -> dismiss());
cancelButton.getBackground().setColorFilter(mButtonColorFilter);
}
}

View File

@@ -26,6 +26,7 @@ import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECT
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -34,6 +35,7 @@ import android.app.WallpaperColors;
import android.graphics.Bitmap;
import android.graphics.drawable.Icon;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.SeekBar;
@@ -60,6 +62,7 @@ import java.util.stream.Collectors;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class MediaOutputAdapterTest extends SysuiTestCase {
private static final String TEST_DEVICE_NAME_1 = "test_device_name_1";
@@ -613,6 +616,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
@Test
public void onItemClick_clickDevice_verifyConnectDevice() {
when(mMediaOutputController.isCurrentOutputDeviceHasSessionOngoing()).thenReturn(false);
assertThat(mMediaDevice2.getState()).isEqualTo(
LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -622,6 +626,21 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
verify(mMediaOutputController).connectDevice(mMediaDevice2);
}
@Test
public void onItemClick_clickDeviceWithSessionOngoing_verifyShowsDialog() {
when(mMediaOutputController.isCurrentOutputDeviceHasSessionOngoing()).thenReturn(true);
assertThat(mMediaDevice2.getState()).isEqualTo(
LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED);
MediaOutputAdapter.MediaDeviceViewHolder spyMediaDeviceViewHolder = spy(mViewHolder);
mMediaOutputAdapter.onBindViewHolder(spyMediaDeviceViewHolder, 0);
mMediaOutputAdapter.onBindViewHolder(spyMediaDeviceViewHolder, 1);
spyMediaDeviceViewHolder.mContainerLayout.performClick();
verify(mMediaOutputController, never()).connectDevice(mMediaDevice2);
verify(spyMediaDeviceViewHolder).showCustomEndSessionDialog(mMediaDevice2);
}
@Test
public void onItemClick_clicksWithMutingExpectedDeviceExist_cancelsMuteAwaitConnection() {
when(mMediaOutputController.isAnyDeviceTransferring()).thenReturn(false);