From e4095a80b674642e0e0e8f0883dee3b22f32f19a Mon Sep 17 00:00:00 2001 From: Jeff Tinker Date: Tue, 4 Mar 2014 13:17:11 -0800 Subject: Support CAST V2 Authentication in MediaDrm Java API version Update frameworks to enable support for CAST V2 Authentication in the DRM Plugin. Change-Id: I23cfbbbc89c1226b7a3968ce8bc1e2d4bd41014a related-to-bug: 12702350 --- media/lib/Android.mk | 46 --- media/lib/README.txt | 28 -- media/lib/com.android.media.remotedisplay.xml | 20 - .../android/media/remotedisplay/RemoteDisplay.java | 173 --------- .../media/remotedisplay/RemoteDisplayProvider.java | 407 --------------------- media/lib/remotedisplay/Android.mk | 46 +++ media/lib/remotedisplay/README.txt | 27 ++ .../com.android.media.remotedisplay.xml | 20 + .../android/media/remotedisplay/RemoteDisplay.java | 173 +++++++++ .../media/remotedisplay/RemoteDisplayProvider.java | 407 +++++++++++++++++++++ media/lib/signer/Android.mk | 45 +++ media/lib/signer/README.txt | 28 ++ media/lib/signer/com.android.mediadrm.signer.xml | 20 + .../android/mediadrm/signer/MediaDrmSigner.java | 139 +++++++ 14 files changed, 905 insertions(+), 674 deletions(-) delete mode 100644 media/lib/Android.mk delete mode 100644 media/lib/README.txt delete mode 100644 media/lib/com.android.media.remotedisplay.xml delete mode 100644 media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java delete mode 100644 media/lib/java/com/android/media/remotedisplay/RemoteDisplayProvider.java create mode 100644 media/lib/remotedisplay/Android.mk create mode 100644 media/lib/remotedisplay/README.txt create mode 100644 media/lib/remotedisplay/com.android.media.remotedisplay.xml create mode 100644 media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplay.java create mode 100644 media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java create mode 100644 media/lib/signer/Android.mk create mode 100644 media/lib/signer/README.txt create mode 100644 media/lib/signer/com.android.mediadrm.signer.xml create mode 100644 media/lib/signer/java/com/android/mediadrm/signer/MediaDrmSigner.java (limited to 'media/lib') diff --git a/media/lib/Android.mk b/media/lib/Android.mk deleted file mode 100644 index 50799a6..0000000 --- a/media/lib/Android.mk +++ /dev/null @@ -1,46 +0,0 @@ -# -# 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 deleted file mode 100644 index cade3df..0000000 --- a/media/lib/README.txt +++ /dev/null @@ -1,28 +0,0 @@ -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 deleted file mode 100644 index 77a91d2..0000000 --- a/media/lib/com.android.media.remotedisplay.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - diff --git a/media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java b/media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java deleted file mode 100644 index 6cfc0e8..0000000 --- a/media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * 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.media.MediaRouter; -import android.media.RemoteDisplayState.RemoteDisplayInfo; -import android.text.TextUtils; - -import java.util.Objects; - -/** - * 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.equals(mMutableInfo.name, name)) { - mMutableInfo.name = name; - mImmutableInfo = null; - } - } - - public String getDescription() { - return mMutableInfo.description; - } - - public void setDescription(String description) { - if (!Objects.equals(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 deleted file mode 100644 index e2df77c..0000000 --- a/media/lib/java/com/android/media/remotedisplay/RemoteDisplayProvider.java +++ /dev/null @@ -1,407 +0,0 @@ -/* - * 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.PendingIntent; -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.provider.Settings; -import android.util.ArrayMap; - -import java.util.Collection; - -/** - * Base class for remote display providers implemented as unbundled services. - *

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

- *
- *   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 ---
- *       }
- *   }
- * 
- *

- * Declare your remote display provider service in your application manifest - * like this: - *

- *
- *   <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>
- * 
- *

- * This object is not thread safe. It is only intended to be accessed on the - * {@link Context#getMainLooper main looper thread} of an application. - *

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

- */ -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 Context mContext; - private final ProviderStub mStub; - private final ProviderHandler mHandler; - private final ArrayMap mDisplays = - new ArrayMap(); - private IRemoteDisplayCallback mCallback; - private int mDiscoveryMode = DISCOVERY_MODE_NONE; - - private PendingIntent mSettingsPendingIntent; - - /** - * 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. - *

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

- */ - public static final int DISCOVERY_MODE_PASSIVE = RemoteDisplayState.DISCOVERY_MODE_PASSIVE; - - /** - * Discovery mode: Active discovery. - *

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

- */ - 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) { - mContext = context; - mStub = new ProviderStub(); - mHandler = new ProviderHandler(context.getMainLooper()); - } - - /** - * Gets the context of the remote display provider. - */ - public final Context getContext() { - return mContext; - } - - /** - * Gets the Binder associated with the provider. - *

- * This is intended to be used for the onBind() method of a service that implements - * a remote display provider service. - *

- * - * @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 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(); - } - - /** - * Finds the remote display with the specified id, returns null if not found. - * - * @param id Id of the remote display. - * @return The display, or null if none. - */ - public RemoteDisplay findRemoteDisplay(String id) { - return mDisplays.get(id); - } - - /** - * Gets a pending intent to launch the remote display settings activity. - * - * @return A pending intent to launch the settings activity. - */ - public PendingIntent getSettingsPendingIntent() { - if (mSettingsPendingIntent == null) { - Intent settingsIntent = new Intent(Settings.ACTION_WIFI_DISPLAY_SETTINGS); - settingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED - | Intent.FLAG_ACTIVITY_CLEAR_TOP); - mSettingsPendingIntent = PendingIntent.getActivity( - mContext, 0, settingsIntent, 0, null); - } - return mSettingsPendingIntent; - } - - 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? - } - } - } - - 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; - } - } - } - } -} diff --git a/media/lib/remotedisplay/Android.mk b/media/lib/remotedisplay/Android.mk new file mode 100644 index 0000000..ea1ac2b --- /dev/null +++ b/media/lib/remotedisplay/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 remotedisplay library +# ============================================================ +include $(CLEAR_VARS) + +LOCAL_MODULE:= com.android.media.remotedisplay +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := \ + $(call all-java-files-under, java) \ + $(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/remotedisplay/README.txt b/media/lib/remotedisplay/README.txt new file mode 100644 index 0000000..5738dbe --- /dev/null +++ b/media/lib/remotedisplay/README.txt @@ -0,0 +1,27 @@ +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/remotedisplay/com.android.media.remotedisplay.xml b/media/lib/remotedisplay/com.android.media.remotedisplay.xml new file mode 100644 index 0000000..77a91d2 --- /dev/null +++ b/media/lib/remotedisplay/com.android.media.remotedisplay.xml @@ -0,0 +1,20 @@ + + + + + + diff --git a/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplay.java b/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplay.java new file mode 100644 index 0000000..6cfc0e8 --- /dev/null +++ b/media/lib/remotedisplay/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 android.media.MediaRouter; +import android.media.RemoteDisplayState.RemoteDisplayInfo; +import android.text.TextUtils; + +import java.util.Objects; + +/** + * 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.equals(mMutableInfo.name, name)) { + mMutableInfo.name = name; + mImmutableInfo = null; + } + } + + public String getDescription() { + return mMutableInfo.description; + } + + public void setDescription(String description) { + if (!Objects.equals(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/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java b/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java new file mode 100644 index 0000000..e2df77c --- /dev/null +++ b/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java @@ -0,0 +1,407 @@ +/* + * 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.PendingIntent; +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.provider.Settings; +import android.util.ArrayMap; + +import java.util.Collection; + +/** + * Base class for remote display providers implemented as unbundled services. + *

+ * 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. + *

+ *
+ *   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 ---
+ *       }
+ *   }
+ * 
+ *

+ * Declare your remote display provider service in your application manifest + * like this: + *

+ *
+ *   <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>
+ * 
+ *

+ * This object is not thread safe. It is only intended to be accessed on the + * {@link Context#getMainLooper main looper thread} of an application. + *

+ * 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. + *

+ */ +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 Context mContext; + private final ProviderStub mStub; + private final ProviderHandler mHandler; + private final ArrayMap mDisplays = + new ArrayMap(); + private IRemoteDisplayCallback mCallback; + private int mDiscoveryMode = DISCOVERY_MODE_NONE; + + private PendingIntent mSettingsPendingIntent; + + /** + * 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. + *

+ * 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. + *

+ */ + public static final int DISCOVERY_MODE_PASSIVE = RemoteDisplayState.DISCOVERY_MODE_PASSIVE; + + /** + * Discovery mode: Active discovery. + *

+ * 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. + *

+ */ + 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) { + mContext = context; + mStub = new ProviderStub(); + mHandler = new ProviderHandler(context.getMainLooper()); + } + + /** + * Gets the context of the remote display provider. + */ + public final Context getContext() { + return mContext; + } + + /** + * Gets the Binder associated with the provider. + *

+ * This is intended to be used for the onBind() method of a service that implements + * a remote display provider service. + *

+ * + * @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 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(); + } + + /** + * Finds the remote display with the specified id, returns null if not found. + * + * @param id Id of the remote display. + * @return The display, or null if none. + */ + public RemoteDisplay findRemoteDisplay(String id) { + return mDisplays.get(id); + } + + /** + * Gets a pending intent to launch the remote display settings activity. + * + * @return A pending intent to launch the settings activity. + */ + public PendingIntent getSettingsPendingIntent() { + if (mSettingsPendingIntent == null) { + Intent settingsIntent = new Intent(Settings.ACTION_WIFI_DISPLAY_SETTINGS); + settingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED + | Intent.FLAG_ACTIVITY_CLEAR_TOP); + mSettingsPendingIntent = PendingIntent.getActivity( + mContext, 0, settingsIntent, 0, null); + } + return mSettingsPendingIntent; + } + + 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? + } + } + } + + 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; + } + } + } + } +} diff --git a/media/lib/signer/Android.mk b/media/lib/signer/Android.mk new file mode 100644 index 0000000..4c3772f --- /dev/null +++ b/media/lib/signer/Android.mk @@ -0,0 +1,45 @@ +# +# 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 mediadrm signer library +# ============================================================ +include $(CLEAR_VARS) + +LOCAL_MODULE:= com.android.mediadrm.signer +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := \ + $(call all-java-files-under, java) + +include $(BUILD_STATIC_JAVA_LIBRARY) + + +# ==== com.android.mediadrm.signer.xml lib def ======================== +include $(CLEAR_VARS) + +LOCAL_MODULE := com.android.mediadrm.signer.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/signer/README.txt b/media/lib/signer/README.txt new file mode 100644 index 0000000..362ab8e --- /dev/null +++ b/media/lib/signer/README.txt @@ -0,0 +1,28 @@ +This library (com.android.mediadrm.signer.jar) is a shared java library +containing classes required by unbundled apps running on devices that use +the certficate provisioning and private key signing capabilities provided +by the MediaDrm API. + +--- Rules of this library --- +o This library is effectively a PUBLIC API for unbundled CAST receivers + 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 exist? --- + +Unbundled apps cannot use internal platform classes. + +This library will eventually be replaced when the provisioned certificate- +based signing 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. + diff --git a/media/lib/signer/com.android.mediadrm.signer.xml b/media/lib/signer/com.android.mediadrm.signer.xml new file mode 100644 index 0000000..b5b1f09 --- /dev/null +++ b/media/lib/signer/com.android.mediadrm.signer.xml @@ -0,0 +1,20 @@ + + + + + + diff --git a/media/lib/signer/java/com/android/mediadrm/signer/MediaDrmSigner.java b/media/lib/signer/java/com/android/mediadrm/signer/MediaDrmSigner.java new file mode 100644 index 0000000..d971afb --- /dev/null +++ b/media/lib/signer/java/com/android/mediadrm/signer/MediaDrmSigner.java @@ -0,0 +1,139 @@ +/* + * 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.mediadrm.signer; + +import android.content.Context; +import android.media.MediaDrm; +import android.media.DeniedByServerException; + +/** + * Provides certificate request generation, response handling and + * signing APIs + */ +public final class MediaDrmSigner { + private MediaDrmSigner() {} + + /** + * Specify X.509 certificate type + */ + public static final int CERTIFICATE_TYPE_X509 = MediaDrm.CERTIFICATE_TYPE_X509; + + /** + * Contains the opaque data an app uses to request a certificate from a provisioning + * server + */ + public final static class CertificateRequest { + private MediaDrm.CertificateRequest mCertRequest; + + CertificateRequest(MediaDrm.CertificateRequest certRequest) { + mCertRequest = certRequest; + } + + /** + * Get the opaque message data + */ + public byte[] getData() { + return mCertRequest.getData(); + } + + /** + * Get the default URL to use when sending the certificate request + * message to a server, if known. The app may prefer to use a different + * certificate server URL obtained from other sources. + */ + public String getDefaultUrl() { + return mCertRequest.getDefaultUrl(); + } + } + + /** + * Contains the wrapped private key and public certificate data associated + * with a certificate. + */ + public final static class Certificate { + private MediaDrm.Certificate mCertificate; + + Certificate(MediaDrm.Certificate certificate) { + mCertificate = certificate; + } + + /** + * Get the wrapped private key data + */ + public byte[] getWrappedPrivateKey() { + return mCertificate.getWrappedPrivateKey(); + } + + /** + * Get the PEM-encoded public certificate chain + */ + public byte[] getContent() { + return mCertificate.getContent(); + } + } + + /** + * Generate a certificate request, specifying the certificate type + * and authority. The response received should be passed to + * provideCertificateResponse. + * + * @param drm the MediaDrm object + * @param certType Specifies the certificate type. + * @param certAuthority is passed to the certificate server to specify + * the chain of authority. + */ + public static CertificateRequest getCertificateRequest(MediaDrm drm, int certType, + String certAuthority) { + return new CertificateRequest(drm.getCertificateRequest(certType, certAuthority)); + } + + /** + * Process a response from the provisioning server. The response + * is obtained from an HTTP Post to the url provided by getCertificateRequest. + * + * The public X509 certificate chain and wrapped private key are returned + * in the returned Certificate objec. The certificate chain is in BIO serialized + * PEM format. The wrapped private key should be stored in application private + * storage, and used when invoking the signRSA method. + * + * @param drm the MediaDrm object + * @param response the opaque certificate response byte array to provide to the + * DRM engine plugin. + * @throws android.media.DeniedByServerException if the response indicates that the + * server rejected the request + */ + public static Certificate provideCertificateResponse(MediaDrm drm, byte[] response) + throws DeniedByServerException { + return new Certificate(drm.provideCertificateResponse(response)); + } + + /** + * Sign data using an RSA key + * + * @param context the App context + * @param drm the MediaDrm object + * @param sessionId a sessionId obtained from openSession on the MediaDrm object + * @param algorithm the signing algorithm to use, e.g. "PKCS1-BlockType1" + * @param wrappedKey - the wrapped (encrypted) RSA private key obtained + * from provideCertificateResponse + * @param message the data for which a signature is to be computed + */ + public static byte[] signRSA(Context context, MediaDrm drm, byte[] sessionId, + String algorithm, byte[] wrappedKey, byte[] message) { + return drm.signRSA(context, sessionId, algorithm, wrappedKey, message); + } +} -- cgit v1.1