1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 package org
.chromium
.chromoting
;
7 import android
.app
.Activity
;
8 import android
.text
.TextUtils
;
9 import android
.util
.Log
;
11 import java
.util
.ArrayList
;
12 import java
.util
.Arrays
;
13 import java
.util
.List
;
16 * A manager for the capabilities of the Android client. Based on the negotiated set of
17 * capabilities, it creates the associated ClientExtensions, and enables their communication with
18 * the Chromoting host by dispatching extension messages appropriately.
20 * The CapabilityManager mirrors how the Chromoting host handles extension messages. For each
21 * incoming extension message, runs through a list of HostExtensionSession objects, giving each one
22 * a chance to handle the message.
24 * The CapabilityManager is a singleton class so we can manage client extensions on an application
25 * level. The singleton object may be used from multiple Activities, thus allowing it to support
26 * different capabilities at different stages of the application.
28 public class CapabilityManager
{
30 /** Lazily-initialized singleton object that can be used from different Activities. */
31 private static CapabilityManager sInstance
;
33 /** Protects access to |sInstance|. */
34 private static final Object sInstanceLock
= new Object();
36 /** List of all capabilities that are supported by the application. */
37 private List
<String
> mLocalCapabilities
;
39 /** List of negotiated capabilities received from the host. */
40 private List
<String
> mNegotiatedCapabilities
;
42 /** List of extensions to the client based on capabilities negotiated with the host. */
43 private List
<ClientExtension
> mClientExtensions
;
45 private CapabilityManager() {
46 mLocalCapabilities
= new ArrayList
<String
>();
47 mClientExtensions
= new ArrayList
<ClientExtension
>();
49 mLocalCapabilities
.add(Capabilities
.CAST_CAPABILITY
);
53 * Returns the singleton object. Thread-safe.
55 public static CapabilityManager
getInstance() {
56 synchronized (sInstanceLock
) {
57 if (sInstance
== null) {
58 sInstance
= new CapabilityManager();
65 * Returns a space-separated list (required by host) of the capabilities supported by
68 public String
getLocalCapabilities() {
69 return TextUtils
.join(" ", mLocalCapabilities
);
73 * Returns the ActivityLifecycleListener associated with the specified capability, if
74 * |capability| is enabled and such a listener exists.
76 * Activities that call this method agree to appropriately notify the listener of lifecycle
77 * events., thus supporting |capability|. This allows extensions like the CastExtensionHandler
78 * to hook into an existing activity's lifecycle.
80 public ActivityLifecycleListener
onActivityAcceptingListener(
81 Activity activity
, String capability
) {
83 ActivityLifecycleListener listener
;
85 if (isCapabilityEnabled(capability
)) {
86 for (ClientExtension ext
: mClientExtensions
) {
87 if (ext
.getCapability().equals(capability
)) {
88 listener
= ext
.onActivityAcceptingListener(activity
);
89 if (listener
!= null) return listener
;
94 return new DummyActivityLifecycleListener();
98 * Receives the capabilities negotiated between client and host and creates the appropriate
101 * Currently only the CAST_CAPABILITY exists, so that is the only extension constructed.
103 public void setNegotiatedCapabilities(String capabilities
) {
104 mNegotiatedCapabilities
= Arrays
.asList(capabilities
.split(" "));
105 mClientExtensions
.clear();
106 if (isCapabilityEnabled(Capabilities
.CAST_CAPABILITY
)) {
107 mClientExtensions
.add(maybeCreateCastExtensionHandler());
112 * Passes the deconstructed extension message to each ClientExtension in turn until the message
113 * is handled or none remain. Returns true if the message was handled.
115 public boolean onExtensionMessage(String type
, String data
) {
116 if (type
== null || type
.isEmpty()) {
120 for (ClientExtension ext
: mClientExtensions
) {
121 if (ext
.onExtensionMessage(type
, data
)) {
129 * Return true if the capability is enabled for this connection with the host.
131 private boolean isCapabilityEnabled(String capability
) {
132 return (mNegotiatedCapabilities
!= null && mNegotiatedCapabilities
.contains(capability
));
136 * Tries to reflectively instantiate a CastExtensionHandler object.
138 * Note: The ONLY reason this is done is that by default, the regular android application
139 * will be built, without this experimental extension.
141 private ClientExtension
maybeCreateCastExtensionHandler() {
143 Class
<?
> cls
= Class
.forName("org.chromium.chromoting.CastExtensionHandler");
144 return (ClientExtension
) cls
.newInstance();
145 } catch (ClassNotFoundException e
) {
146 Log
.w("CapabilityManager", "Failed to create CastExtensionHandler.");
147 return new DummyClientExtension();
148 } catch (InstantiationException e
) {
149 Log
.w("CapabilityManager", "Failed to create CastExtensionHandler.");
150 return new DummyClientExtension();
151 } catch (IllegalAccessException e
) {
152 Log
.w("CapabilityManager", "Failed to create CastExtensionHandler.");
153 return new DummyClientExtension();