Upstream version 10.38.222.0
[platform/framework/web/crosswalk.git] / src / third_party / cacheinvalidation / src / java / com / google / ipc / invalidation / ticl / android / AndroidClientManager.java
1 /*
2  * Copyright 2011 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.google.ipc.invalidation.ticl.android;
18
19 import com.google.ipc.invalidation.external.client.SystemResources.Logger;
20 import com.google.ipc.invalidation.external.client.android.service.AndroidClientException;
21 import com.google.ipc.invalidation.external.client.android.service.AndroidLogger;
22 import com.google.ipc.invalidation.external.client.android.service.Response.Status;
23 import com.google.ipc.invalidation.ticl.InvalidationClientCore;
24 import com.google.ipc.invalidation.util.TypedUtil;
25 import com.google.protos.ipc.invalidation.ClientProtocol.ClientConfigP;
26
27 import android.accounts.Account;
28 import android.content.Context;
29 import android.content.Intent;
30
31 import java.util.HashMap;
32 import java.util.Map;
33
34
35 /**
36  * Manages active client instances for the Android invalidation service. The client manager contains
37  * the code to create, persist, load, and lookup client instances, as well as handling the
38  * propagation of any C2DM registration notifications to active clients.
39  *
40  */
41 public class AndroidClientManager {
42
43   /** Logger */
44   private static final Logger logger = AndroidLogger.forTag("InvClientManager");
45
46   /**
47    * The client configuration used creating new invalidation client instances.   This is normally
48    * a constant but may be varied for testing.
49    */
50   private static ClientConfigP clientConfig = InvalidationClientCore.createConfig().build();
51
52   /** The invalidation service associated with this manager */
53   private final AndroidInvalidationService service;
54
55   /**
56    * When set, this registration ID is used rather than the ID returned by
57    * {@code GCMRegistrar.getRegistrationId()}.
58    */
59   private static String registrationIdForTest;
60
61   /** A map from client key to client proxy instances for in-memory client instances */
62   private final Map<String, AndroidClientProxy> clientMap =
63       new HashMap<String, AndroidClientProxy>();
64
65   /** All client manager operations are synchronized on this lock */
66   private final Object lock = new Object();
67
68   /** Creates a new client manager instance associated with the provided service */
69   AndroidClientManager(AndroidInvalidationService service) {
70     this.service = service;
71   }
72
73   /**
74    * Returns the number of managed clients.
75    */
76   int getClientCount() {
77     synchronized (lock) {
78       return clientMap.size();
79     }
80   }
81
82   /**
83    * Creates a new Android client proxy with the provided attributes. Before creating, will check to
84    * see if there is an existing client with attributes that match and return it if found. If there
85    * is an existing client with the same key but attributes that do not match, an exception will be
86    * thrown. If no client with a matching key exists, a new client proxy will be created and
87    * returned.
88    *
89    * @param clientKey key that uniquely identifies the client on the device.
90    * @param clientType client type.
91    * @param account user account associated with the client.
92    * @param authType authentication type for the client.
93    * @param eventIntent intent that can be used to bind to an event listener for the client.
94    * @return an android invalidation client instance representing the client.
95    */
96   AndroidClientProxy create(String clientKey, int clientType, Account account, String authType,
97       Intent eventIntent) {
98     synchronized (lock) {
99
100       // First check to see if an existing client is found
101       AndroidClientProxy proxy = lookup(clientKey);
102       if (proxy != null) {
103         if (!proxy.getAccount().equals(account) || !proxy.getAuthType().equals(authType)) {
104           throw new AndroidClientException(
105               Status.INVALID_CLIENT, "Account does not match existing client");
106         }
107         return proxy;
108       }
109
110       // If not found, create a new client proxy instance to represent the client.
111       AndroidStorage store = createAndroidStorage(service, clientKey);
112       store.create(clientType, account, authType, eventIntent);
113       proxy = new AndroidClientProxy(service, store, clientConfig);
114       if (registrationIdForTest != null) {
115         proxy.getChannel().setRegistrationIdForTest(registrationIdForTest);
116       }
117       clientMap.put(clientKey, proxy);
118       logger.fine("Client %s created", clientKey);
119       return proxy;
120     }
121   }
122
123   /**
124    * Retrieves an existing client that matches the provided key, loading it if necessary. If no
125    * matching client can be found, an exception is thrown.
126    *
127    * @param clientKey the client key for the client to retrieve.
128    * @return the matching client instance
129    */
130   AndroidClientProxy get(String clientKey) {
131     synchronized (lock) {
132       return lookup(clientKey);
133     }
134   }
135
136   /**
137    * Removes any client proxy instance associated with the provided key from memory but leaves the
138    * instance persisted. The client may subsequently be loaded again by calling {@code #get}.
139    *
140    * @param clientKey the client key of the instance to remove from memory.
141    */
142   void remove(String clientKey) {
143     synchronized (lock) {
144       // Remove the proxy from the managed set and release any associated resources
145       AndroidClientProxy proxy = clientMap.remove(clientKey);
146       if (proxy != null) {
147         proxy.release();
148       }
149     }
150   }
151
152   /**
153    * Looks up the client proxy instance associated with the provided key and returns it (or {@code
154    * null} if not found).
155    *
156    * @param clientKey the client key to look up
157    * @return the client instance or {@code null}.
158    */
159   
160   AndroidClientProxy lookup(String clientKey) {
161     synchronized (lock) {
162       // See if the client is already resident in memory
163       AndroidClientProxy client = clientMap.get(clientKey);
164       if (client == null) {
165         // Attempt to load the client from the store
166         AndroidStorage storage = createAndroidStorage(service, clientKey);
167         if (storage.load()) {
168           logger.fine("Client %s loaded from disk", clientKey);
169           client = new AndroidClientProxy(service, storage, clientConfig);
170           clientMap.put(clientKey, client);
171         }
172       }
173       return client;
174     }
175   }
176
177   /**
178    * Sets the GCM registration ID that should be used for all managed clients (new and existing).
179    */
180   void informRegistrationIdChanged() {
181     synchronized (lock) {
182       // Propagate the value to all existing clients
183       for (AndroidClientProxy proxy : clientMap.values()) {
184         proxy.getChannel().informRegistrationIdChanged();
185       }
186     }
187   }
188
189   /**
190    * Releases all managed clients and drops them from the managed set.
191    */
192   void releaseAll() {
193     synchronized (lock) {
194       for (AndroidClientProxy clientProxy : clientMap.values()) {
195         clientProxy.release();
196       }
197       clientMap.clear();
198     }
199   }
200
201   /**
202    * Returns an android storage instance for managing client state.
203    */
204   
205   protected AndroidStorage createAndroidStorage(Context context, String clientKey) {
206     synchronized (lock) {
207       return new AndroidStorage(context, clientKey);
208     }
209   }
210
211   
212   static ClientConfigP setConfigForTest(ClientConfigP newConfig) {
213     logger.info("Setting client configuration: %s", newConfig);
214     ClientConfigP currentConfig = clientConfig;
215     clientConfig = newConfig;
216     return clientConfig;
217   }
218
219   
220   public static void setRegistrationIdForTest(String registrationIdForTest) {
221     AndroidClientManager.registrationIdForTest = registrationIdForTest;
222   }
223
224   /** Returns whether all loaded clients are stopped. */
225   public boolean areAllClientsStopped() {
226     synchronized (lock) {
227       for (AndroidClientProxy proxy : clientMap.values()) {
228         if (proxy.isStarted()) {
229           return false;
230         }
231       }
232       return true;
233     }
234   }
235
236   /** Returns whether the client with key {@code clientKey} is in memory. */
237   public boolean isLoadedForTest(String clientKey) {
238     synchronized (lock) {
239       return TypedUtil.containsKey(clientMap, clientKey);
240     }
241   }
242 }