Merge "MediaRouter: Add missing info to MediaRoute2Info"

This commit is contained in:
TreeHugger Robot
2019-12-24 05:33:11 +00:00
committed by Android (Google) Code Review
4 changed files with 284 additions and 20 deletions

View File

@@ -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.
*/

View File

@@ -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);

View File

@@ -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);

View File

@@ -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,21 +123,7 @@ 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.
*/
@Test
@@ -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));
}