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

Commit 338bb0d7 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "MediaRouter: Add missing info to MediaRoute2Info"

parents c169faaa 3aeabe0e
Loading
Loading
Loading
Loading
+180 −1
Original line number Diff line number Diff line
@@ -16,13 +16,17 @@

package android.media;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -46,6 +50,34 @@ public final class MediaRoute2Info implements Parcelable {
        }
    };

    /** @hide */
    @IntDef({CONNECTION_STATE_DISCONNECTED, CONNECTION_STATE_CONNECTING,
            CONNECTION_STATE_CONNECTED})
    @Retention(RetentionPolicy.SOURCE)
    private @interface ConnectionState {}

    /**
     * The default connection state indicating the route is disconnected.
     *
     * @see #getConnectionState
     */
    public static final int CONNECTION_STATE_DISCONNECTED = 0;

    /**
     * A connection state indicating the route is in the process of connecting and is not yet
     * ready for use.
     *
     * @see #getConnectionState
     */
    public static final int CONNECTION_STATE_CONNECTING = 1;

    /**
     * A connection state indicating the route is connected.
     *
     * @see #getConnectionState
     */
    public static final int CONNECTION_STATE_CONNECTED = 2;

    /**
     * Playback information indicating the playback volume is fixed, i.e. it cannot be
     * controlled from this object. An example of fixed playback volume is a remote player,
@@ -61,6 +93,46 @@ public final class MediaRoute2Info implements Parcelable {
     */
    public static final int PLAYBACK_VOLUME_VARIABLE = 1;

    /** @hide */
    @IntDef({
            DEVICE_TYPE_UNKNOWN, DEVICE_TYPE_TV,
            DEVICE_TYPE_SPEAKER, DEVICE_TYPE_BLUETOOTH})
    @Retention(RetentionPolicy.SOURCE)
    private @interface DeviceType {}

    /**
     * The default receiver device type of the route indicating the type is unknown.
     *
     * @see #getDeviceType
     * @hide
     */
    public static final int DEVICE_TYPE_UNKNOWN = 0;

    /**
     * A receiver device type of the route indicating the presentation of the media is happening
     * on a TV.
     *
     * @see #getDeviceType
     */
    public static final int DEVICE_TYPE_TV = 1;

    /**
     * A receiver device type of the route indicating the presentation of the media is happening
     * on a speaker.
     *
     * @see #getDeviceType
     */
    public static final int DEVICE_TYPE_SPEAKER = 2;

    /**
     * A receiver device type of the route indicating the presentation of the media is happening
     * on a bluetooth device such as a bluetooth speaker.
     *
     * @see #getDeviceType
     * @hide
     */
    public static final int DEVICE_TYPE_BLUETOOTH = 3;

    @NonNull
    final String mId;
    @Nullable
@@ -70,12 +142,17 @@ public final class MediaRoute2Info implements Parcelable {
    @Nullable
    final CharSequence mDescription;
    @Nullable
    final @ConnectionState int mConnectionState;
    @Nullable
    final Uri mIconUri;
    @Nullable
    final String mClientPackageName;
    @NonNull
    final List<String> mSupportedCategories;
    final int mVolume;
    final int mVolumeMax;
    final int mVolumeHandling;
    final @DeviceType int mDeviceType;
    @Nullable
    final Bundle mExtras;

@@ -86,11 +163,14 @@ public final class MediaRoute2Info implements Parcelable {
        mProviderId = builder.mProviderId;
        mName = builder.mName;
        mDescription = builder.mDescription;
        mConnectionState = builder.mConnectionState;
        mIconUri = builder.mIconUri;
        mClientPackageName = builder.mClientPackageName;
        mSupportedCategories = builder.mSupportedCategories;
        mVolume = builder.mVolume;
        mVolumeMax = builder.mVolumeMax;
        mVolumeHandling = builder.mVolumeHandling;
        mDeviceType = builder.mDeviceType;
        mExtras = builder.mExtras;
        mUniqueId = createUniqueId();
    }
@@ -100,11 +180,14 @@ public final class MediaRoute2Info implements Parcelable {
        mProviderId = in.readString();
        mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
        mDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
        mConnectionState = in.readInt();
        mIconUri = in.readParcelable(null);
        mClientPackageName = in.readString();
        mSupportedCategories = in.createStringArrayList();
        mVolume = in.readInt();
        mVolumeMax = in.readInt();
        mVolumeHandling = in.readInt();
        mDeviceType = in.readInt();
        mExtras = in.readBundle();
        mUniqueId = createUniqueId();
    }
@@ -145,18 +228,22 @@ public final class MediaRoute2Info implements Parcelable {
                && Objects.equals(mProviderId, other.mProviderId)
                && Objects.equals(mName, other.mName)
                && Objects.equals(mDescription, other.mDescription)
                && (mConnectionState == other.mConnectionState)
                && Objects.equals(mIconUri, other.mIconUri)
                && Objects.equals(mClientPackageName, other.mClientPackageName)
                && Objects.equals(mSupportedCategories, other.mSupportedCategories)
                && (mVolume == other.mVolume)
                && (mVolumeMax == other.mVolumeMax)
                && (mVolumeHandling == other.mVolumeHandling)
                && (mDeviceType == other.mDeviceType)
                //TODO: This will be evaluated as false in most cases. Try not to.
                && Objects.equals(mExtras, other.mExtras);
    }

    @Override
    public int hashCode() {
        return Objects.hash(mId, mName, mDescription, mSupportedCategories);
        return Objects.hash(mId, mName, mDescription, mConnectionState, mIconUri,
                mSupportedCategories, mVolume, mVolumeMax, mVolumeHandling, mDeviceType);
    }

    /**
@@ -203,6 +290,29 @@ public final class MediaRoute2Info implements Parcelable {
        return mDescription;
    }

    /**
     * Gets the connection state of the route.
     *
     * @return The connection state of this route: {@link #CONNECTION_STATE_DISCONNECTED},
     * {@link #CONNECTION_STATE_CONNECTING}, or {@link #CONNECTION_STATE_CONNECTED}.
     */
    @ConnectionState
    public int getConnectionState() {
        return mConnectionState;
    }

    /**
     * Gets the URI of the icon representing this route.
     * <p>
     * This icon will be used in picker UIs if available.
     *
     * @return The URI of the icon representing this route, or null if none.
     */
    @Nullable
    public Uri getIconUri() {
        return mIconUri;
    }

    /**
     * Gets the package name of the client that uses the route.
     * Returns null if no clients use this.
@@ -221,6 +331,18 @@ public final class MediaRoute2Info implements Parcelable {
        return mSupportedCategories;
    }

    //TODO: once device types are confirmed, reflect those into the comment.
    /**
     * Gets the type of the receiver device associated with this route.
     *
     * @return The type of the receiver device associated with this route:
     * {@link #DEVICE_TYPE_TV} or {@link #DEVICE_TYPE_SPEAKER}.
     */
    @DeviceType
    public int getDeviceType() {
        return mDeviceType;
    }

    /**
     * Gets the current volume of the route. This may be invalid if the route is not selected.
     */
@@ -293,11 +415,14 @@ public final class MediaRoute2Info implements Parcelable {
        dest.writeString(mProviderId);
        TextUtils.writeToParcel(mName, dest, flags);
        TextUtils.writeToParcel(mDescription, dest, flags);
        dest.writeInt(mConnectionState);
        dest.writeParcelable(mIconUri, flags);
        dest.writeString(mClientPackageName);
        dest.writeStringList(mSupportedCategories);
        dest.writeInt(mVolume);
        dest.writeInt(mVolumeMax);
        dest.writeInt(mVolumeHandling);
        dest.writeInt(mDeviceType);
        dest.writeBundle(mExtras);
    }

@@ -308,9 +433,12 @@ public final class MediaRoute2Info implements Parcelable {
                .append("id=").append(getId())
                .append(", name=").append(getName())
                .append(", description=").append(getDescription())
                .append(", connectionState=").append(getConnectionState())
                .append(", iconUri=").append(getIconUri())
                .append(", volume=").append(getVolume())
                .append(", volumeMax=").append(getVolumeMax())
                .append(", volumeHandling=").append(getVolumeHandling())
                .append(", deviceType=").append(getDeviceType())
                .append(", providerId=").append(getProviderId())
                .append(" }");
        return result.toString();
@@ -324,11 +452,16 @@ public final class MediaRoute2Info implements Parcelable {
        String mProviderId;
        CharSequence mName;
        CharSequence mDescription;
        @ConnectionState
        int mConnectionState;
        Uri mIconUri;
        String mClientPackageName;
        List<String> mSupportedCategories;
        int mVolume;
        int mVolumeMax;
        int mVolumeHandling = PLAYBACK_VOLUME_FIXED;
        @DeviceType
        int mDeviceType = DEVICE_TYPE_UNKNOWN;
        Bundle mExtras;

        public Builder(@NonNull String id, @NonNull CharSequence name) {
@@ -348,11 +481,14 @@ public final class MediaRoute2Info implements Parcelable {
            }
            setName(routeInfo.mName);
            mDescription = routeInfo.mDescription;
            mConnectionState = routeInfo.mConnectionState;
            mIconUri = routeInfo.mIconUri;
            setClientPackageName(routeInfo.mClientPackageName);
            setSupportedCategories(routeInfo.mSupportedCategories);
            setVolume(routeInfo.mVolume);
            setVolumeMax(routeInfo.mVolumeMax);
            setVolumeHandling(routeInfo.mVolumeHandling);
            setDeviceType(routeInfo.mDeviceType);
            if (routeInfo.mExtras != null) {
                mExtras = new Bundle(routeInfo.mExtras);
            }
@@ -402,6 +538,39 @@ public final class MediaRoute2Info implements Parcelable {
            return this;
        }

        /**
        * Sets the route's connection state.
        *
        * {@link #CONNECTION_STATE_DISCONNECTED},
        * {@link #CONNECTION_STATE_CONNECTING}, or
        * {@link #CONNECTION_STATE_CONNECTED}.
        */
        @NonNull
        public Builder setConnectionState(@ConnectionState int connectionState) {
            mConnectionState = connectionState;
            return this;
        }

        /**
         * Sets the URI of the icon representing this route.
         * <p>
         * This icon will be used in picker UIs if available.
         * </p><p>
         * The URI must be one of the following formats:
         * <ul>
         * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
         * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
         * </li>
         * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
         * </ul>
         * </p>
         */
        @NonNull
        public Builder setIconUri(@Nullable Uri iconUri) {
            mIconUri = iconUri;
            return this;
        }

        /**
         * Sets the package name of the app using the route.
         */
@@ -470,6 +639,16 @@ public final class MediaRoute2Info implements Parcelable {
            mVolumeHandling = volumeHandling;
            return this;
        }

        /**
         * Sets the route's device type.
         */
        @NonNull
        public Builder setDeviceType(@DeviceType int deviceType) {
            mDeviceType = deviceType;
            return this;
        }

        /**
         * Sets a bundle of extras for the route.
         */
+7 −1
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package com.android.mediarouteprovider.example;

import static android.media.MediaRoute2Info.DEVICE_TYPE_SPEAKER;
import static android.media.MediaRoute2Info.DEVICE_TYPE_TV;

import android.content.Intent;
import android.media.MediaRoute2Info;
import android.media.MediaRoute2ProviderInfo;
@@ -57,9 +60,11 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
    private void initializeRoutes() {
        MediaRoute2Info route1 = new MediaRoute2Info.Builder(ROUTE_ID1, ROUTE_NAME1)
                .addSupportedCategory(CATEGORY_SAMPLE)
                .setDeviceType(DEVICE_TYPE_TV)
                .build();
        MediaRoute2Info route2 = new MediaRoute2Info.Builder(ROUTE_ID2, ROUTE_NAME2)
                .addSupportedCategory(CATEGORY_SAMPLE)
                .setDeviceType(DEVICE_TYPE_SPEAKER)
                .build();
        MediaRoute2Info routeSpecial =
                new MediaRoute2Info.Builder(ROUTE_ID_SPECIAL_CATEGORY, ROUTE_NAME_SPECIAL_CATEGORY)
@@ -123,7 +128,8 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService

    @Override
    public void onControlRequest(String routeId, Intent request) {
        if (ACTION_REMOVE_ROUTE.equals(request.getAction())) {
        String action = request.getAction();
        if (ACTION_REMOVE_ROUTE.equals(action)) {
            MediaRoute2Info route = mRoutes.get(routeId);
            if (route != null) {
                mRoutes.remove(routeId);
+96 −0
Original line number Diff line number Diff line
@@ -16,19 +16,31 @@

package com.android.mediaroutertest;

import static android.media.MediaRoute2Info.CONNECTION_STATE_CONNECTED;
import static android.media.MediaRoute2Info.CONNECTION_STATE_CONNECTING;
import static android.media.MediaRoute2Info.DEVICE_TYPE_SPEAKER;
import static android.media.MediaRoute2Info.DEVICE_TYPE_TV;
import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_FIXED;
import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE;

import static com.android.mediaroutertest.MediaRouterManagerTest.CATEGORIES_ALL;
import static com.android.mediaroutertest.MediaRouterManagerTest.CATEGORIES_SPECIAL;
import static com.android.mediaroutertest.MediaRouterManagerTest.CATEGORY_SAMPLE;
import static com.android.mediaroutertest.MediaRouterManagerTest.CATEGORY_SPECIAL;
import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID_SPECIAL_CATEGORY;
import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID_VARIABLE_VOLUME;
import static com.android.mediaroutertest.MediaRouterManagerTest.SYSTEM_PROVIDER_ID;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import android.content.Context;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2;
import android.net.Uri;
import android.os.Parcel;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -87,6 +99,90 @@ public class MediaRouter2Test {
        assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
    }

    @Test
    public void testRouteInfoEquality() {
        MediaRoute2Info routeInfo = new MediaRoute2Info.Builder("id", "name")
                .setDescription("description")
                .setClientPackageName("com.android.mediaroutertest")
                .setConnectionState(CONNECTION_STATE_CONNECTING)
                .setIconUri(new Uri.Builder().path("icon").build())
                .setVolume(5)
                .setVolumeMax(20)
                .addSupportedCategory(CATEGORY_SAMPLE)
                .setVolumeHandling(PLAYBACK_VOLUME_VARIABLE)
                .setDeviceType(DEVICE_TYPE_SPEAKER)
                .build();

        MediaRoute2Info routeInfoRebuilt = new MediaRoute2Info.Builder(routeInfo).build();
        assertEquals(routeInfo, routeInfoRebuilt);

        Parcel parcel = Parcel.obtain();
        parcel.writeParcelable(routeInfo, 0);
        parcel.setDataPosition(0);
        MediaRoute2Info routeInfoFromParcel = parcel.readParcelable(null);

        assertEquals(routeInfo, routeInfoFromParcel);
    }

    @Test
    public void testRouteInfoInequality() {
        MediaRoute2Info route = new MediaRoute2Info.Builder("id", "name")
                .setDescription("description")
                .setClientPackageName("com.android.mediaroutertest")
                .setConnectionState(CONNECTION_STATE_CONNECTING)
                .setIconUri(new Uri.Builder().path("icon").build())
                .addSupportedCategory(CATEGORY_SAMPLE)
                .setVolume(5)
                .setVolumeMax(20)
                .setVolumeHandling(PLAYBACK_VOLUME_VARIABLE)
                .setDeviceType(DEVICE_TYPE_SPEAKER)
                .build();

        MediaRoute2Info routeId = new MediaRoute2Info.Builder(route)
                .setId("another id").build();
        assertNotEquals(route, routeId);

        MediaRoute2Info routeName = new MediaRoute2Info.Builder(route)
                .setName("another name").build();
        assertNotEquals(route, routeName);

        MediaRoute2Info routeDescription = new MediaRoute2Info.Builder(route)
                .setDescription("another description").build();
        assertNotEquals(route, routeDescription);

        MediaRoute2Info routeConnectionState = new MediaRoute2Info.Builder(route)
                .setConnectionState(CONNECTION_STATE_CONNECTED).build();
        assertNotEquals(route, routeConnectionState);

        MediaRoute2Info routeIcon = new MediaRoute2Info.Builder(route)
                .setIconUri(new Uri.Builder().path("new icon").build()).build();
        assertNotEquals(route, routeIcon);

        MediaRoute2Info routeClient = new MediaRoute2Info.Builder(route)
                .setClientPackageName("another.client.package").build();
        assertNotEquals(route, routeClient);

        MediaRoute2Info routeCategory = new MediaRoute2Info.Builder(route)
                .addSupportedCategory(CATEGORY_SPECIAL).build();
        assertNotEquals(route, routeCategory);

        MediaRoute2Info routeVolume = new MediaRoute2Info.Builder(route)
                .setVolume(10).build();
        assertNotEquals(route, routeVolume);

        MediaRoute2Info routeVolumeMax = new MediaRoute2Info.Builder(route)
                .setVolumeMax(30).build();
        assertNotEquals(route, routeVolumeMax);

        MediaRoute2Info routeVolumeHandling = new MediaRoute2Info.Builder(route)
                .setVolumeHandling(PLAYBACK_VOLUME_FIXED).build();
        assertNotEquals(route, routeVolumeHandling);

        MediaRoute2Info routeDeviceType = new MediaRoute2Info.Builder(route)
                .setVolume(DEVICE_TYPE_TV).build();
        assertNotEquals(route, routeDeviceType);
    }

    @Test
    public void testControlVolumeWithRouter() throws Exception {
        Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_ALL);
+1 −18
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@ import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_FIXED;
import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

@@ -124,20 +123,6 @@ public class MediaRouterManagerTest {
        clearCallbacks();
    }

    //TODO: Move to a separate file
    @Test
    public void testMediaRoute2Info() {
        MediaRoute2Info routeInfo1 = new MediaRoute2Info.Builder("id", "name")
                .build();
        MediaRoute2Info routeInfo2 = new MediaRoute2Info.Builder(routeInfo1).build();

        MediaRoute2Info routeInfo3 = new MediaRoute2Info.Builder(routeInfo1)
                .setClientPackageName(mPackageName).build();

        assertEquals(routeInfo1, routeInfo2);
        assertNotEquals(routeInfo1, routeInfo3);
    }

   /**
     * Tests if routes are added correctly when a new callback is registered.
     */
@@ -177,8 +162,6 @@ public class MediaRouterManagerTest {
            }
        });

        //TODO: Figure out a more proper way to test.
        // (Control requests shouldn't be used in this way.)
        mRouter2.sendControlRequest(routes.get(ROUTE_ID2), new Intent(ACTION_REMOVE_ROUTE));
        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
    }