Index: remoting/android/java/src/org/chromium/chromoting/CapabilityManager.java |
diff --git a/remoting/android/java/src/org/chromium/chromoting/CapabilityManager.java b/remoting/android/java/src/org/chromium/chromoting/CapabilityManager.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..932b38563a70aa1a76195d4df2bbfd15ec446583 |
--- /dev/null |
+++ b/remoting/android/java/src/org/chromium/chromoting/CapabilityManager.java |
@@ -0,0 +1,157 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+package org.chromium.chromoting; |
+ |
+import android.app.Activity; |
+import android.text.TextUtils; |
+import android.util.Log; |
+ |
+import java.util.ArrayList; |
+import java.util.Arrays; |
+import java.util.List; |
+ |
+/** |
+ * A manager for the capabilities of the Android client. Based on the negotiated set of |
+ * capabilities, it creates the associated ClientExtensions, and enables their communication with |
+ * the Chromoting host by dispatching extension messages appropriately. |
+ * |
+ * The CapabilityManager mirrors how the Chromoting host handles extension messages. For each |
+ * incoming extension message, runs through a list of HostExtensionSession objects, giving each one |
+ * a chance to handle the message. |
+ * |
+ * The CapabilityManager is a singleton class so we can manage client extensions on an application |
+ * level. The singleton object may be used from multiple Activities, thus allowing it to support |
+ * different capabilities at different stages of the application. |
+ */ |
+public class CapabilityManager { |
+ |
+ /** Lazily-initialized singleton object that can be used from different Activities. */ |
+ private static CapabilityManager sInstance; |
+ |
+ /** Protects access to |sInstance|. */ |
+ private static final Object sInstanceLock = new Object(); |
+ |
+ /** List of all capabilities that are supported by the application. */ |
+ private List<String> mLocalCapabilities; |
+ |
+ /** List of negotiated capabilities received from the host. */ |
+ private List<String> mNegotiatedCapabilities; |
+ |
+ /** List of extensions to the client based on capabilities negotiated with the host. */ |
+ private List<ClientExtension> mClientExtensions; |
+ |
+ private CapabilityManager() { |
+ mLocalCapabilities = new ArrayList<String>(); |
+ mClientExtensions = new ArrayList<ClientExtension>(); |
+ |
+ mLocalCapabilities.add(Capabilities.CAST_CAPABILITY); |
+ } |
+ |
+ /** |
+ * Returns the singleton object. Thread-safe. |
+ */ |
+ public static CapabilityManager getInstance() { |
+ synchronized (sInstanceLock) { |
+ if (sInstance == null) { |
+ sInstance = new CapabilityManager(); |
+ } |
+ return sInstance; |
+ } |
+ } |
+ |
+ /** |
+ * Returns a space-separated list (required by host) of the capabilities supported by |
+ * this client. |
+ */ |
+ public String getLocalCapabilities() { |
+ return TextUtils.join(" ", mLocalCapabilities); |
+ } |
+ |
+ /** |
+ * Returns the ActivityLifecycleListener associated with the specified capability, if |
+ * |capability| is enabled and such a listener exists. |
+ * |
+ * Activities that call this method agree to appropriately notify the listener of lifecycle |
+ * events., thus supporting |capability|. This allows extensions like the CastExtensionHandler |
+ * to hook into an existing activity's lifecycle. |
+ */ |
+ public ActivityLifecycleListener onActivityAcceptingListener( |
+ Activity activity, String capability) { |
+ |
+ ActivityLifecycleListener listener; |
+ |
+ if (isCapabilityEnabled(capability)) { |
+ for (ClientExtension ext : mClientExtensions) { |
+ if (ext.getCapability().equals(capability)) { |
+ listener = ext.onActivityAcceptingListener(activity); |
+ if (listener != null) |
+ return listener; |
+ } |
+ } |
+ } |
+ |
+ return new DummyActivityLifecycleListener(); |
+ } |
+ |
+ /** |
+ * Receives the capabilities negotiated between client and host and creates the appropriate |
+ * extension handlers. |
+ * |
+ * Currently only the CAST_CAPABILITY exists, so that is the only extension constructed. |
+ */ |
+ public void setNegotiatedCapabilities(String capabilities) { |
+ mNegotiatedCapabilities = Arrays.asList(capabilities.split(" ")); |
+ mClientExtensions.clear(); |
+ if (isCapabilityEnabled(Capabilities.CAST_CAPABILITY)) { |
+ mClientExtensions.add(maybeCreateCastExtensionHandler()); |
+ } |
+ } |
+ |
+ /** |
+ * Passes the deconstructed extension message to each ClientExtension in turn until the message |
+ * is handled or none remain. Returns true if the message was handled. |
+ */ |
+ public boolean onExtensionMessage(String type, String data) { |
+ if (type == null || type.isEmpty()) { |
+ return false; |
+ } |
+ |
+ for (ClientExtension ext : mClientExtensions) { |
+ if (ext.onExtensionMessage(type, data)) { |
+ return true; |
+ } |
+ } |
+ return false; |
+ } |
+ |
+ /** |
+ * Return true if the capability is enabled for this connection with the host. |
+ */ |
+ private boolean isCapabilityEnabled(String capability) { |
+ return (mNegotiatedCapabilities != null && mNegotiatedCapabilities.contains(capability)); |
+ } |
+ |
+ /** |
+ * Tries to reflectively instantiate a CastExtensionHandler object. |
+ * |
+ * Note: The ONLY reason this is done is that by default, the regular android application |
+ * will be built, without this experimental extension. |
+ */ |
+ private ClientExtension maybeCreateCastExtensionHandler() { |
+ try { |
+ Class<?> cls = Class.forName("org.chromium.chromoting.CastExtensionHandler"); |
+ return (ClientExtension) cls.newInstance(); |
+ } catch (ClassNotFoundException e) { |
+ Log.w("CapabilityManager", "Failed to create CastExtensionHandler."); |
+ return new DummyClientExtension(); |
+ } catch (InstantiationException e) { |
+ Log.w("CapabilityManager", "Failed to create CastExtensionHandler."); |
+ return new DummyClientExtension(); |
+ } catch (IllegalAccessException e) { |
+ Log.w("CapabilityManager", "Failed to create CastExtensionHandler."); |
+ return new DummyClientExtension(); |
+ } |
+ } |
+} |