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/IRemoteControlClient.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/IRingtonePlayer.aidl \
|
||||
telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl \
|
||||
|
||||
@@ -1992,6 +1992,14 @@
|
||||
android:description="@string/permdesc_bindWallpaper"
|
||||
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
|
||||
system can interact with it. -->
|
||||
<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
|
||||
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. -->
|
||||
<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. -->
|
||||
|
||||
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