From 5861d45dba665f57fdcec33ec75f24187a901364 Mon Sep 17 00:00:00 2001 From: shaoweishen Date: Thu, 5 Jan 2023 11:13:01 +0000 Subject: [PATCH] [Output Switcher] Add support for device disabled reason Implement support in MediaDevice for device status, which used for showing under subtext. When dsiabled reason exist, Output Switcher should disable the device and show corresponded reason in subtext. Test: atest MediaOutputAdapterTest MediaOutputControllerTest MediaOutputBaseDialogTest MediaOutputDialogTest Bug:260021954 Change-Id: Ia6e8fd4f7ca066e85c4afcc688ff1875c9e60964 --- .../settingslib/media/MediaDevice.java | 22 +++++++++++++ packages/SystemUI/res/values/strings.xml | 2 ++ .../media/dialog/MediaOutputAdapter.java | 31 +++++++++++++++++++ .../media/dialog/MediaOutputController.java | 4 +++ .../media/dialog/MediaOutputAdapterTest.java | 23 ++++++++++++++ 5 files changed, 82 insertions(+) diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java index b73e7a3628db1..d708e577b68eb 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java @@ -30,6 +30,7 @@ import static android.media.MediaRoute2Info.TYPE_USB_DEVICE; import static android.media.MediaRoute2Info.TYPE_USB_HEADSET; import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES; import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET; +import static android.media.RouteListingPreference.Item.DISABLE_REASON_NONE; import static android.media.RouteListingPreference.Item.FLAG_SUGGESTED_ROUTE; import static com.android.settingslib.media.LocalMediaManager.MediaDeviceState.STATE_SELECTED; @@ -192,6 +193,27 @@ public abstract class MediaDevice implements Comparable { */ public abstract String getId(); + /** + * Get disabled reason of device + * + * @return disabled reason of device + */ + @RouteListingPreference.Item.DisableReason + public int getDisableReason() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE && mItem != null + ? mItem.getDisableReason() : -1; + } + + /** + * Checks if device is has disabled reason + * + * @return true if device has disabled reason + */ + public boolean hasDisabledReason() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE && mItem != null + && mItem.getDisableReason() != DISABLE_REASON_NONE; + } + /** * Checks if device is suggested device from application * diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index e4f339af9bcb7..626d3b92d40a2 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2522,6 +2522,8 @@ Speakers & Displays Suggested Devices + + Requires premium account 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 51b5a3d1a08c0..d6c6a81fbfc0f 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java @@ -16,17 +16,24 @@ package com.android.systemui.media.dialog; +import static android.media.RouteListingPreference.Item.DISABLE_REASON_SUBSCRIPTION_REQUIRED; + +import android.content.Context; import android.content.res.ColorStateList; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; +import android.media.RouteListingPreference; +import android.os.Build; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.CheckBox; import android.widget.TextView; +import androidx.annotation.DoNotInline; import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; import androidx.core.widget.CompoundButtonCompat; import androidx.recyclerview.widget.RecyclerView; @@ -186,6 +193,17 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter { mCurrentActivePosition = position; updateFullItemClickListener(v -> onItemClick(v, device)); setSingleLineLayout(getItemTitle(device)); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU + && mController.isSubStatusSupported() && device.hasDisabledReason()) { + //update to subtext with device status + setUpDeviceIcon(device); + mSubTitleText.setText( + Api34Impl.composeDisabledReason(device.getDisableReason(), mContext)); + updateConnectionFailedStatusIcon(); + updateFullItemClickListener(null); + setTwoLineLayout(device, false /* bFocused */, false /* showSeekBar */, + false /* showProgressBar */, true /* showSubtitle */, + true /* showStatus */); } else if (device.getState() == MediaDeviceState.STATE_CONNECTING_FAILED) { setUpDeviceIcon(device); updateConnectionFailedStatusIcon(); @@ -389,4 +407,17 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter { mTitleText.setText(groupDividerTitle); } } + + @RequiresApi(34) + private static class Api34Impl { + @DoNotInline + static String composeDisabledReason(@RouteListingPreference.Item.DisableReason int reason, + Context context) { + switch(reason) { + case DISABLE_REASON_SUBSCRIPTION_REQUIRED: + return context.getString(R.string.media_output_status_require_premium); + } + return ""; + } + } } 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 7bc0c0cc614ba..5b137e91f9e7b 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java @@ -748,6 +748,10 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, return mFeatureFlags.isEnabled(Flags.OUTPUT_SWITCHER_ROUTES_PROCESSING); } + public boolean isSubStatusSupported() { + return mFeatureFlags.isEnabled(Flags.OUTPUT_SWITCHER_DEVICE_STATUS); + } + List getGroupMediaDevices() { final List selectedDevices = getSelectedMediaDevice(); final List selectableDevices = getSelectableMediaDevice(); 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 7c3c9d2a1bb18..77daa3f1c2072 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 @@ -16,6 +16,8 @@ package com.android.systemui.media.dialog; +import static android.media.RouteListingPreference.Item.DISABLE_REASON_SUBSCRIPTION_REQUIRED; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.mock; @@ -57,6 +59,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase { private static final String TEST_DEVICE_ID_1 = "test_device_id_1"; private static final String TEST_DEVICE_ID_2 = "test_device_id_2"; private static final String TEST_SESSION_NAME = "test_session_name"; + private static final int TEST_MAX_VOLUME = 20; private static final int TEST_CURRENT_VOLUME = 10; @@ -78,6 +81,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase { @Before public void setUp() { when(mMediaOutputController.isAdvancedLayoutSupported()).thenReturn(false); + when(mMediaOutputController.isSubStatusSupported()).thenReturn(false); when(mMediaOutputController.getMediaItemList()).thenReturn(mMediaItems); when(mMediaOutputController.getMediaDevices()).thenReturn(mMediaDevices); when(mMediaOutputController.hasAdjustVolumeUserRestriction()).thenReturn(false); @@ -403,6 +407,25 @@ public class MediaOutputAdapterTest extends SysuiTestCase { assertThat(mViewHolder.mTwoLineTitleText.getText()).isEqualTo(TEST_DEVICE_NAME_2); } + @Test + public void subStatusSupported_onBindViewHolder_bindFailedStateDevice_verifyView() { + String deviceStatus = (String) mContext.getText( + R.string.media_output_status_require_premium); + when(mMediaOutputController.isSubStatusSupported()).thenReturn(true); + when(mMediaDevice2.hasDisabledReason()).thenReturn(true); + when(mMediaDevice2.getDisableReason()).thenReturn(DISABLE_REASON_SUBSCRIPTION_REQUIRED); + mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1); + + assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mViewHolder.mSubTitleText.getText()).isEqualTo(deviceStatus); + assertThat(mViewHolder.mTwoLineTitleText.getText()).isEqualTo(TEST_DEVICE_NAME_2); + } + @Test public void onBindViewHolder_inTransferring_bindTransferringDevice_verifyView() { when(mMediaOutputController.isAnyDeviceTransferring()).thenReturn(true);