Merge "Add a platform library for remote display providers." into klp-dev
This commit is contained in:
@@ -255,6 +255,8 @@ LOCAL_SRC_FILES += \
|
|||||||
media/java/android/media/IMediaScannerService.aidl \
|
media/java/android/media/IMediaScannerService.aidl \
|
||||||
media/java/android/media/IRemoteControlClient.aidl \
|
media/java/android/media/IRemoteControlClient.aidl \
|
||||||
media/java/android/media/IRemoteControlDisplay.aidl \
|
media/java/android/media/IRemoteControlDisplay.aidl \
|
||||||
|
media/java/android/media/IRemoteDisplayCallback.aidl \
|
||||||
|
media/java/android/media/IRemoteDisplayProvider.aidl \
|
||||||
media/java/android/media/IRemoteVolumeObserver.aidl \
|
media/java/android/media/IRemoteVolumeObserver.aidl \
|
||||||
media/java/android/media/IRingtonePlayer.aidl \
|
media/java/android/media/IRingtonePlayer.aidl \
|
||||||
telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl \
|
telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl \
|
||||||
|
|||||||
@@ -1992,6 +1992,14 @@
|
|||||||
android:description="@string/permdesc_bindWallpaper"
|
android:description="@string/permdesc_bindWallpaper"
|
||||||
android:protectionLevel="signature|system" />
|
android:protectionLevel="signature|system" />
|
||||||
|
|
||||||
|
<!-- Must be required by a {@link com.android.media.remotedisplay.RemoteDisplayProvider},
|
||||||
|
to ensure that only the system can bind to it.
|
||||||
|
@hide -->
|
||||||
|
<permission android:name="android.permission.BIND_REMOTE_DISPLAY"
|
||||||
|
android:label="@string/permlab_bindRemoteDisplay"
|
||||||
|
android:description="@string/permdesc_bindRemoteDisplay"
|
||||||
|
android:protectionLevel="signature" />
|
||||||
|
|
||||||
<!-- Must be required by device administration receiver, to ensure that only the
|
<!-- Must be required by device administration receiver, to ensure that only the
|
||||||
system can interact with it. -->
|
system can interact with it. -->
|
||||||
<permission android:name="android.permission.BIND_DEVICE_ADMIN"
|
<permission android:name="android.permission.BIND_DEVICE_ADMIN"
|
||||||
|
|||||||
@@ -1051,6 +1051,12 @@
|
|||||||
<string name="permdesc_bindWallpaper">Allows the holder to bind to the top-level
|
<string name="permdesc_bindWallpaper">Allows the holder to bind to the top-level
|
||||||
interface of a wallpaper. Should never be needed for normal apps.</string>
|
interface of a wallpaper. Should never be needed for normal apps.</string>
|
||||||
|
|
||||||
|
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
|
||||||
|
<string name="permlab_bindRemoteDisplay">bind to a remote display</string>
|
||||||
|
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
|
||||||
|
<string name="permdesc_bindRemoteDisplay">Allows the holder to bind to the top-level
|
||||||
|
interface of a remote display. Should never be needed for normal apps.</string>
|
||||||
|
|
||||||
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
|
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
|
||||||
<string name="permlab_bindRemoteViews">bind to a widget service</string>
|
<string name="permlab_bindRemoteViews">bind to a widget service</string>
|
||||||
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
|
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
|
||||||
|
|||||||
26
media/java/android/media/IRemoteDisplayCallback.aidl
Normal file
26
media/java/android/media/IRemoteDisplayCallback.aidl
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013 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 android.media.RemoteDisplayState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@hide}
|
||||||
|
*/
|
||||||
|
oneway interface IRemoteDisplayCallback {
|
||||||
|
void onStateChanged(in RemoteDisplayState state);
|
||||||
|
}
|
||||||
31
media/java/android/media/IRemoteDisplayProvider.aidl
Normal file
31
media/java/android/media/IRemoteDisplayProvider.aidl
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013 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 android.media.IRemoteDisplayCallback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@hide}
|
||||||
|
*/
|
||||||
|
oneway interface IRemoteDisplayProvider {
|
||||||
|
void setCallback(in IRemoteDisplayCallback callback);
|
||||||
|
void setDiscoveryMode(int mode);
|
||||||
|
void connect(String id);
|
||||||
|
void disconnect(String id);
|
||||||
|
void setVolume(String id, int volume);
|
||||||
|
void adjustVolume(String id, int delta);
|
||||||
|
}
|
||||||
18
media/java/android/media/RemoteDisplayState.aidl
Normal file
18
media/java/android/media/RemoteDisplayState.aidl
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/* Copyright 2013, 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;
|
||||||
|
|
||||||
|
parcelable RemoteDisplayState;
|
||||||
189
media/java/android/media/RemoteDisplayState.java
Normal file
189
media/java/android/media/RemoteDisplayState.java
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013 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 android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information available from IRemoteDisplayProvider about available remote displays.
|
||||||
|
*
|
||||||
|
* Clients must not modify the contents of this object.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public final class RemoteDisplayState implements Parcelable {
|
||||||
|
// Note: These constants are used by the remote display provider API.
|
||||||
|
// Do not change them!
|
||||||
|
public static final String SERVICE_INTERFACE =
|
||||||
|
"com.android.media.remotedisplay.RemoteDisplayProvider";
|
||||||
|
public static final int DISCOVERY_MODE_NONE = 0;
|
||||||
|
public static final int DISCOVERY_MODE_PASSIVE = 1;
|
||||||
|
public static final int DISCOVERY_MODE_ACTIVE = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of all remote displays.
|
||||||
|
*/
|
||||||
|
public final ArrayList<RemoteDisplayInfo> displays;
|
||||||
|
|
||||||
|
public RemoteDisplayState() {
|
||||||
|
displays = new ArrayList<RemoteDisplayInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoteDisplayState(Parcel src) {
|
||||||
|
displays = src.createTypedArrayList(RemoteDisplayInfo.CREATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isValid() {
|
||||||
|
if (displays == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final int count = displays.size();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
if (!displays.get(i).isValid()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeTypedList(displays);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Parcelable.Creator<RemoteDisplayState> CREATOR =
|
||||||
|
new Parcelable.Creator<RemoteDisplayState>() {
|
||||||
|
@Override
|
||||||
|
public RemoteDisplayState createFromParcel(Parcel in) {
|
||||||
|
return new RemoteDisplayState(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RemoteDisplayState[] newArray(int size) {
|
||||||
|
return new RemoteDisplayState[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final class RemoteDisplayInfo implements Parcelable {
|
||||||
|
// Note: These constants are used by the remote display provider API.
|
||||||
|
// Do not change them!
|
||||||
|
public static final int STATUS_NOT_AVAILABLE = 0;
|
||||||
|
public static final int STATUS_IN_USE = 1;
|
||||||
|
public static final int STATUS_AVAILABLE = 2;
|
||||||
|
public static final int STATUS_CONNECTING = 3;
|
||||||
|
public static final int STATUS_CONNECTED = 4;
|
||||||
|
|
||||||
|
public static final int PLAYBACK_VOLUME_VARIABLE =
|
||||||
|
MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE;
|
||||||
|
public static final int PLAYBACK_VOLUME_FIXED =
|
||||||
|
MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED;
|
||||||
|
|
||||||
|
public String id;
|
||||||
|
public String name;
|
||||||
|
public String description;
|
||||||
|
public int status;
|
||||||
|
public int volume;
|
||||||
|
public int volumeMax;
|
||||||
|
public int volumeHandling;
|
||||||
|
public int presentationDisplayId;
|
||||||
|
|
||||||
|
public RemoteDisplayInfo(String id) {
|
||||||
|
this.id = id;
|
||||||
|
status = STATUS_NOT_AVAILABLE;
|
||||||
|
volumeHandling = MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED;
|
||||||
|
presentationDisplayId = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RemoteDisplayInfo(RemoteDisplayInfo other) {
|
||||||
|
id = other.id;
|
||||||
|
name = other.name;
|
||||||
|
description = other.description;
|
||||||
|
status = other.status;
|
||||||
|
volume = other.volume;
|
||||||
|
volumeMax = other.volumeMax;
|
||||||
|
volumeHandling = other.volumeHandling;
|
||||||
|
presentationDisplayId = other.presentationDisplayId;
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoteDisplayInfo(Parcel in) {
|
||||||
|
id = in.readString();
|
||||||
|
name = in.readString();
|
||||||
|
description = in.readString();
|
||||||
|
status = in.readInt();
|
||||||
|
volume = in.readInt();
|
||||||
|
volumeMax = in.readInt();
|
||||||
|
volumeHandling = in.readInt();
|
||||||
|
presentationDisplayId = in.readInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isValid() {
|
||||||
|
return !TextUtils.isEmpty(id) && !TextUtils.isEmpty(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeString(id);
|
||||||
|
dest.writeString(name);
|
||||||
|
dest.writeString(description);
|
||||||
|
dest.writeInt(status);
|
||||||
|
dest.writeInt(volume);
|
||||||
|
dest.writeInt(volumeMax);
|
||||||
|
dest.writeInt(volumeHandling);
|
||||||
|
dest.writeInt(presentationDisplayId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "RemoteDisplayInfo{ id=" + id
|
||||||
|
+ ", name=" + name
|
||||||
|
+ ", description=" + description
|
||||||
|
+ ", status=" + status
|
||||||
|
+ ", volume=" + volume
|
||||||
|
+ ", volumeMax=" + volumeMax
|
||||||
|
+ ", volumeHandling=" + volumeHandling
|
||||||
|
+ ", presentationDisplayId=" + presentationDisplayId
|
||||||
|
+ " }";
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("hiding")
|
||||||
|
public static final Parcelable.Creator<RemoteDisplayInfo> CREATOR =
|
||||||
|
new Parcelable.Creator<RemoteDisplayInfo>() {
|
||||||
|
@Override
|
||||||
|
public RemoteDisplayInfo createFromParcel(Parcel in) {
|
||||||
|
return new RemoteDisplayInfo(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RemoteDisplayInfo[] newArray(int size) {
|
||||||
|
return new RemoteDisplayInfo[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
46
media/lib/Android.mk
Normal file
46
media/lib/Android.mk
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#
|
||||||
|
# Copyright (C) 2013 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.
|
||||||
|
#
|
||||||
|
LOCAL_PATH := $(call my-dir)
|
||||||
|
|
||||||
|
# the library
|
||||||
|
# ============================================================
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_MODULE:= com.android.media.remotedisplay
|
||||||
|
LOCAL_MODULE_TAGS := optional
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES := \
|
||||||
|
$(call all-subdir-java-files) \
|
||||||
|
$(call all-aidl-files-under, java)
|
||||||
|
|
||||||
|
include $(BUILD_JAVA_LIBRARY)
|
||||||
|
|
||||||
|
|
||||||
|
# ==== com.android.media.remotedisplay.xml lib def ========================
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_MODULE := com.android.media.remotedisplay.xml
|
||||||
|
LOCAL_MODULE_TAGS := optional
|
||||||
|
|
||||||
|
LOCAL_MODULE_CLASS := ETC
|
||||||
|
|
||||||
|
# This will install the file in /system/etc/permissions
|
||||||
|
#
|
||||||
|
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES := $(LOCAL_MODULE)
|
||||||
|
|
||||||
|
include $(BUILD_PREBUILT)
|
||||||
28
media/lib/README.txt
Normal file
28
media/lib/README.txt
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
This library (com.android.media.remotedisplay.jar) is a shared java library
|
||||||
|
containing classes required by unbundled remote display providers.
|
||||||
|
|
||||||
|
--- Rules of this library ---
|
||||||
|
o This library is effectively a PUBLIC API for unbundled remote display providers
|
||||||
|
that may be distributed outside the system image. So it MUST BE API STABLE.
|
||||||
|
You can add but not remove. The rules are the same as for the
|
||||||
|
public platform SDK API.
|
||||||
|
o This library can see and instantiate internal platform classes, but it must not
|
||||||
|
expose them in any public method (or by extending them via inheritance). This would
|
||||||
|
break clients of the library because they cannot see the internal platform classes.
|
||||||
|
|
||||||
|
This library is distributed in the system image, and loaded as
|
||||||
|
a shared library. So you can change the implementation, but not
|
||||||
|
the interface. In this way it is like framework.jar.
|
||||||
|
|
||||||
|
--- Why does this library exists? ---
|
||||||
|
|
||||||
|
Unbundled remote display providers (such as Cast) cannot use internal
|
||||||
|
platform classes.
|
||||||
|
|
||||||
|
This library will eventually be replaced when the media route provider
|
||||||
|
infrastructure that is currently defined in the support library is reintegrated
|
||||||
|
with the framework in a new API. That API isn't ready yet so this
|
||||||
|
library is a compromise to make new capabilities available to the system
|
||||||
|
without exposing the full surface area of the support library media
|
||||||
|
route provider protocol.
|
||||||
|
|
||||||
20
media/lib/com.android.media.remotedisplay.xml
Normal file
20
media/lib/com.android.media.remotedisplay.xml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2013 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<permissions>
|
||||||
|
<library name="com.android.media.remotedisplay"
|
||||||
|
file="/system/framework/com.android.media.remotedisplay.jar" />
|
||||||
|
</permissions>
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013 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 com.android.media.remotedisplay;
|
||||||
|
|
||||||
|
import com.android.internal.util.Objects;
|
||||||
|
|
||||||
|
import android.media.MediaRouter;
|
||||||
|
import android.media.RemoteDisplayState.RemoteDisplayInfo;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a remote display that has been discovered.
|
||||||
|
*/
|
||||||
|
public class RemoteDisplay {
|
||||||
|
private final RemoteDisplayInfo mMutableInfo;
|
||||||
|
private RemoteDisplayInfo mImmutableInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Status code: Indicates that the remote display is not available.
|
||||||
|
*/
|
||||||
|
public static final int STATUS_NOT_AVAILABLE = RemoteDisplayInfo.STATUS_NOT_AVAILABLE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Status code: Indicates that the remote display is in use by someone else.
|
||||||
|
*/
|
||||||
|
public static final int STATUS_IN_USE = RemoteDisplayInfo.STATUS_IN_USE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Status code: Indicates that the remote display is available for new connections.
|
||||||
|
*/
|
||||||
|
public static final int STATUS_AVAILABLE = RemoteDisplayInfo.STATUS_AVAILABLE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Status code: Indicates that the remote display is current connecting.
|
||||||
|
*/
|
||||||
|
public static final int STATUS_CONNECTING = RemoteDisplayInfo.STATUS_CONNECTING;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Status code: Indicates that the remote display is connected and is mirroring
|
||||||
|
* display contents.
|
||||||
|
*/
|
||||||
|
public static final int STATUS_CONNECTED = RemoteDisplayInfo.STATUS_CONNECTED;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Volume handling: Output volume can be changed.
|
||||||
|
*/
|
||||||
|
public static final int PLAYBACK_VOLUME_VARIABLE =
|
||||||
|
RemoteDisplayInfo.PLAYBACK_VOLUME_VARIABLE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Volume handling: Output volume is fixed.
|
||||||
|
*/
|
||||||
|
public static final int PLAYBACK_VOLUME_FIXED =
|
||||||
|
RemoteDisplayInfo.PLAYBACK_VOLUME_FIXED;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a remote display with the specified name and id.
|
||||||
|
*/
|
||||||
|
public RemoteDisplay(String id, String name) {
|
||||||
|
if (TextUtils.isEmpty(id)) {
|
||||||
|
throw new IllegalArgumentException("id must not be null or empty");
|
||||||
|
}
|
||||||
|
mMutableInfo = new RemoteDisplayInfo(id);
|
||||||
|
setName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return mMutableInfo.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return mMutableInfo.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
if (!Objects.equal(mMutableInfo.name, name)) {
|
||||||
|
mMutableInfo.name = name;
|
||||||
|
mImmutableInfo = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return mMutableInfo.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
if (!Objects.equal(mMutableInfo.description, description)) {
|
||||||
|
mMutableInfo.description = description;
|
||||||
|
mImmutableInfo = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStatus() {
|
||||||
|
return mMutableInfo.status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(int status) {
|
||||||
|
if (mMutableInfo.status != status) {
|
||||||
|
mMutableInfo.status = status;
|
||||||
|
mImmutableInfo = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getVolume() {
|
||||||
|
return mMutableInfo.volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVolume(int volume) {
|
||||||
|
if (mMutableInfo.volume != volume) {
|
||||||
|
mMutableInfo.volume = volume;
|
||||||
|
mImmutableInfo = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getVolumeMax() {
|
||||||
|
return mMutableInfo.volumeMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVolumeMax(int volumeMax) {
|
||||||
|
if (mMutableInfo.volumeMax != volumeMax) {
|
||||||
|
mMutableInfo.volumeMax = volumeMax;
|
||||||
|
mImmutableInfo = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getVolumeHandling() {
|
||||||
|
return mMutableInfo.volumeHandling;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVolumeHandling(int volumeHandling) {
|
||||||
|
if (mMutableInfo.volumeHandling != volumeHandling) {
|
||||||
|
mMutableInfo.volumeHandling = volumeHandling;
|
||||||
|
mImmutableInfo = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPresentationDisplayId() {
|
||||||
|
return mMutableInfo.presentationDisplayId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPresentationDisplayId(int presentationDisplayId) {
|
||||||
|
if (mMutableInfo.presentationDisplayId != presentationDisplayId) {
|
||||||
|
mMutableInfo.presentationDisplayId = presentationDisplayId;
|
||||||
|
mImmutableInfo = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "RemoteDisplay{" + mMutableInfo.toString() + "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoteDisplayInfo getInfo() {
|
||||||
|
if (mImmutableInfo == null) {
|
||||||
|
mImmutableInfo = new RemoteDisplayInfo(mMutableInfo);
|
||||||
|
}
|
||||||
|
return mImmutableInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,371 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013 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 com.android.media.remotedisplay;
|
||||||
|
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.media.IRemoteDisplayCallback;
|
||||||
|
import android.media.IRemoteDisplayProvider;
|
||||||
|
import android.media.RemoteDisplayState;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.util.ArrayMap;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for remote display providers implemented as unbundled services.
|
||||||
|
* <p>
|
||||||
|
* To implement your remote display provider service, create a subclass of
|
||||||
|
* {@link Service} and override the {@link Service#onBind Service.onBind()} method
|
||||||
|
* to return the provider's binder when the {@link #SERVICE_INTERFACE} is requested.
|
||||||
|
* </p>
|
||||||
|
* <pre>
|
||||||
|
* public class SampleRemoteDisplayProviderService extends Service {
|
||||||
|
* private SampleProvider mProvider;
|
||||||
|
*
|
||||||
|
* public IBinder onBind(Intent intent) {
|
||||||
|
* if (intent.getAction().equals(RemoteDisplayProvider.SERVICE_INTERFACE)) {
|
||||||
|
* if (mProvider == null) {
|
||||||
|
* mProvider = new SampleProvider(this);
|
||||||
|
* }
|
||||||
|
* return mProvider.getBinder();
|
||||||
|
* }
|
||||||
|
* return null;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* class SampleProvider extends RemoteDisplayProvider {
|
||||||
|
* public SampleProvider() {
|
||||||
|
* super(SampleRemoteDisplayProviderService.this);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* // --- Implementation goes here ---
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* Declare your remote display provider service in your application manifest
|
||||||
|
* like this:
|
||||||
|
* </p>
|
||||||
|
* <pre>
|
||||||
|
* <application>
|
||||||
|
* <uses-library android:name="com.android.media.remotedisplay" />
|
||||||
|
*
|
||||||
|
* <service android:name=".SampleRemoteDisplayProviderService"
|
||||||
|
* android:label="@string/sample_remote_display_provider_service"
|
||||||
|
* android:exported="true"
|
||||||
|
* android:permission="android.permission.BIND_REMOTE_DISPLAY">
|
||||||
|
* <intent-filter>
|
||||||
|
* <action android:name="com.android.media.remotedisplay.RemoteDisplayProvider" />
|
||||||
|
* </intent-filter>
|
||||||
|
* </service>
|
||||||
|
* </application>
|
||||||
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* This object is not thread safe. It is only intended to be accessed on the
|
||||||
|
* {@link Context#getMainLooper main looper thread} of an application.
|
||||||
|
* </p><p>
|
||||||
|
* IMPORTANT: This class is effectively a public API for unbundled applications, and
|
||||||
|
* must remain API stable. See README.txt in the root of this package for more information.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public abstract class RemoteDisplayProvider {
|
||||||
|
private static final int MSG_SET_CALLBACK = 1;
|
||||||
|
private static final int MSG_SET_DISCOVERY_MODE = 2;
|
||||||
|
private static final int MSG_CONNECT = 3;
|
||||||
|
private static final int MSG_DISCONNECT = 4;
|
||||||
|
private static final int MSG_SET_VOLUME = 5;
|
||||||
|
private static final int MSG_ADJUST_VOLUME = 6;
|
||||||
|
|
||||||
|
private final ProviderStub mStub;
|
||||||
|
private final ProviderHandler mHandler;
|
||||||
|
private final ArrayMap<String, RemoteDisplay> mDisplays =
|
||||||
|
new ArrayMap<String, RemoteDisplay>();
|
||||||
|
private IRemoteDisplayCallback mCallback;
|
||||||
|
private int mDiscoveryMode = DISCOVERY_MODE_NONE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link Intent} that must be declared as handled by the service.
|
||||||
|
* Put this in your manifest.
|
||||||
|
*/
|
||||||
|
public static final String SERVICE_INTERFACE = RemoteDisplayState.SERVICE_INTERFACE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discovery mode: Do not perform any discovery.
|
||||||
|
*/
|
||||||
|
public static final int DISCOVERY_MODE_NONE = RemoteDisplayState.DISCOVERY_MODE_NONE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discovery mode: Passive or low-power periodic discovery.
|
||||||
|
* <p>
|
||||||
|
* This mode indicates that an application is interested in knowing whether there
|
||||||
|
* are any remote displays paired or available but doesn't need the latest or
|
||||||
|
* most detailed information. The provider may scan at a lower rate or rely on
|
||||||
|
* knowledge of previously paired devices.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public static final int DISCOVERY_MODE_PASSIVE = RemoteDisplayState.DISCOVERY_MODE_PASSIVE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discovery mode: Active discovery.
|
||||||
|
* <p>
|
||||||
|
* This mode indicates that the user is actively trying to connect to a route
|
||||||
|
* and we should perform continuous scans. This mode may use significantly more
|
||||||
|
* power but is intended to be short-lived.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public static final int DISCOVERY_MODE_ACTIVE = RemoteDisplayState.DISCOVERY_MODE_ACTIVE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a remote display provider.
|
||||||
|
*
|
||||||
|
* @param context The application context for the remote display provider.
|
||||||
|
*/
|
||||||
|
public RemoteDisplayProvider(Context context) {
|
||||||
|
mStub = new ProviderStub();
|
||||||
|
mHandler = new ProviderHandler(context.getMainLooper());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the Binder associated with the provider.
|
||||||
|
* <p>
|
||||||
|
* This is intended to be used for the onBind() method of a service that implements
|
||||||
|
* a remote display provider service.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @return The IBinder instance associated with the provider.
|
||||||
|
*/
|
||||||
|
public IBinder getBinder() {
|
||||||
|
return mStub;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the current discovery mode changes.
|
||||||
|
*
|
||||||
|
* @param mode The new discovery mode.
|
||||||
|
*/
|
||||||
|
public void onDiscoveryModeChanged(int mode) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the system would like to connect to a display.
|
||||||
|
*
|
||||||
|
* @param display The remote display.
|
||||||
|
*/
|
||||||
|
public void onConnect(RemoteDisplay display) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the system would like to disconnect from a display.
|
||||||
|
*
|
||||||
|
* @param display The remote display.
|
||||||
|
*/
|
||||||
|
public void onDisconnect(RemoteDisplay display) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the system would like to set the volume of a display.
|
||||||
|
*
|
||||||
|
* @param display The remote display.
|
||||||
|
* @param volume The desired volume.
|
||||||
|
*/
|
||||||
|
public void onSetVolume(RemoteDisplay display, int volume) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the system would like to adjust the volume of a display.
|
||||||
|
*
|
||||||
|
* @param display The remote display.
|
||||||
|
* @param delta An increment to add to the current volume, such as +1 or -1.
|
||||||
|
*/
|
||||||
|
public void onAdjustVolume(RemoteDisplay display, int delta) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current discovery mode.
|
||||||
|
*
|
||||||
|
* @return The current discovery mode.
|
||||||
|
*/
|
||||||
|
public int getDiscoveryMode() {
|
||||||
|
return mDiscoveryMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current collection of displays.
|
||||||
|
*
|
||||||
|
* @return The current collection of displays, which must not be modified.
|
||||||
|
*/
|
||||||
|
public Collection<RemoteDisplay> getDisplays() {
|
||||||
|
return mDisplays.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the specified remote display and notifies the system.
|
||||||
|
*
|
||||||
|
* @param display The remote display that was added.
|
||||||
|
* @throws IllegalStateException if there is already a display with the same id.
|
||||||
|
*/
|
||||||
|
public void addDisplay(RemoteDisplay display) {
|
||||||
|
if (display == null || mDisplays.containsKey(display.getId())) {
|
||||||
|
throw new IllegalArgumentException("display");
|
||||||
|
}
|
||||||
|
mDisplays.put(display.getId(), display);
|
||||||
|
publishState();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates information about the specified remote display and notifies the system.
|
||||||
|
*
|
||||||
|
* @param display The remote display that was added.
|
||||||
|
* @throws IllegalStateException if the display was n
|
||||||
|
*/
|
||||||
|
public void updateDisplay(RemoteDisplay display) {
|
||||||
|
if (display == null || mDisplays.get(display.getId()) != display) {
|
||||||
|
throw new IllegalArgumentException("display");
|
||||||
|
}
|
||||||
|
publishState();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the specified remote display and tells the system about it.
|
||||||
|
*
|
||||||
|
* @param display The remote display that was removed.
|
||||||
|
*/
|
||||||
|
public void removeDisplay(RemoteDisplay display) {
|
||||||
|
if (display == null || mDisplays.get(display.getId()) != display) {
|
||||||
|
throw new IllegalArgumentException("display");
|
||||||
|
}
|
||||||
|
mDisplays.remove(display.getId());
|
||||||
|
publishState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCallback(IRemoteDisplayCallback callback) {
|
||||||
|
mCallback = callback;
|
||||||
|
publishState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDiscoveryMode(int mode) {
|
||||||
|
if (mDiscoveryMode != mode) {
|
||||||
|
mDiscoveryMode = mode;
|
||||||
|
onDiscoveryModeChanged(mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void publishState() {
|
||||||
|
if (mCallback != null) {
|
||||||
|
RemoteDisplayState state = new RemoteDisplayState();
|
||||||
|
final int count = mDisplays.size();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
final RemoteDisplay display = mDisplays.valueAt(i);
|
||||||
|
state.displays.add(display.getInfo());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
mCallback.onStateChanged(state);
|
||||||
|
} catch (RemoteException ex) {
|
||||||
|
// system server died?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoteDisplay findRemoteDisplay(String id) {
|
||||||
|
return mDisplays.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
final class ProviderStub extends IRemoteDisplayProvider.Stub {
|
||||||
|
@Override
|
||||||
|
public void setCallback(IRemoteDisplayCallback callback) {
|
||||||
|
mHandler.obtainMessage(MSG_SET_CALLBACK, callback).sendToTarget();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDiscoveryMode(int mode) {
|
||||||
|
mHandler.obtainMessage(MSG_SET_DISCOVERY_MODE, mode, 0).sendToTarget();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void connect(String id) {
|
||||||
|
mHandler.obtainMessage(MSG_CONNECT, id).sendToTarget();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disconnect(String id) {
|
||||||
|
mHandler.obtainMessage(MSG_DISCONNECT, id).sendToTarget();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setVolume(String id, int volume) {
|
||||||
|
mHandler.obtainMessage(MSG_SET_VOLUME, volume, 0, id).sendToTarget();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void adjustVolume(String id, int delta) {
|
||||||
|
mHandler.obtainMessage(MSG_ADJUST_VOLUME, delta, 0, id).sendToTarget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final class ProviderHandler extends Handler {
|
||||||
|
public ProviderHandler(Looper looper) {
|
||||||
|
super(looper, null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg) {
|
||||||
|
switch (msg.what) {
|
||||||
|
case MSG_SET_CALLBACK: {
|
||||||
|
setCallback((IRemoteDisplayCallback)msg.obj);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_SET_DISCOVERY_MODE: {
|
||||||
|
setDiscoveryMode(msg.arg1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_CONNECT: {
|
||||||
|
RemoteDisplay display = findRemoteDisplay((String)msg.obj);
|
||||||
|
if (display != null) {
|
||||||
|
onConnect(display);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_DISCONNECT: {
|
||||||
|
RemoteDisplay display = findRemoteDisplay((String)msg.obj);
|
||||||
|
if (display != null) {
|
||||||
|
onDisconnect(display);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_SET_VOLUME: {
|
||||||
|
RemoteDisplay display = findRemoteDisplay((String)msg.obj);
|
||||||
|
if (display != null) {
|
||||||
|
onSetVolume(display, msg.arg1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_ADJUST_VOLUME: {
|
||||||
|
RemoteDisplay display = findRemoteDisplay((String)msg.obj);
|
||||||
|
if (display != null) {
|
||||||
|
onAdjustVolume(display, msg.arg1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user