Chromium Code Reviews| 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..8039c1d2cd0351f2fb92cc1dd9f8cfd086a0dae3 |
| --- /dev/null |
| +++ b/remoting/android/java/src/org/chromium/chromoting/CapabilityManager.java |
| @@ -0,0 +1,159 @@ |
| +// 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; |
| + |
| + /** |
| + * Constructs the Capability Manager. The same manager is used for an entire application run. |
|
Lambros
2014/08/14 23:54:25
I don't think this comment is needed.
aiguha
2014/08/15 03:37:29
Done.
|
| + */ |
| + private CapabilityManager() { |
| + mLocalCapabilities = new ArrayList<String>(); |
| + mClientExtensions = new ArrayList<ClientExtension>(); |
| + |
| + mLocalCapabilities.add(Capabilities.CAST_CAPABILITY); |
| + } |
| + |
| + /** |
| + * Returns |sInstance|. Thread-safe. |
|
Lambros
2014/08/14 23:54:25
nit: Don't reference private fields inside public
aiguha
2014/08/15 03:37:29
Done.
|
| + */ |
| + public static CapabilityManager getInstance() { |
| + synchronized (sInstanceLock) { |
| + if (sInstance == null) { |
|
Lambros
2014/08/14 23:54:25
nit: the lines inside synchronized {...} should be
aiguha
2014/08/15 03:37:29
Done.
|
| + sInstance = new CapabilityManager(); |
| + } |
| + return sInstance; |
| + } |
| + } |
| + |
| + /** |
| + * Returns a space-separated list (required by host) of the capabilities supported using |
|
Lambros
2014/08/14 23:54:25
nit: Same here. Suggest: "... supported by this cl
aiguha
2014/08/15 03:37:29
Done.
|
| + * |mLocalCapabilities|. |
| + */ |
| + 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 |
|
Lambros
2014/08/14 23:54:25
Not sure what "thus supporting |capability|" means
aiguha
2014/08/15 03:37:29
Discussed offline.
|
| + * to hook into an existing activity's lifecycle. |
| + */ |
| + public ActivityLifecycleListener onActivityAcceptingListener( |
| + Activity activity, String capability) { |
| + |
| + ActivityLifecycleListener listener = new DummyActivityLifecycleListener(); |
| + |
| + if (isCapabilityEnabled(capability)) { |
| + for (ClientExtension ext : mClientExtensions) { |
| + if (ext.getCapability().equals(capability)) { |
| + listener = ext.onActivityAcceptingListener(activity); |
| + if (listener != null) |
| + return listener; |
| + } |
| + } |
| + } |
| + return listener; |
| + } |
| + |
| + /** |
| + * 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."); |
|
Lambros
2014/08/14 23:54:25
Optional: Since the try {} block ends with a retur
aiguha
2014/08/15 03:37:29
I wanted to do this but findbugs complains about i
|
| + 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(); |
| + } |
| + } |
| +} |