Merge "[Output Switcher] Add switch confirm dialog" into udc-dev
This commit is contained in:
91
packages/SystemUI/res/layout/media_session_end_dialog.xml
Normal file
91
packages/SystemUI/res/layout/media_session_end_dialog.xml
Normal 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>
|
||||
@@ -2684,6 +2684,10 @@
|
||||
<string name="media_output_group_title_speakers_and_displays">Speakers & 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 -->
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user