diff options
author | Jeff Brown <jeffbrown@google.com> | 2013-11-08 01:36:41 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2013-11-08 01:36:41 +0000 |
commit | 1f7a8a06256907e03405f89108f081289c23e97a (patch) | |
tree | 8ef01bc8a8f7b2b7edfa3cb1633dc2c0f2f5b882 /media | |
parent | 1e45fd78090693c5eff346feb32bab90f31a5e30 (diff) | |
parent | f3c99e883f46c56e5e2877e844b902b6eb45545b (diff) | |
download | frameworks_base-1f7a8a06256907e03405f89108f081289c23e97a.zip frameworks_base-1f7a8a06256907e03405f89108f081289c23e97a.tar.gz frameworks_base-1f7a8a06256907e03405f89108f081289c23e97a.tar.bz2 |
Merge "Add a platform library for remote display providers." into klp-dev
Diffstat (limited to 'media')
-rw-r--r-- | media/java/android/media/IRemoteDisplayCallback.aidl | 26 | ||||
-rw-r--r-- | media/java/android/media/IRemoteDisplayProvider.aidl | 31 | ||||
-rw-r--r-- | media/java/android/media/RemoteDisplayState.aidl | 18 | ||||
-rw-r--r-- | media/java/android/media/RemoteDisplayState.java | 189 | ||||
-rw-r--r-- | media/lib/Android.mk | 46 | ||||
-rw-r--r-- | media/lib/README.txt | 28 | ||||
-rw-r--r-- | media/lib/com.android.media.remotedisplay.xml | 20 | ||||
-rw-r--r-- | media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java | 173 | ||||
-rw-r--r-- | media/lib/java/com/android/media/remotedisplay/RemoteDisplayProvider.java | 371 |
9 files changed, 902 insertions, 0 deletions
diff --git a/media/java/android/media/IRemoteDisplayCallback.aidl b/media/java/android/media/IRemoteDisplayCallback.aidl new file mode 100644 index 0000000..19cf070 --- /dev/null +++ b/media/java/android/media/IRemoteDisplayCallback.aidl @@ -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); +} diff --git a/media/java/android/media/IRemoteDisplayProvider.aidl b/media/java/android/media/IRemoteDisplayProvider.aidl new file mode 100644 index 0000000..b0d7379 --- /dev/null +++ b/media/java/android/media/IRemoteDisplayProvider.aidl @@ -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); +} diff --git a/media/java/android/media/RemoteDisplayState.aidl b/media/java/android/media/RemoteDisplayState.aidl new file mode 100644 index 0000000..b3262fc --- /dev/null +++ b/media/java/android/media/RemoteDisplayState.aidl @@ -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; diff --git a/media/java/android/media/RemoteDisplayState.java b/media/java/android/media/RemoteDisplayState.java new file mode 100644 index 0000000..1197f65 --- /dev/null +++ b/media/java/android/media/RemoteDisplayState.java @@ -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]; + } + }; + } +} diff --git a/media/lib/Android.mk b/media/lib/Android.mk new file mode 100644 index 0000000..50799a6 --- /dev/null +++ b/media/lib/Android.mk @@ -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) diff --git a/media/lib/README.txt b/media/lib/README.txt new file mode 100644 index 0000000..cade3df --- /dev/null +++ b/media/lib/README.txt @@ -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. + diff --git a/media/lib/com.android.media.remotedisplay.xml b/media/lib/com.android.media.remotedisplay.xml new file mode 100644 index 0000000..77a91d2 --- /dev/null +++ b/media/lib/com.android.media.remotedisplay.xml @@ -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> diff --git a/media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java b/media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java new file mode 100644 index 0000000..5e15702 --- /dev/null +++ b/media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java @@ -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; + } +} diff --git a/media/lib/java/com/android/media/remotedisplay/RemoteDisplayProvider.java b/media/lib/java/com/android/media/remotedisplay/RemoteDisplayProvider.java new file mode 100644 index 0000000..8e4042c --- /dev/null +++ b/media/lib/java/com/android/media/remotedisplay/RemoteDisplayProvider.java @@ -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; + } + } + } + } +} |