diff options
| author | 2023-05-05 09:21:12 +0000 | |
|---|---|---|
| committer | 2023-05-05 09:21:12 +0000 | |
| commit | d850b7714c8c126f65cdf6813b97fa34b51b1fbd (patch) | |
| tree | 2bdf429cfeac1e7af69d0444837d79dfc680c071 | |
| parent | a07b2f67144d4b107b792a851daed50b3e7784cb (diff) | |
| parent | a937b49da161c7d6dc1dd69ecc64e216235643dd (diff) | |
Merge "[Output Switcher] Add switch confirm dialog" into udc-dev am: b875795205 am: a937b49da1
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/22952407
Change-Id: Iba80983ab17089e39a4c3c4157a30e06219fafa1
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
6 files changed, 226 insertions, 0 deletions
diff --git a/packages/SystemUI/res/layout/media_session_end_dialog.xml b/packages/SystemUI/res/layout/media_session_end_dialog.xml new file mode 100644 index 000000000000..e1050f65d47a --- /dev/null +++ b/packages/SystemUI/res/layout/media_session_end_dialog.xml @@ -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> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index c57fef1c52f7..70fdc2070b7a 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -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 --> diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java index f50a7a854169..d46e6b996fa4 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java @@ -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(); diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java index 8e014c61c641..822644b8e573 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java @@ -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); } diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSessionReleaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSessionReleaseDialog.java new file mode 100644 index 000000000000..2680a2ff4567 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSessionReleaseDialog.java @@ -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); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java index 7f7952feb10b..17d2f7bedf30 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java @@ -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); @@ -623,6 +627,21 @@ public class MediaOutputAdapterTest extends SysuiTestCase { } @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); when(mMediaOutputController.hasMutingExpectedDevice()).thenReturn(true); |