1437 lines
48 KiB
Java
1437 lines
48 KiB
Java
![]() |
/*
|
||
|
* Copyright 2019 The Android Open Source Project
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
package android.media;
|
||
|
|
||
|
import static android.media.MediaRouter2Utils.toUniqueId;
|
||
|
|
||
|
import static com.android.media.flags.Flags.FLAG_ENABLE_AUDIO_POLICIES_DEVICE_AND_BLUETOOTH_CONTROLLER;
|
||
|
import static com.android.media.flags.Flags.FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES;
|
||
|
import static com.android.media.flags.Flags.FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES;
|
||
|
|
||
|
import android.annotation.FlaggedApi;
|
||
|
import android.annotation.IntDef;
|
||
|
import android.annotation.NonNull;
|
||
|
import android.annotation.Nullable;
|
||
|
import android.annotation.TestApi;
|
||
|
import android.net.Uri;
|
||
|
import android.os.Bundle;
|
||
|
import android.os.Parcel;
|
||
|
import android.os.Parcelable;
|
||
|
import android.text.TextUtils;
|
||
|
|
||
|
import com.android.internal.util.Preconditions;
|
||
|
|
||
|
import java.io.PrintWriter;
|
||
|
import java.lang.annotation.Retention;
|
||
|
import java.lang.annotation.RetentionPolicy;
|
||
|
import java.util.ArrayList;
|
||
|
import java.util.Collection;
|
||
|
import java.util.List;
|
||
|
import java.util.Locale;
|
||
|
import java.util.Objects;
|
||
|
import java.util.Set;
|
||
|
|
||
|
/**
|
||
|
* Describes the properties of a route.
|
||
|
*/
|
||
|
public final class MediaRoute2Info implements Parcelable {
|
||
|
@NonNull
|
||
|
public static final Creator<MediaRoute2Info> CREATOR = new Creator<MediaRoute2Info>() {
|
||
|
@Override
|
||
|
public MediaRoute2Info createFromParcel(Parcel in) {
|
||
|
return new MediaRoute2Info(in);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public MediaRoute2Info[] newArray(int size) {
|
||
|
return new MediaRoute2Info[size];
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* The {@link #getOriginalId() original id} of the route that represents the built-in media
|
||
|
* route.
|
||
|
*
|
||
|
* <p>A route with this id will only be visible to apps with permission to do system routing,
|
||
|
* which means having {@link android.Manifest.permission#BLUETOOTH_CONNECT} and {@link
|
||
|
* android.Manifest.permission#BLUETOOTH_SCAN}, or {@link
|
||
|
* android.Manifest.permission#MODIFY_AUDIO_ROUTING}.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
public static final String ROUTE_ID_DEVICE = "DEVICE_ROUTE";
|
||
|
|
||
|
/**
|
||
|
* The {@link #getOriginalId() original id} of the route that represents the default system
|
||
|
* media route.
|
||
|
*
|
||
|
* <p>A route with this id will be visible to apps with no permission over system routing. See
|
||
|
* {@link #ROUTE_ID_DEVICE} for details.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
public static final String ROUTE_ID_DEFAULT = "DEFAULT_ROUTE";
|
||
|
|
||
|
/** @hide */
|
||
|
@IntDef({CONNECTION_STATE_DISCONNECTED, CONNECTION_STATE_CONNECTING,
|
||
|
CONNECTION_STATE_CONNECTED})
|
||
|
@Retention(RetentionPolicy.SOURCE)
|
||
|
public @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;
|
||
|
|
||
|
/** @hide */
|
||
|
@IntDef({PLAYBACK_VOLUME_FIXED, PLAYBACK_VOLUME_VARIABLE})
|
||
|
@Retention(RetentionPolicy.SOURCE)
|
||
|
public @interface PlaybackVolume {}
|
||
|
|
||
|
/**
|
||
|
* 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,
|
||
|
* playing over HDMI where the user prefers to control the volume on the HDMI sink, rather
|
||
|
* than attenuate at the source.
|
||
|
*
|
||
|
* @see #getVolumeHandling()
|
||
|
*/
|
||
|
public static final int PLAYBACK_VOLUME_FIXED = 0;
|
||
|
/**
|
||
|
* Playback information indicating the playback volume is variable and can be controlled
|
||
|
* from this object.
|
||
|
*
|
||
|
* @see #getVolumeHandling()
|
||
|
*/
|
||
|
public static final int PLAYBACK_VOLUME_VARIABLE = 1;
|
||
|
|
||
|
/** @hide */
|
||
|
@IntDef(
|
||
|
prefix = {"TYPE_"},
|
||
|
value = {
|
||
|
TYPE_UNKNOWN,
|
||
|
TYPE_BUILTIN_SPEAKER,
|
||
|
TYPE_WIRED_HEADSET,
|
||
|
TYPE_WIRED_HEADPHONES,
|
||
|
TYPE_BLUETOOTH_A2DP,
|
||
|
TYPE_HDMI,
|
||
|
TYPE_HDMI_ARC,
|
||
|
TYPE_HDMI_EARC,
|
||
|
TYPE_USB_DEVICE,
|
||
|
TYPE_USB_ACCESSORY,
|
||
|
TYPE_DOCK,
|
||
|
TYPE_USB_HEADSET,
|
||
|
TYPE_HEARING_AID,
|
||
|
TYPE_BLE_HEADSET,
|
||
|
TYPE_REMOTE_TV,
|
||
|
TYPE_REMOTE_SPEAKER,
|
||
|
TYPE_REMOTE_AUDIO_VIDEO_RECEIVER,
|
||
|
TYPE_REMOTE_TABLET,
|
||
|
TYPE_REMOTE_TABLET_DOCKED,
|
||
|
TYPE_REMOTE_COMPUTER,
|
||
|
TYPE_REMOTE_GAME_CONSOLE,
|
||
|
TYPE_REMOTE_CAR,
|
||
|
TYPE_REMOTE_SMARTWATCH,
|
||
|
TYPE_REMOTE_SMARTPHONE,
|
||
|
TYPE_GROUP
|
||
|
})
|
||
|
@Retention(RetentionPolicy.SOURCE)
|
||
|
public @interface Type {}
|
||
|
|
||
|
/**
|
||
|
* Indicates the route's type is unknown or undefined.
|
||
|
*
|
||
|
* @see #getType
|
||
|
*/
|
||
|
public static final int TYPE_UNKNOWN = 0;
|
||
|
|
||
|
/**
|
||
|
* Indicates the route is the speaker system (i.e. a mono speaker or stereo speakers) built into
|
||
|
* the device.
|
||
|
*
|
||
|
* @see #getType
|
||
|
*/
|
||
|
public static final int TYPE_BUILTIN_SPEAKER = AudioDeviceInfo.TYPE_BUILTIN_SPEAKER;
|
||
|
|
||
|
/**
|
||
|
* Indicates the route is a headset, which is the combination of a headphones and a microphone.
|
||
|
*
|
||
|
* @see #getType
|
||
|
*/
|
||
|
public static final int TYPE_WIRED_HEADSET = AudioDeviceInfo.TYPE_WIRED_HEADSET;
|
||
|
|
||
|
/**
|
||
|
* Indicates the route is a pair of wired headphones.
|
||
|
*
|
||
|
* @see #getType
|
||
|
*/
|
||
|
public static final int TYPE_WIRED_HEADPHONES = AudioDeviceInfo.TYPE_WIRED_HEADPHONES;
|
||
|
|
||
|
/**
|
||
|
* Indicates the route is a bluetooth device, such as a bluetooth speaker or headphones.
|
||
|
*
|
||
|
* @see #getType
|
||
|
*/
|
||
|
public static final int TYPE_BLUETOOTH_A2DP = AudioDeviceInfo.TYPE_BLUETOOTH_A2DP;
|
||
|
|
||
|
/**
|
||
|
* Indicates the route is an HDMI connection.
|
||
|
*
|
||
|
* @see #getType
|
||
|
*/
|
||
|
public static final int TYPE_HDMI = AudioDeviceInfo.TYPE_HDMI;
|
||
|
|
||
|
/**
|
||
|
* Indicates the route is an Audio Return Channel of an HDMI connection.
|
||
|
*
|
||
|
* @see #getType
|
||
|
*/
|
||
|
@FlaggedApi(FLAG_ENABLE_AUDIO_POLICIES_DEVICE_AND_BLUETOOTH_CONTROLLER)
|
||
|
public static final int TYPE_HDMI_ARC = AudioDeviceInfo.TYPE_HDMI_ARC;
|
||
|
|
||
|
/**
|
||
|
* Indicates the route is an Enhanced Audio Return Channel of an HDMI connection.
|
||
|
*
|
||
|
* @see #getType
|
||
|
*/
|
||
|
@FlaggedApi(FLAG_ENABLE_AUDIO_POLICIES_DEVICE_AND_BLUETOOTH_CONTROLLER)
|
||
|
public static final int TYPE_HDMI_EARC = AudioDeviceInfo.TYPE_HDMI_EARC;
|
||
|
|
||
|
/**
|
||
|
* Indicates the route is a USB audio device.
|
||
|
*
|
||
|
* @see #getType
|
||
|
*/
|
||
|
public static final int TYPE_USB_DEVICE = AudioDeviceInfo.TYPE_USB_DEVICE;
|
||
|
|
||
|
/**
|
||
|
* Indicates the route is a USB audio device in accessory mode.
|
||
|
*
|
||
|
* @see #getType
|
||
|
*/
|
||
|
public static final int TYPE_USB_ACCESSORY = AudioDeviceInfo.TYPE_USB_ACCESSORY;
|
||
|
|
||
|
/**
|
||
|
* Indicates the route is the audio device associated with a dock.
|
||
|
*
|
||
|
* @see #getType
|
||
|
*/
|
||
|
public static final int TYPE_DOCK = AudioDeviceInfo.TYPE_DOCK;
|
||
|
|
||
|
/**
|
||
|
* Indicates the route is a USB audio headset.
|
||
|
*
|
||
|
* @see #getType
|
||
|
*/
|
||
|
public static final int TYPE_USB_HEADSET = AudioDeviceInfo.TYPE_USB_HEADSET;
|
||
|
|
||
|
/**
|
||
|
* Indicates the route is a hearing aid.
|
||
|
*
|
||
|
* @see #getType
|
||
|
*/
|
||
|
public static final int TYPE_HEARING_AID = AudioDeviceInfo.TYPE_HEARING_AID;
|
||
|
|
||
|
/**
|
||
|
* Indicates the route is a Bluetooth Low Energy (BLE) HEADSET.
|
||
|
*
|
||
|
* @see #getType
|
||
|
*/
|
||
|
public static final int TYPE_BLE_HEADSET = AudioDeviceInfo.TYPE_BLE_HEADSET;
|
||
|
|
||
|
/**
|
||
|
* Indicates the route is a remote TV.
|
||
|
*
|
||
|
* <p>A remote device uses a routing protocol managed by the application, as opposed to the
|
||
|
* routing being done by the system.
|
||
|
*
|
||
|
* @see #getType
|
||
|
*/
|
||
|
public static final int TYPE_REMOTE_TV = 1001;
|
||
|
|
||
|
/**
|
||
|
* Indicates the route is a remote speaker.
|
||
|
*
|
||
|
* <p>A remote device uses a routing protocol managed by the application, as opposed to the
|
||
|
* routing being done by the system.
|
||
|
*
|
||
|
* @see #getType
|
||
|
*/
|
||
|
public static final int TYPE_REMOTE_SPEAKER = 1002;
|
||
|
|
||
|
/**
|
||
|
* Indicates the route is a remote Audio/Video Receiver (AVR).
|
||
|
*
|
||
|
* <p>A remote device uses a routing protocol managed by the application, as opposed to the
|
||
|
* routing being done by the system.
|
||
|
*
|
||
|
* @see #getType
|
||
|
*/
|
||
|
public static final int TYPE_REMOTE_AUDIO_VIDEO_RECEIVER = 1003;
|
||
|
|
||
|
/**
|
||
|
* Indicates the route is a remote tablet.
|
||
|
*
|
||
|
* <p>A remote device uses a routing protocol managed by the application, as opposed to the
|
||
|
* routing being done by the system.
|
||
|
*
|
||
|
* @see #getType
|
||
|
*/
|
||
|
@FlaggedApi(FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES)
|
||
|
public static final int TYPE_REMOTE_TABLET = 1004;
|
||
|
|
||
|
/**
|
||
|
* Indicates the route is a remote docked tablet.
|
||
|
*
|
||
|
* <p>A remote device uses a routing protocol managed by the application, as opposed to the
|
||
|
* routing being done by the system.
|
||
|
*
|
||
|
* @see #getType
|
||
|
*/
|
||
|
@FlaggedApi(FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES)
|
||
|
public static final int TYPE_REMOTE_TABLET_DOCKED = 1005;
|
||
|
|
||
|
/**
|
||
|
* Indicates the route is a remote computer.
|
||
|
*
|
||
|
* <p>A remote device uses a routing protocol managed by the application, as opposed to the
|
||
|
* routing being done by the system.
|
||
|
*
|
||
|
* @see #getType
|
||
|
*/
|
||
|
@FlaggedApi(FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES)
|
||
|
public static final int TYPE_REMOTE_COMPUTER = 1006;
|
||
|
|
||
|
/**
|
||
|
* Indicates the route is a remote gaming console.
|
||
|
*
|
||
|
* <p>A remote device uses a routing protocol managed by the application, as opposed to the
|
||
|
* routing being done by the system.
|
||
|
*
|
||
|
* @see #getType
|
||
|
*/
|
||
|
@FlaggedApi(FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES)
|
||
|
public static final int TYPE_REMOTE_GAME_CONSOLE = 1007;
|
||
|
|
||
|
/**
|
||
|
* Indicates the route is a remote car.
|
||
|
*
|
||
|
* <p>A remote device uses a routing protocol managed by the application, as opposed to the
|
||
|
* routing being done by the system.
|
||
|
*
|
||
|
* @see #getType
|
||
|
*/
|
||
|
@FlaggedApi(FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES)
|
||
|
public static final int TYPE_REMOTE_CAR = 1008;
|
||
|
|
||
|
/**
|
||
|
* Indicates the route is a remote smartwatch.
|
||
|
*
|
||
|
* <p>A remote device uses a routing protocol managed by the application, as opposed to the
|
||
|
* routing being done by the system.
|
||
|
*
|
||
|
* @see #getType
|
||
|
*/
|
||
|
@FlaggedApi(FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES)
|
||
|
public static final int TYPE_REMOTE_SMARTWATCH = 1009;
|
||
|
|
||
|
/**
|
||
|
* Indicates the route is a remote smartphone.
|
||
|
*
|
||
|
* <p>A remote device uses a routing protocol managed by the application, as opposed to the
|
||
|
* routing being done by the system.
|
||
|
*
|
||
|
* @see #getType
|
||
|
*/
|
||
|
@FlaggedApi(FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES)
|
||
|
public static final int TYPE_REMOTE_SMARTPHONE = 1010;
|
||
|
|
||
|
/**
|
||
|
* Indicates the route is a group of devices.
|
||
|
*
|
||
|
* @see #getType
|
||
|
*/
|
||
|
public static final int TYPE_GROUP = 2000;
|
||
|
|
||
|
/**
|
||
|
* Route feature: Live audio.
|
||
|
* <p>
|
||
|
* A route that supports live audio routing will allow the media audio stream
|
||
|
* to be sent to supported destinations. This can include internal speakers or
|
||
|
* audio jacks on the device itself, A2DP devices, and more.
|
||
|
* </p><p>
|
||
|
* When a live audio route is selected, audio routing is transparent to the application.
|
||
|
* All audio played on the media stream will be routed to the selected destination.
|
||
|
* </p><p>
|
||
|
* Refer to the class documentation for details about live audio routes.
|
||
|
* </p>
|
||
|
*/
|
||
|
public static final String FEATURE_LIVE_AUDIO = "android.media.route.feature.LIVE_AUDIO";
|
||
|
|
||
|
/**
|
||
|
* Route feature: Live video.
|
||
|
* <p>
|
||
|
* A route that supports live video routing will allow a mirrored version
|
||
|
* of the device's primary display or a customized
|
||
|
* {@link android.app.Presentation Presentation} to be sent to supported
|
||
|
* destinations.
|
||
|
* </p><p>
|
||
|
* When a live video route is selected, audio and video routing is transparent
|
||
|
* to the application. By default, audio and video is routed to the selected
|
||
|
* destination. For certain live video routes, the application may also use a
|
||
|
* {@link android.app.Presentation Presentation} to replace the mirrored view
|
||
|
* on the external display with different content.
|
||
|
* </p><p>
|
||
|
* Refer to the class documentation for details about live video routes.
|
||
|
* </p>
|
||
|
*
|
||
|
* @see android.app.Presentation
|
||
|
*/
|
||
|
public static final String FEATURE_LIVE_VIDEO = "android.media.route.feature.LIVE_VIDEO";
|
||
|
|
||
|
/**
|
||
|
* Route feature: Local playback.
|
||
|
* @hide
|
||
|
*/
|
||
|
public static final String FEATURE_LOCAL_PLAYBACK =
|
||
|
"android.media.route.feature.LOCAL_PLAYBACK";
|
||
|
|
||
|
/**
|
||
|
* Route feature: Remote playback.
|
||
|
* <p>
|
||
|
* A route that supports remote playback routing will allow an application to send
|
||
|
* requests to play content remotely to supported destinations.
|
||
|
* A route may only support {@link #FEATURE_REMOTE_AUDIO_PLAYBACK audio playback} or
|
||
|
* {@link #FEATURE_REMOTE_VIDEO_PLAYBACK video playback}.
|
||
|
* </p><p>
|
||
|
* Remote playback routes destinations operate independently of the local device.
|
||
|
* When a remote playback route is selected, the application can control the content
|
||
|
* playing on the destination using {@link MediaRouter2.RoutingController#getControlHints()}.
|
||
|
* The application may also receive status updates from the route regarding remote playback.
|
||
|
* </p><p>
|
||
|
* Refer to the class documentation for details about remote playback routes.
|
||
|
* </p>
|
||
|
* @see #FEATURE_REMOTE_AUDIO_PLAYBACK
|
||
|
* @see #FEATURE_REMOTE_VIDEO_PLAYBACK
|
||
|
*/
|
||
|
public static final String FEATURE_REMOTE_PLAYBACK =
|
||
|
"android.media.route.feature.REMOTE_PLAYBACK";
|
||
|
|
||
|
/**
|
||
|
* Route feature: Remote audio playback.
|
||
|
* <p>
|
||
|
* A route that supports remote audio playback routing will allow an application to send
|
||
|
* requests to play audio content remotely to supported destinations.
|
||
|
*
|
||
|
* @see #FEATURE_REMOTE_PLAYBACK
|
||
|
* @see #FEATURE_REMOTE_VIDEO_PLAYBACK
|
||
|
*/
|
||
|
public static final String FEATURE_REMOTE_AUDIO_PLAYBACK =
|
||
|
"android.media.route.feature.REMOTE_AUDIO_PLAYBACK";
|
||
|
|
||
|
/**
|
||
|
* Route feature: Remote video playback.
|
||
|
* <p>
|
||
|
* A route that supports remote video playback routing will allow an application to send
|
||
|
* requests to play video content remotely to supported destinations.
|
||
|
*
|
||
|
* @see #FEATURE_REMOTE_PLAYBACK
|
||
|
* @see #FEATURE_REMOTE_AUDIO_PLAYBACK
|
||
|
*/
|
||
|
public static final String FEATURE_REMOTE_VIDEO_PLAYBACK =
|
||
|
"android.media.route.feature.REMOTE_VIDEO_PLAYBACK";
|
||
|
|
||
|
/**
|
||
|
* Route feature: Remote group playback.
|
||
|
* <p>
|
||
|
* @hide
|
||
|
*/
|
||
|
public static final String FEATURE_REMOTE_GROUP_PLAYBACK =
|
||
|
"android.media.route.feature.REMOTE_GROUP_PLAYBACK";
|
||
|
|
||
|
/** Indicates the route is always suitable for media playback. */
|
||
|
@FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
|
||
|
public static final int SUITABILITY_STATUS_SUITABLE_FOR_DEFAULT_TRANSFER = 0;
|
||
|
|
||
|
/**
|
||
|
* Indicates that the route is suitable for media playback only after explicit user selection.
|
||
|
*/
|
||
|
@FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
|
||
|
public static final int SUITABILITY_STATUS_SUITABLE_FOR_MANUAL_TRANSFER = 1;
|
||
|
|
||
|
/** Indicates that the route is never suitable for media playback. */
|
||
|
@FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
|
||
|
public static final int SUITABILITY_STATUS_NOT_SUITABLE_FOR_TRANSFER = 2;
|
||
|
|
||
|
/**
|
||
|
* Route suitability status.
|
||
|
*
|
||
|
* <p>Signals whether the route is suitable to play media.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
@IntDef(
|
||
|
value = {
|
||
|
SUITABILITY_STATUS_SUITABLE_FOR_DEFAULT_TRANSFER,
|
||
|
SUITABILITY_STATUS_SUITABLE_FOR_MANUAL_TRANSFER,
|
||
|
SUITABILITY_STATUS_NOT_SUITABLE_FOR_TRANSFER
|
||
|
})
|
||
|
@Retention(RetentionPolicy.SOURCE)
|
||
|
@FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
|
||
|
public @interface SuitabilityStatus {}
|
||
|
|
||
|
private final String mId;
|
||
|
private final CharSequence mName;
|
||
|
private final List<String> mFeatures;
|
||
|
@Type
|
||
|
private final int mType;
|
||
|
private final boolean mIsSystem;
|
||
|
private final Uri mIconUri;
|
||
|
private final CharSequence mDescription;
|
||
|
@ConnectionState
|
||
|
private final int mConnectionState;
|
||
|
private final String mClientPackageName;
|
||
|
private final String mPackageName;
|
||
|
private final int mVolumeHandling;
|
||
|
private final int mVolumeMax;
|
||
|
private final int mVolume;
|
||
|
private final String mAddress;
|
||
|
private final Set<String> mDeduplicationIds;
|
||
|
private final Bundle mExtras;
|
||
|
private final String mProviderId;
|
||
|
private final boolean mIsVisibilityRestricted;
|
||
|
private final Set<String> mAllowedPackages;
|
||
|
@SuitabilityStatus private final int mSuitabilityStatus;
|
||
|
|
||
|
MediaRoute2Info(@NonNull Builder builder) {
|
||
|
mId = builder.mId;
|
||
|
mName = builder.mName;
|
||
|
mFeatures = builder.mFeatures;
|
||
|
mType = builder.mType;
|
||
|
mIsSystem = builder.mIsSystem;
|
||
|
mIconUri = builder.mIconUri;
|
||
|
mDescription = builder.mDescription;
|
||
|
mConnectionState = builder.mConnectionState;
|
||
|
mClientPackageName = builder.mClientPackageName;
|
||
|
mPackageName = builder.mPackageName;
|
||
|
mVolumeHandling = builder.mVolumeHandling;
|
||
|
mVolumeMax = builder.mVolumeMax;
|
||
|
mVolume = builder.mVolume;
|
||
|
mAddress = builder.mAddress;
|
||
|
mDeduplicationIds = builder.mDeduplicationIds;
|
||
|
mExtras = builder.mExtras;
|
||
|
mProviderId = builder.mProviderId;
|
||
|
mIsVisibilityRestricted = builder.mIsVisibilityRestricted;
|
||
|
mAllowedPackages = builder.mAllowedPackages;
|
||
|
mSuitabilityStatus = builder.mSuitabilityStatus;
|
||
|
}
|
||
|
|
||
|
MediaRoute2Info(@NonNull Parcel in) {
|
||
|
mId = in.readString();
|
||
|
Preconditions.checkArgument(!TextUtils.isEmpty(mId));
|
||
|
mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
|
||
|
mFeatures = in.createStringArrayList();
|
||
|
mType = in.readInt();
|
||
|
mIsSystem = in.readBoolean();
|
||
|
mIconUri = in.readParcelable(null, android.net.Uri.class);
|
||
|
mDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
|
||
|
mConnectionState = in.readInt();
|
||
|
mClientPackageName = in.readString();
|
||
|
mPackageName = in.readString();
|
||
|
mVolumeHandling = in.readInt();
|
||
|
mVolumeMax = in.readInt();
|
||
|
mVolume = in.readInt();
|
||
|
mAddress = in.readString();
|
||
|
mDeduplicationIds = Set.of(in.readStringArray());
|
||
|
mExtras = in.readBundle();
|
||
|
mProviderId = in.readString();
|
||
|
mIsVisibilityRestricted = in.readBoolean();
|
||
|
mAllowedPackages = Set.of(in.createString8Array());
|
||
|
mSuitabilityStatus = in.readInt();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Gets the id of the route. The routes which are given by {@link MediaRouter2} will have
|
||
|
* unique IDs.
|
||
|
* <p>
|
||
|
* In order to ensure uniqueness in {@link MediaRouter2} side, the value of this method
|
||
|
* can be different from what was set in {@link MediaRoute2ProviderService}.
|
||
|
*
|
||
|
* @see Builder#Builder(String, CharSequence)
|
||
|
*/
|
||
|
@NonNull
|
||
|
public String getId() {
|
||
|
if (!TextUtils.isEmpty(mProviderId)) {
|
||
|
return toUniqueId(mProviderId, mId);
|
||
|
} else {
|
||
|
return mId;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Gets the user-visible name of the route.
|
||
|
*/
|
||
|
@NonNull
|
||
|
public CharSequence getName() {
|
||
|
return mName;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Gets the supported features of the route.
|
||
|
*/
|
||
|
@NonNull
|
||
|
public List<String> getFeatures() {
|
||
|
return mFeatures;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the type of this route.
|
||
|
*/
|
||
|
@Type
|
||
|
public int getType() {
|
||
|
return mType;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns whether the route is a system route or not.
|
||
|
* <p>
|
||
|
* System routes are media routes directly controlled by the system
|
||
|
* such as phone speaker, wired headset, and Bluetooth devices.
|
||
|
* </p>
|
||
|
*/
|
||
|
public boolean isSystemRoute() {
|
||
|
return mIsSystem;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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 user-visible description of the route.
|
||
|
*/
|
||
|
@Nullable
|
||
|
public CharSequence getDescription() {
|
||
|
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 package name of the app using the route.
|
||
|
* Returns null if no apps are using this route.
|
||
|
*/
|
||
|
@Nullable
|
||
|
public String getClientPackageName() {
|
||
|
return mClientPackageName;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Gets the package name of the provider that published the route.
|
||
|
* <p>
|
||
|
* It is set by the system service.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Nullable
|
||
|
public String getPackageName() {
|
||
|
return mPackageName;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Gets information about how volume is handled on the route.
|
||
|
*
|
||
|
* @return {@link #PLAYBACK_VOLUME_FIXED} or {@link #PLAYBACK_VOLUME_VARIABLE}
|
||
|
*/
|
||
|
@PlaybackVolume
|
||
|
public int getVolumeHandling() {
|
||
|
return mVolumeHandling;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Gets the maximum volume of the route.
|
||
|
*/
|
||
|
public int getVolumeMax() {
|
||
|
return mVolumeMax;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Gets the current volume of the route. This may be invalid if the route is not selected.
|
||
|
*/
|
||
|
public int getVolume() {
|
||
|
return mVolume;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Gets the hardware address of the route if available.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Nullable
|
||
|
public String getAddress() {
|
||
|
return mAddress;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Gets the deduplication IDs associated to the route.
|
||
|
*
|
||
|
* <p>Two routes with a matching deduplication ID originate from the same receiver device.
|
||
|
*/
|
||
|
@NonNull
|
||
|
public Set<String> getDeduplicationIds() {
|
||
|
return mDeduplicationIds;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Gets an optional bundle with extra data.
|
||
|
*/
|
||
|
@Nullable
|
||
|
public Bundle getExtras() {
|
||
|
return mExtras == null ? null : new Bundle(mExtras);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Gets the original id set by {@link Builder#Builder(String, CharSequence)}.
|
||
|
* @hide
|
||
|
*/
|
||
|
@NonNull
|
||
|
@TestApi
|
||
|
public String getOriginalId() {
|
||
|
return mId;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Gets the provider id of the route. It is assigned automatically by
|
||
|
* {@link com.android.server.media.MediaRouterService}.
|
||
|
*
|
||
|
* @return provider id of the route or null if it's not set.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Nullable
|
||
|
public String getProviderId() {
|
||
|
return mProviderId;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns if the route has at least one of the specified route features.
|
||
|
*
|
||
|
* @param features the list of route features to consider
|
||
|
* @return {@code true} if the route has at least one feature in the list
|
||
|
* @hide
|
||
|
*/
|
||
|
public boolean hasAnyFeatures(@NonNull Collection<String> features) {
|
||
|
Objects.requireNonNull(features, "features must not be null");
|
||
|
for (String feature : features) {
|
||
|
if (getFeatures().contains(feature)) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns if the route has all the specified route features.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
public boolean hasAllFeatures(@NonNull Collection<String> features) {
|
||
|
Objects.requireNonNull(features, "features must not be null");
|
||
|
for (String feature : features) {
|
||
|
if (!getFeatures().contains(feature)) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if the route info has all of the required field.
|
||
|
* A route is valid if and only if it is obtained from
|
||
|
* {@link com.android.server.media.MediaRouterService}.
|
||
|
* @hide
|
||
|
*/
|
||
|
public boolean isValid() {
|
||
|
if (TextUtils.isEmpty(getId()) || TextUtils.isEmpty(getName())
|
||
|
|| TextUtils.isEmpty(getProviderId())) {
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns whether this route is visible to the package with the given name.
|
||
|
* @hide
|
||
|
*/
|
||
|
public boolean isVisibleTo(String packageName) {
|
||
|
return !mIsVisibilityRestricted || getPackageName().equals(packageName)
|
||
|
|| mAllowedPackages.contains(packageName);
|
||
|
}
|
||
|
|
||
|
/** Returns the route suitability status. */
|
||
|
@SuitabilityStatus
|
||
|
@FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
|
||
|
public int getSuitabilityStatus() {
|
||
|
return mSuitabilityStatus;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Dumps the current state of the object to the given {@code pw} as a human-readable string.
|
||
|
*
|
||
|
* <p> Used in the context of dumpsys. </p>
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
|
||
|
pw.println(prefix + "MediaRoute2Info");
|
||
|
|
||
|
String indent = prefix + " ";
|
||
|
|
||
|
pw.println(indent + "mId=" + mId);
|
||
|
pw.println(indent + "mName=" + mName);
|
||
|
pw.println(indent + "mFeatures=" + mFeatures);
|
||
|
pw.println(indent + "mType=" + getDeviceTypeString(mType));
|
||
|
pw.println(indent + "mIsSystem=" + mIsSystem);
|
||
|
pw.println(indent + "mIconUri=" + mIconUri);
|
||
|
pw.println(indent + "mDescription=" + mDescription);
|
||
|
pw.println(indent + "mConnectionState=" + mConnectionState);
|
||
|
pw.println(indent + "mClientPackageName=" + mClientPackageName);
|
||
|
pw.println(indent + "mPackageName=" + mPackageName);
|
||
|
|
||
|
dumpVolume(pw, indent);
|
||
|
|
||
|
pw.println(indent + "mAddress=" + mAddress);
|
||
|
pw.println(indent + "mDeduplicationIds=" + mDeduplicationIds);
|
||
|
pw.println(indent + "mExtras=" + mExtras);
|
||
|
pw.println(indent + "mProviderId=" + mProviderId);
|
||
|
pw.println(indent + "mIsVisibilityRestricted=" + mIsVisibilityRestricted);
|
||
|
pw.println(indent + "mAllowedPackages=" + mAllowedPackages);
|
||
|
pw.println(indent + "mSuitabilityStatus=" + mSuitabilityStatus);
|
||
|
}
|
||
|
|
||
|
private void dumpVolume(@NonNull PrintWriter pw, @NonNull String prefix) {
|
||
|
String volumeHandlingName;
|
||
|
|
||
|
switch (mVolumeHandling) {
|
||
|
case PLAYBACK_VOLUME_FIXED:
|
||
|
volumeHandlingName = "FIXED";
|
||
|
break;
|
||
|
case PLAYBACK_VOLUME_VARIABLE:
|
||
|
volumeHandlingName = "VARIABLE";
|
||
|
break;
|
||
|
default:
|
||
|
volumeHandlingName = "UNKNOWN";
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
String volume = String.format(Locale.US,
|
||
|
"volume(current=%d, max=%d, handling=%s(%d))",
|
||
|
mVolume, mVolumeMax, volumeHandlingName, mVolumeHandling);
|
||
|
|
||
|
pw.println(prefix + volume);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean equals(Object obj) {
|
||
|
if (this == obj) {
|
||
|
return true;
|
||
|
}
|
||
|
if (!(obj instanceof MediaRoute2Info)) {
|
||
|
return false;
|
||
|
}
|
||
|
MediaRoute2Info other = (MediaRoute2Info) obj;
|
||
|
|
||
|
// Note: mExtras is not included.
|
||
|
return Objects.equals(mId, other.mId)
|
||
|
&& Objects.equals(mName, other.mName)
|
||
|
&& Objects.equals(mFeatures, other.mFeatures)
|
||
|
&& (mType == other.mType)
|
||
|
&& (mIsSystem == other.mIsSystem)
|
||
|
&& Objects.equals(mIconUri, other.mIconUri)
|
||
|
&& Objects.equals(mDescription, other.mDescription)
|
||
|
&& (mConnectionState == other.mConnectionState)
|
||
|
&& Objects.equals(mClientPackageName, other.mClientPackageName)
|
||
|
&& Objects.equals(mPackageName, other.mPackageName)
|
||
|
&& (mVolumeHandling == other.mVolumeHandling)
|
||
|
&& (mVolumeMax == other.mVolumeMax)
|
||
|
&& (mVolume == other.mVolume)
|
||
|
&& Objects.equals(mAddress, other.mAddress)
|
||
|
&& Objects.equals(mDeduplicationIds, other.mDeduplicationIds)
|
||
|
&& Objects.equals(mProviderId, other.mProviderId)
|
||
|
&& (mIsVisibilityRestricted == other.mIsVisibilityRestricted)
|
||
|
&& Objects.equals(mAllowedPackages, other.mAllowedPackages)
|
||
|
&& mSuitabilityStatus == other.mSuitabilityStatus;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int hashCode() {
|
||
|
// Note: mExtras is not included.
|
||
|
return Objects.hash(
|
||
|
mId,
|
||
|
mName,
|
||
|
mFeatures,
|
||
|
mType,
|
||
|
mIsSystem,
|
||
|
mIconUri,
|
||
|
mDescription,
|
||
|
mConnectionState,
|
||
|
mClientPackageName,
|
||
|
mPackageName,
|
||
|
mVolumeHandling,
|
||
|
mVolumeMax,
|
||
|
mVolume,
|
||
|
mAddress,
|
||
|
mDeduplicationIds,
|
||
|
mProviderId,
|
||
|
mIsVisibilityRestricted,
|
||
|
mAllowedPackages,
|
||
|
mSuitabilityStatus);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public String toString() {
|
||
|
// Note: mExtras is not printed here.
|
||
|
StringBuilder result =
|
||
|
new StringBuilder()
|
||
|
.append("MediaRoute2Info{ ")
|
||
|
.append("id=")
|
||
|
.append(getId())
|
||
|
.append(", name=")
|
||
|
.append(getName())
|
||
|
.append(", type=")
|
||
|
.append(getDeviceTypeString(getType()))
|
||
|
.append(", isSystem=")
|
||
|
.append(isSystemRoute())
|
||
|
.append(", features=")
|
||
|
.append(getFeatures())
|
||
|
.append(", iconUri=")
|
||
|
.append(getIconUri())
|
||
|
.append(", description=")
|
||
|
.append(getDescription())
|
||
|
.append(", connectionState=")
|
||
|
.append(getConnectionState())
|
||
|
.append(", clientPackageName=")
|
||
|
.append(getClientPackageName())
|
||
|
.append(", volumeHandling=")
|
||
|
.append(getVolumeHandling())
|
||
|
.append(", volumeMax=")
|
||
|
.append(getVolumeMax())
|
||
|
.append(", volume=")
|
||
|
.append(getVolume())
|
||
|
.append(", address=")
|
||
|
.append(getAddress())
|
||
|
.append(", deduplicationIds=")
|
||
|
.append(String.join(",", getDeduplicationIds()))
|
||
|
.append(", providerId=")
|
||
|
.append(getProviderId())
|
||
|
.append(", isVisibilityRestricted=")
|
||
|
.append(mIsVisibilityRestricted)
|
||
|
.append(", allowedPackages=")
|
||
|
.append(String.join(",", mAllowedPackages))
|
||
|
.append(", suitabilityStatus=")
|
||
|
.append(mSuitabilityStatus)
|
||
|
.append(" }");
|
||
|
return result.toString();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int describeContents() {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||
|
dest.writeString(mId);
|
||
|
TextUtils.writeToParcel(mName, dest, flags);
|
||
|
dest.writeStringList(mFeatures);
|
||
|
dest.writeInt(mType);
|
||
|
dest.writeBoolean(mIsSystem);
|
||
|
dest.writeParcelable(mIconUri, flags);
|
||
|
TextUtils.writeToParcel(mDescription, dest, flags);
|
||
|
dest.writeInt(mConnectionState);
|
||
|
dest.writeString(mClientPackageName);
|
||
|
dest.writeString(mPackageName);
|
||
|
dest.writeInt(mVolumeHandling);
|
||
|
dest.writeInt(mVolumeMax);
|
||
|
dest.writeInt(mVolume);
|
||
|
dest.writeString(mAddress);
|
||
|
dest.writeStringArray(mDeduplicationIds.toArray(new String[mDeduplicationIds.size()]));
|
||
|
dest.writeBundle(mExtras);
|
||
|
dest.writeString(mProviderId);
|
||
|
dest.writeBoolean(mIsVisibilityRestricted);
|
||
|
dest.writeString8Array(mAllowedPackages.toArray(new String[0]));
|
||
|
dest.writeInt(mSuitabilityStatus);
|
||
|
}
|
||
|
|
||
|
private static String getDeviceTypeString(@Type int deviceType) {
|
||
|
switch (deviceType) {
|
||
|
case TYPE_BUILTIN_SPEAKER:
|
||
|
return "BUILTIN_SPEAKER";
|
||
|
case TYPE_WIRED_HEADSET:
|
||
|
return "WIRED_HEADSET";
|
||
|
case TYPE_WIRED_HEADPHONES:
|
||
|
return "WIRED_HEADPHONES";
|
||
|
case TYPE_BLUETOOTH_A2DP:
|
||
|
return "BLUETOOTH_A2DP";
|
||
|
case TYPE_HDMI:
|
||
|
return "HDMI";
|
||
|
case TYPE_HDMI_ARC:
|
||
|
return "HDMI_ARC";
|
||
|
case TYPE_HDMI_EARC:
|
||
|
return "HDMI_EARC";
|
||
|
case TYPE_DOCK:
|
||
|
return "DOCK";
|
||
|
case TYPE_USB_DEVICE:
|
||
|
return "USB_DEVICE";
|
||
|
case TYPE_USB_ACCESSORY:
|
||
|
return "USB_ACCESSORY";
|
||
|
case TYPE_USB_HEADSET:
|
||
|
return "USB_HEADSET";
|
||
|
case TYPE_HEARING_AID:
|
||
|
return "HEARING_AID";
|
||
|
case TYPE_REMOTE_TV:
|
||
|
return "REMOTE_TV";
|
||
|
case TYPE_REMOTE_SPEAKER:
|
||
|
return "REMOTE_SPEAKER";
|
||
|
case TYPE_REMOTE_AUDIO_VIDEO_RECEIVER:
|
||
|
return "REMOTE_AUDIO_VIDEO_RECEIVER";
|
||
|
case TYPE_REMOTE_TABLET:
|
||
|
return "REMOTE_TABLET";
|
||
|
case TYPE_REMOTE_TABLET_DOCKED:
|
||
|
return "REMOTE_TABLET_DOCKED";
|
||
|
case TYPE_REMOTE_COMPUTER:
|
||
|
return "REMOTE_COMPUTER";
|
||
|
case TYPE_REMOTE_GAME_CONSOLE:
|
||
|
return "REMOTE_GAME_CONSOLE";
|
||
|
case TYPE_REMOTE_CAR:
|
||
|
return "REMOTE_CAR";
|
||
|
case TYPE_REMOTE_SMARTWATCH:
|
||
|
return "REMOTE_SMARTWATCH";
|
||
|
case TYPE_REMOTE_SMARTPHONE:
|
||
|
return "REMOTE_SMARTPHONE";
|
||
|
case TYPE_GROUP:
|
||
|
return "GROUP";
|
||
|
case TYPE_UNKNOWN:
|
||
|
default:
|
||
|
return TextUtils.formatSimple("UNKNOWN(%d)", deviceType);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Builder for {@link MediaRoute2Info media route info}.
|
||
|
*/
|
||
|
public static final class Builder {
|
||
|
private final String mId;
|
||
|
private final CharSequence mName;
|
||
|
private final List<String> mFeatures;
|
||
|
|
||
|
@Type
|
||
|
private int mType = TYPE_UNKNOWN;
|
||
|
private boolean mIsSystem;
|
||
|
private Uri mIconUri;
|
||
|
private CharSequence mDescription;
|
||
|
@ConnectionState
|
||
|
private int mConnectionState;
|
||
|
private String mClientPackageName;
|
||
|
private String mPackageName;
|
||
|
private int mVolumeHandling = PLAYBACK_VOLUME_FIXED;
|
||
|
private int mVolumeMax;
|
||
|
private int mVolume;
|
||
|
private String mAddress;
|
||
|
private Set<String> mDeduplicationIds;
|
||
|
private Bundle mExtras;
|
||
|
private String mProviderId;
|
||
|
private boolean mIsVisibilityRestricted;
|
||
|
private Set<String> mAllowedPackages;
|
||
|
@SuitabilityStatus private int mSuitabilityStatus;
|
||
|
|
||
|
/**
|
||
|
* Constructor for builder to create {@link MediaRoute2Info}.
|
||
|
* <p>
|
||
|
* In order to ensure ID uniqueness, the {@link MediaRoute2Info#getId() ID} of a route info
|
||
|
* obtained from {@link MediaRouter2} can be different from what was set in
|
||
|
* {@link MediaRoute2ProviderService}.
|
||
|
* </p>
|
||
|
* @param id The ID of the route. Must not be empty.
|
||
|
* @param name The user-visible name of the route.
|
||
|
*/
|
||
|
public Builder(@NonNull String id, @NonNull CharSequence name) {
|
||
|
if (TextUtils.isEmpty(id)) {
|
||
|
throw new IllegalArgumentException("id must not be empty");
|
||
|
}
|
||
|
if (TextUtils.isEmpty(name)) {
|
||
|
throw new IllegalArgumentException("name must not be empty");
|
||
|
}
|
||
|
mId = id;
|
||
|
mName = name;
|
||
|
mFeatures = new ArrayList<>();
|
||
|
mDeduplicationIds = Set.of();
|
||
|
mAllowedPackages = Set.of();
|
||
|
mSuitabilityStatus = SUITABILITY_STATUS_SUITABLE_FOR_DEFAULT_TRANSFER;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Constructor for builder to create {@link MediaRoute2Info} with existing
|
||
|
* {@link MediaRoute2Info} instance.
|
||
|
*
|
||
|
* @param routeInfo the existing instance to copy data from.
|
||
|
*/
|
||
|
public Builder(@NonNull MediaRoute2Info routeInfo) {
|
||
|
this(routeInfo.mId, routeInfo);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Constructor for builder to create {@link MediaRoute2Info} with existing
|
||
|
* {@link MediaRoute2Info} instance and replace ID with the given {@code id}.
|
||
|
*
|
||
|
* @param id The ID of the new route. Must not be empty.
|
||
|
* @param routeInfo the existing instance to copy data from.
|
||
|
* @hide
|
||
|
*/
|
||
|
public Builder(@NonNull String id, @NonNull MediaRoute2Info routeInfo) {
|
||
|
if (TextUtils.isEmpty(id)) {
|
||
|
throw new IllegalArgumentException("id must not be empty");
|
||
|
}
|
||
|
Objects.requireNonNull(routeInfo, "routeInfo must not be null");
|
||
|
|
||
|
mId = id;
|
||
|
mName = routeInfo.mName;
|
||
|
mFeatures = new ArrayList<>(routeInfo.mFeatures);
|
||
|
mType = routeInfo.mType;
|
||
|
mIsSystem = routeInfo.mIsSystem;
|
||
|
mIconUri = routeInfo.mIconUri;
|
||
|
mDescription = routeInfo.mDescription;
|
||
|
mConnectionState = routeInfo.mConnectionState;
|
||
|
mClientPackageName = routeInfo.mClientPackageName;
|
||
|
mPackageName = routeInfo.mPackageName;
|
||
|
mVolumeHandling = routeInfo.mVolumeHandling;
|
||
|
mVolumeMax = routeInfo.mVolumeMax;
|
||
|
mVolume = routeInfo.mVolume;
|
||
|
mAddress = routeInfo.mAddress;
|
||
|
mDeduplicationIds = Set.copyOf(routeInfo.mDeduplicationIds);
|
||
|
if (routeInfo.mExtras != null) {
|
||
|
mExtras = new Bundle(routeInfo.mExtras);
|
||
|
}
|
||
|
mProviderId = routeInfo.mProviderId;
|
||
|
mIsVisibilityRestricted = routeInfo.mIsVisibilityRestricted;
|
||
|
mAllowedPackages = routeInfo.mAllowedPackages;
|
||
|
mSuitabilityStatus = routeInfo.mSuitabilityStatus;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Adds a feature for the route.
|
||
|
* @param feature a feature that the route has. May be one of predefined features
|
||
|
* such as {@link #FEATURE_LIVE_AUDIO}, {@link #FEATURE_LIVE_VIDEO} or
|
||
|
* {@link #FEATURE_REMOTE_PLAYBACK} or a custom feature defined by
|
||
|
* a provider.
|
||
|
*
|
||
|
* @see #addFeatures(Collection)
|
||
|
*/
|
||
|
@NonNull
|
||
|
public Builder addFeature(@NonNull String feature) {
|
||
|
if (TextUtils.isEmpty(feature)) {
|
||
|
throw new IllegalArgumentException("feature must not be null or empty");
|
||
|
}
|
||
|
mFeatures.add(feature);
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Adds features for the route. A route must support at least one route type.
|
||
|
* @param features features that the route has. May include predefined features
|
||
|
* such as {@link #FEATURE_LIVE_AUDIO}, {@link #FEATURE_LIVE_VIDEO} or
|
||
|
* {@link #FEATURE_REMOTE_PLAYBACK} or custom features defined by
|
||
|
* a provider.
|
||
|
*
|
||
|
* @see #addFeature(String)
|
||
|
*/
|
||
|
@NonNull
|
||
|
public Builder addFeatures(@NonNull Collection<String> features) {
|
||
|
Objects.requireNonNull(features, "features must not be null");
|
||
|
for (String feature : features) {
|
||
|
addFeature(feature);
|
||
|
}
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Clears the features of the route. A route must support at least one route type.
|
||
|
*/
|
||
|
@NonNull
|
||
|
public Builder clearFeatures() {
|
||
|
mFeatures.clear();
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the route's type.
|
||
|
*
|
||
|
* @see MediaRoute2Info#getType()
|
||
|
*/
|
||
|
@NonNull
|
||
|
public Builder setType(@Type int type) {
|
||
|
mType = type;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets whether the route is a system route or not.
|
||
|
* @hide
|
||
|
*/
|
||
|
@NonNull
|
||
|
public Builder setSystemRoute(boolean isSystem) {
|
||
|
mIsSystem = isSystem;
|
||
|
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 user-visible description of the route.
|
||
|
*/
|
||
|
@NonNull
|
||
|
public Builder setDescription(@Nullable CharSequence description) {
|
||
|
mDescription = description;
|
||
|
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 package name of the app using the route.
|
||
|
*/
|
||
|
@NonNull
|
||
|
public Builder setClientPackageName(@Nullable String packageName) {
|
||
|
mClientPackageName = packageName;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the package name of the route.
|
||
|
* @hide
|
||
|
*/
|
||
|
@NonNull
|
||
|
public Builder setPackageName(@NonNull String packageName) {
|
||
|
mPackageName = packageName;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the route's volume handling.
|
||
|
*/
|
||
|
@NonNull
|
||
|
public Builder setVolumeHandling(@PlaybackVolume int volumeHandling) {
|
||
|
mVolumeHandling = volumeHandling;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the route's maximum volume, or 0 if unknown.
|
||
|
*/
|
||
|
@NonNull
|
||
|
public Builder setVolumeMax(int volumeMax) {
|
||
|
mVolumeMax = volumeMax;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the route's current volume, or 0 if unknown.
|
||
|
*/
|
||
|
@NonNull
|
||
|
public Builder setVolume(int volume) {
|
||
|
mVolume = volume;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the hardware address of the route.
|
||
|
* @hide
|
||
|
*/
|
||
|
@NonNull
|
||
|
public Builder setAddress(String address) {
|
||
|
mAddress = address;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the {@link MediaRoute2Info#getDeduplicationIds() deduplication IDs} of the route.
|
||
|
*/
|
||
|
@NonNull
|
||
|
public Builder setDeduplicationIds(@NonNull Set<String> id) {
|
||
|
mDeduplicationIds = Set.copyOf(id);
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets a bundle of extras for the route.
|
||
|
* <p>
|
||
|
* Note: The extras will not affect the result of {@link MediaRoute2Info#equals(Object)}.
|
||
|
*/
|
||
|
@NonNull
|
||
|
public Builder setExtras(@Nullable Bundle extras) {
|
||
|
if (extras == null) {
|
||
|
mExtras = null;
|
||
|
return this;
|
||
|
}
|
||
|
mExtras = new Bundle(extras);
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the provider id of the route.
|
||
|
* @hide
|
||
|
*/
|
||
|
@NonNull
|
||
|
public Builder setProviderId(@NonNull String providerId) {
|
||
|
if (TextUtils.isEmpty(providerId)) {
|
||
|
throw new IllegalArgumentException("providerId must not be null or empty");
|
||
|
}
|
||
|
mProviderId = providerId;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the visibility of this route to public.
|
||
|
*
|
||
|
* <p>By default, unless you call {@link #setVisibilityRestricted}, the new route will be
|
||
|
* public.
|
||
|
*
|
||
|
* <p>Public routes are visible to any application with a matching {@link
|
||
|
* RouteDiscoveryPreference#getPreferredFeatures feature}.
|
||
|
*
|
||
|
* <p>Calls to this method override previous calls to {@link #setVisibilityPublic} and
|
||
|
* {@link #setVisibilityRestricted}.
|
||
|
*/
|
||
|
@NonNull
|
||
|
public Builder setVisibilityPublic() {
|
||
|
mIsVisibilityRestricted = false;
|
||
|
mAllowedPackages = Set.of();
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the visibility of this route to restricted.
|
||
|
*
|
||
|
* <p>Routes with restricted visibility are only visible to its publisher application and
|
||
|
* applications whose package name is included in the provided {@code allowedPackages} set
|
||
|
* with a matching {@link RouteDiscoveryPreference#getPreferredFeatures feature}.
|
||
|
*
|
||
|
* <p>Calls to this method override previous calls to {@link #setVisibilityPublic} and
|
||
|
* {@link #setVisibilityRestricted}.
|
||
|
*
|
||
|
* @see #setVisibilityPublic
|
||
|
* @param allowedPackages set of package names which are allowed to see this route.
|
||
|
*/
|
||
|
@NonNull
|
||
|
public Builder setVisibilityRestricted(@NonNull Set<String> allowedPackages) {
|
||
|
mIsVisibilityRestricted = true;
|
||
|
mAllowedPackages = Set.copyOf(allowedPackages);
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets route suitability status.
|
||
|
*
|
||
|
* <p>The default value is {@link
|
||
|
* MediaRoute2Info#SUITABILITY_STATUS_SUITABLE_FOR_DEFAULT_TRANSFER}.
|
||
|
*
|
||
|
* <p> Apps are not supposed to set {@link
|
||
|
* MediaRoute2Info#SUITABILITY_STATUS_NOT_SUITABLE_FOR_TRANSFER}. Publishing a non-system
|
||
|
* route with such status throws {@link SecurityException}.
|
||
|
*/
|
||
|
@NonNull
|
||
|
@FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
|
||
|
public Builder setSuitabilityStatus(@SuitabilityStatus int suitabilityStatus) {
|
||
|
mSuitabilityStatus = suitabilityStatus;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Builds the {@link MediaRoute2Info media route info}.
|
||
|
*
|
||
|
* @throws IllegalArgumentException if no features are added.
|
||
|
*/
|
||
|
@NonNull
|
||
|
public MediaRoute2Info build() {
|
||
|
if (mFeatures.isEmpty()) {
|
||
|
throw new IllegalArgumentException("features must not be empty!");
|
||
|
}
|
||
|
return new MediaRoute2Info(this);
|
||
|
}
|
||
|
}
|
||
|
}
|