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

Commit fa21cfd6 authored by Shaowei Shen's avatar Shaowei Shen Committed by Android (Google) Code Review
Browse files

Merge "[Output Switcher] Add suport for subtext and ongoing session"

parents 2c291d6b 72dc3726
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -1315,6 +1315,13 @@
    <string name="media_transfer_this_device_name" product="tablet">This tablet</string>
    <!-- Name of the phone device with an active remote session. [CHAR LIMIT=30] -->
    <string name="media_transfer_this_phone">This phone</string>
    <!-- Sub status indicates device need premium account. [CHAR LIMIT=NONE] -->
    <string name="media_output_status_require_premium">Upgrade account to switch</string>
    <!-- Sub status indicates device not support download content. [CHAR LIMIT=NONE] -->
    <string name="media_output_status_not_support_downloads">Can\’t play downloads here</string>
    <!-- Sub status indicates device need to wait after ad. [CHAR LIMIT=NONE] -->
    <string name="media_output_status_try_after_ad">Try again after the ad</string>


    <!-- Warning message to tell user is have problem during profile connect, it need to turn off device and back on. [CHAR_LIMIT=NONE] -->
    <string name="profile_connect_timeout_subtext">Problem connecting. Turn device off &amp; back on</string>
+20 −0
Original line number Diff line number Diff line
@@ -34,10 +34,12 @@ import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR;

import static com.android.settingslib.media.LocalMediaManager.MediaDeviceState.STATE_SELECTED;

import android.annotation.Nullable;
import android.annotation.TargetApi;
import android.app.Notification;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.ComponentName;
import android.content.Context;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
@@ -191,6 +193,14 @@ public class InfoMediaManager extends MediaManager {
                && Api34Impl.preferRouteListingOrdering(mRouterManager, mPackageName);
    }

    @Nullable
    ComponentName getLinkedItemComponentName() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
            return null;
        }
        return Api34Impl.getLinkedItemComponentName(mRouterManager, mPackageName);
    }

    /**
     * Remove a {@code device} from current media.
     *
@@ -681,6 +691,16 @@ public class InfoMediaManager extends MediaManager {
                    && !routeListingPreference.getUseSystemOrdering();
        }

        @DoNotInline
        @Nullable
        static ComponentName getLinkedItemComponentName(
                MediaRouter2Manager mediaRouter2Manager, String packageName) {
            RouteListingPreference routeListingPreference =
                    mediaRouter2Manager.getRouteListingPreference(packageName);
            return routeListingPreference == null ? null
                    : routeListingPreference.getLinkedItemComponentName();
        }

        @DoNotInline
        static void onRouteListingPreferenceUpdated(
                String packageName,
+11 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR;
import android.app.Notification;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.ComponentName;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
@@ -216,6 +217,16 @@ public class LocalMediaManager implements BluetoothCallback {
        return mInfoMediaManager.preferRouteListingOrdering();
    }

    /**
     * Returns required component name for system to take the user back to the app by launching an
     * intent with the returned {@link ComponentName}, using action {@link #ACTION_TRANSFER_MEDIA},
     * with the extra {@link #EXTRA_ROUTE_ID}.
     */
    @Nullable
    public ComponentName getLinkedItemComponentName() {
        return mInfoMediaManager.getLinkedItemComponentName();
    }

    /**
     * Start scan connected MediaDevice
     */
+67 −9
Original line number Diff line number Diff line
@@ -30,8 +30,14 @@ 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.FLAG_ONGOING_SESSION;
import static android.media.RouteListingPreference.Item.FLAG_SUGGESTED_ROUTE;
import static android.media.RouteListingPreference.Item.SELECTION_BEHAVIOR_NONE;
import static android.media.RouteListingPreference.Item.SUBTEXT_AD_ROUTING_DISALLOWED;
import static android.media.RouteListingPreference.Item.SUBTEXT_CUSTOM;
import static android.media.RouteListingPreference.Item.SUBTEXT_DOWNLOADED_CONTENT_ROUTING_DISALLOWED;
import static android.media.RouteListingPreference.Item.SUBTEXT_NONE;
import static android.media.RouteListingPreference.Item.SUBTEXT_SUBSCRIPTION_REQUIRED;

import static com.android.settingslib.media.LocalMediaManager.MediaDeviceState.STATE_SELECTED;

@@ -51,6 +57,8 @@ import androidx.annotation.IntDef;
import androidx.annotation.RequiresApi;
import androidx.annotation.VisibleForTesting;

import com.android.settingslib.R;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -194,28 +202,58 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {
    public abstract String getId();

    /**
     * Get disabled reason of device
     * Get selection behavior of device
     *
     * @return disabled reason of device
     * @return selection behavior of device
     */
    @RouteListingPreference.Item.SubText
    public int getDisableReason() {
    public int getSelectionBehavior() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE && mItem != null
                ? mItem.getSubText()
                : -1;
                ? mItem.getSelectionBehavior() : SELECTION_BEHAVIOR_NONE;
    }

    /**
     * Checks if device is has disabled reason
     * Checks if device is has subtext
     *
     * @return true if device has disabled reason
     * @return true if device has subtext
     */
    public boolean hasDisabledReason() {
    public boolean hasSubtext() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
                && mItem != null
                && mItem.getSubText() != SUBTEXT_NONE;
    }

    /**
     * Get subtext of device
     *
     * @return subtext of device
     */
    @RouteListingPreference.Item.SubText
    public int getSubtext() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE && mItem != null
                ? mItem.getSubText() : SUBTEXT_NONE;
    }

    /**
     * Returns subtext string for current route.
     *
     * @return subtext string for this route
     */
    public String getSubtextString() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE && mItem != null
                ? Api34Impl.composeSubtext(mItem, mContext) : null;
    }

    /**
     * Checks if device has ongoing shared session, which allow user to join
     *
     * @return true if device has ongoing session
     */
    public boolean hasOngoingSession() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
                && Api34Impl.hasOngoingSession(mItem);
    }

    /**
     * Checks if device is suggested device from application
     *
@@ -513,7 +551,27 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {
    private static class Api34Impl {
        @DoNotInline
        static boolean isSuggestedDevice(RouteListingPreference.Item item) {
            return item != null && item.getFlags() == FLAG_SUGGESTED_ROUTE;
            return item != null && (item.getFlags() & FLAG_SUGGESTED_ROUTE) != 0;
        }

        @DoNotInline
        static boolean hasOngoingSession(RouteListingPreference.Item item) {
            return item != null && (item.getFlags() & FLAG_ONGOING_SESSION) != 0;
        }

        @DoNotInline
        static String composeSubtext(RouteListingPreference.Item item, Context context) {
            switch (item.getSubText()) {
                case SUBTEXT_SUBSCRIPTION_REQUIRED:
                    return context.getString(R.string.media_output_status_require_premium);
                case SUBTEXT_DOWNLOADED_CONTENT_ROUTING_DISALLOWED:
                    return context.getString(R.string.media_output_status_not_support_downloads);
                case SUBTEXT_AD_ROUTING_DISALLOWED:
                    return context.getString(R.string.media_output_status_try_after_ad);
                case SUBTEXT_CUSTOM:
                    return (String) item.getCustomSubtextMessage();
            }
            return "";
        }
    }
}
+21 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.bluetooth.BluetoothDevice;
import android.content.ComponentName;
import android.content.Context;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
@@ -88,6 +89,8 @@ public class InfoMediaManagerTest {
    private MediaManager.MediaDeviceCallback mCallback;
    @Mock
    private MediaSessionManager mMediaSessionManager;
    @Mock
    private ComponentName mComponentName;

    private InfoMediaManager mInfoMediaManager;
    private Context mContext;
@@ -372,6 +375,24 @@ public class InfoMediaManagerTest {
        assertThat(mInfoMediaManager.preferRouteListingOrdering()).isFalse();
    }

    @Test
    public void getInAppOnlyItemRoutingReceiver_oldSdkVersion_returnsNull() {
        assertThat(mInfoMediaManager.getLinkedItemComponentName()).isNull();
    }

    @Test
    public void getInAppOnlyItemRoutingReceiver_newSdkVersionWithReceiverExist_returns() {
        ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT",
                Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
        when(mRouterManager.getRouteListingPreference(any())).thenReturn(
                new RouteListingPreference.Builder().setItems(
                        ImmutableList.of()).setUseSystemOrdering(
                        false).setLinkedItemComponentName(mComponentName).build());
        mInfoMediaManager.mRouterManager = mRouterManager;

        assertThat(mInfoMediaManager.getLinkedItemComponentName()).isEqualTo(mComponentName);
    }

    private List<MediaRoute2Info> getRoutesListWithDuplicatedIds() {
        final List<MediaRoute2Info> routes = new ArrayList<>();
        final MediaRoute2Info info = mock(MediaRoute2Info.class);
Loading