Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5861d45d authored by shaoweishen's avatar shaoweishen
Browse files

[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
parent 8b0fad3c
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -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<MediaDevice> {
     */
    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
     *
+2 −0
Original line number Diff line number Diff line
@@ -2522,6 +2522,8 @@
    <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>
    <!-- Sub status indicates device need premium account. [CHAR LIMIT=NONE] -->
    <string name="media_output_status_require_premium">Requires premium account</string>

    <!-- Media Output Broadcast Dialog -->
    <!-- Title for Broadcast First Notify Dialog [CHAR LIMIT=60] -->
+31 −0
Original line number Diff line number Diff line
@@ -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 "";
        }
    }
}
+4 −0
Original line number Diff line number Diff line
@@ -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<MediaDevice> getGroupMediaDevices() {
        final List<MediaDevice> selectedDevices = getSelectedMediaDevice();
        final List<MediaDevice> selectableDevices = getSelectableMediaDevice();
+23 −0
Original line number Diff line number Diff line
@@ -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);