blob: 5d87aaff8d5635632ca6c725ce5971de6ed6b21c [file] [log] [blame]
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -08001/*
2 * Copyright (C) 2016 The Android Open Source Project
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 */
16package android.hardware.location;
17
Arthur Ishiguroe35a6de2017-12-20 15:30:51 -080018import android.annotation.CallbackExecutor;
19import android.annotation.NonNull;
Arthur Ishiguroac7b9592018-01-02 09:46:42 -080020import android.annotation.Nullable;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060021import android.annotation.RequiresPermission;
22import android.annotation.SuppressLint;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080023import android.annotation.SystemApi;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060024import android.annotation.SystemService;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080025import android.content.Context;
Peng Xu9ff7d222016-02-11 13:02:05 -080026import android.os.Handler;
Arthur Ishiguro9b9c9d82017-12-20 16:11:53 -080027import android.os.HandlerExecutor;
Peng Xu9ff7d222016-02-11 13:02:05 -080028import android.os.Looper;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080029import android.os.RemoteException;
Peng Xu9ff7d222016-02-11 13:02:05 -080030import android.os.ServiceManager;
Jeff Sharkey49ca5292016-05-10 12:54:45 -060031import android.os.ServiceManager.ServiceNotFoundException;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080032import android.util.Log;
33
Arthur Ishiguroac7b9592018-01-02 09:46:42 -080034import com.android.internal.util.Preconditions;
35
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -070036import java.util.List;
Arthur Ishiguroe35a6de2017-12-20 15:30:51 -080037import java.util.concurrent.Executor;
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -070038
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080039/**
destradaa8bad3fe2016-03-15 12:33:40 -070040 * A class that exposes the Context hubs on a device to applications.
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080041 *
destradaa8bad3fe2016-03-15 12:33:40 -070042 * Please note that this class is not expected to be used by unbundled applications. Also, calling
43 * applications are expected to have LOCATION_HARDWARE permissions to use this class.
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080044 *
45 * @hide
46 */
47@SystemApi
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060048@SystemService(Context.CONTEXTHUB_SERVICE)
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080049public final class ContextHubManager {
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080050 private static final String TAG = "ContextHubManager";
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080051
Peng Xu9ff7d222016-02-11 13:02:05 -080052 private final Looper mMainLooper;
Jeff Sharkey49ca5292016-05-10 12:54:45 -060053 private final IContextHubService mService;
Greg Kaiser6ba60e62016-03-18 10:08:39 -070054 private Callback mCallback;
Peng Xu9ff7d222016-02-11 13:02:05 -080055 private Handler mCallbackHandler;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080056
57 /**
destradaa78cebca2016-04-14 18:40:14 -070058 * @deprecated Use {@code mCallback} instead.
59 */
60 @Deprecated
61 private ICallback mLocalCallback;
62
63 /**
destradaa8bad3fe2016-03-15 12:33:40 -070064 * An interface to receive asynchronous communication from the context hub.
Peng Xu9ff7d222016-02-11 13:02:05 -080065 */
Greg Kaiser6ba60e62016-03-18 10:08:39 -070066 public abstract static class Callback {
67 protected Callback() {}
destradaa8bad3fe2016-03-15 12:33:40 -070068
Peng Xu9ff7d222016-02-11 13:02:05 -080069 /**
destradaa8bad3fe2016-03-15 12:33:40 -070070 * Callback function called on message receipt from context hub.
Peng Xu9ff7d222016-02-11 13:02:05 -080071 *
destradaa8bad3fe2016-03-15 12:33:40 -070072 * @param hubHandle Handle (system-wide unique identifier) of the hub of the message.
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070073 * @param nanoAppHandle Handle (unique identifier) for app instance that sent the message.
destradaa8bad3fe2016-03-15 12:33:40 -070074 * @param message The context hub message.
Peng Xu9ff7d222016-02-11 13:02:05 -080075 *
76 * @see ContextHubMessage
77 */
destradaa8bad3fe2016-03-15 12:33:40 -070078 public abstract void onMessageReceipt(
79 int hubHandle,
80 int nanoAppHandle,
Arthur Ishiguroac7b9592018-01-02 09:46:42 -080081 @NonNull ContextHubMessage message);
Peng Xu9ff7d222016-02-11 13:02:05 -080082 }
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080083
84 /**
destradaa78cebca2016-04-14 18:40:14 -070085 * @deprecated Use {@link Callback} instead.
86 * @hide
87 */
88 @Deprecated
89 public interface ICallback {
90 /**
91 * Callback function called on message receipt from context hub.
92 *
93 * @param hubHandle Handle (system-wide unique identifier) of the hub of the message.
94 * @param nanoAppHandle Handle (unique identifier) for app instance that sent the message.
95 * @param message The context hub message.
96 *
97 * @see ContextHubMessage
98 */
99 void onMessageReceipt(int hubHandle, int nanoAppHandle, ContextHubMessage message);
100 }
101
102 /**
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800103 * Get a handle to all the context hubs in the system
104 * @return array of context hub handles
105 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -0600106 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
Peng Xu9ff7d222016-02-11 13:02:05 -0800107 public int[] getContextHubHandles() {
Peng Xu9ff7d222016-02-11 13:02:05 -0800108 try {
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600109 return mService.getContextHubHandles();
Peng Xu9ff7d222016-02-11 13:02:05 -0800110 } catch (RemoteException e) {
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600111 throw e.rethrowFromSystemServer();
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800112 }
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800113 }
114
115 /**
116 * Get more information about a specific hub.
117 *
destradaa8bad3fe2016-03-15 12:33:40 -0700118 * @param hubHandle Handle (system-wide unique identifier) of a context hub.
119 * @return ContextHubInfo Information about the requested context hub.
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800120 *
121 * @see ContextHubInfo
122 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -0600123 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
destradaa8bad3fe2016-03-15 12:33:40 -0700124 public ContextHubInfo getContextHubInfo(int hubHandle) {
Peng Xu9ff7d222016-02-11 13:02:05 -0800125 try {
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600126 return mService.getContextHubInfo(hubHandle);
Peng Xu9ff7d222016-02-11 13:02:05 -0800127 } catch (RemoteException e) {
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600128 throw e.rethrowFromSystemServer();
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800129 }
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800130 }
131
132 /**
destradaa8bad3fe2016-03-15 12:33:40 -0700133 * Load a nano app on a specified context hub.
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800134 *
Greg Kaiserfac5be22016-08-17 15:33:10 -0700135 * Note that loading is asynchronous. When we return from this method,
136 * the nano app (probably) hasn't loaded yet. Assuming a return of 0
137 * from this method, then the final success/failure for the load, along
138 * with the "handle" for the nanoapp, is all delivered in a byte
139 * string via a call to Callback.onMessageReceipt.
140 *
141 * TODO(b/30784270): Provide a better success/failure and "handle" delivery.
142 *
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800143 * @param hubHandle handle of context hub to load the app on.
144 * @param app the nanoApp to load on the hub
145 *
Greg Kaiserfac5be22016-08-17 15:33:10 -0700146 * @return 0 if the command for loading was sent to the context hub;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800147 * -1 otherwise
148 *
149 * @see NanoApp
150 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -0600151 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
Arthur Ishiguroac7b9592018-01-02 09:46:42 -0800152 public int loadNanoApp(int hubHandle, @NonNull NanoApp app) {
Peng Xu9ff7d222016-02-11 13:02:05 -0800153 try {
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600154 return mService.loadNanoApp(hubHandle, app);
Peng Xu9ff7d222016-02-11 13:02:05 -0800155 } catch (RemoteException e) {
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600156 throw e.rethrowFromSystemServer();
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800157 }
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800158 }
159
160 /**
161 * Unload a specified nanoApp
162 *
Greg Kaiserfac5be22016-08-17 15:33:10 -0700163 * Note that unloading is asynchronous. When we return from this method,
164 * the nano app (probably) hasn't unloaded yet. Assuming a return of 0
165 * from this method, then the final success/failure for the unload is
166 * delivered in a byte string via a call to Callback.onMessageReceipt.
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800167 *
Greg Kaiserfac5be22016-08-17 15:33:10 -0700168 * TODO(b/30784270): Provide a better success/failure delivery.
169 *
170 * @param nanoAppHandle handle of the nanoApp to unload
171 *
172 * @return 0 if the command for unloading was sent to the context hub;
173 * -1 otherwise
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800174 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -0600175 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
destradaa8bad3fe2016-03-15 12:33:40 -0700176 public int unloadNanoApp(int nanoAppHandle) {
Peng Xu9ff7d222016-02-11 13:02:05 -0800177 try {
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600178 return mService.unloadNanoApp(nanoAppHandle);
Peng Xu9ff7d222016-02-11 13:02:05 -0800179 } catch (RemoteException e) {
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600180 throw e.rethrowFromSystemServer();
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800181 }
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800182 }
183
184 /**
185 * get information about the nano app instance
186 *
Greg Kaiser3be73d32016-08-18 10:13:52 -0700187 * NOTE: The returned NanoAppInstanceInfo does _not_ contain correct
188 * information for several fields, specifically:
189 * - getName()
190 * - getPublisher()
191 * - getNeededExecMemBytes()
192 * - getNeededReadMemBytes()
193 * - getNeededWriteMemBytes()
194 *
195 * For example, say you call loadNanoApp() with a NanoApp that has
196 * getName() returning "My Name". Later, if you call getNanoAppInstanceInfo
197 * for that nanoapp, the returned NanoAppInstanceInfo's getName()
198 * method will claim "Preloaded app, unknown", even though you would
199 * have expected "My Name". For now, as the user, you'll need to
200 * separately track the above fields if they are of interest to you.
201 *
202 * TODO(b/30943489): Have the returned NanoAppInstanceInfo contain the
203 * correct information.
204 *
Arthur Ishiguroac7b9592018-01-02 09:46:42 -0800205 * @param nanoAppHandle handle of the nanoapp instance
206 * @return NanoAppInstanceInfo the NanoAppInstanceInfo of the nanoapp, or null if the nanoapp
207 * does not exist
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800208 *
209 * @see NanoAppInstanceInfo
210 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -0600211 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
Arthur Ishiguroac7b9592018-01-02 09:46:42 -0800212 @Nullable public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppHandle) {
Peng Xu9ff7d222016-02-11 13:02:05 -0800213 try {
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600214 return mService.getNanoAppInstanceInfo(nanoAppHandle);
Peng Xu9ff7d222016-02-11 13:02:05 -0800215 } catch (RemoteException e) {
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600216 throw e.rethrowFromSystemServer();
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800217 }
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800218 }
219
220 /**
221 * Find a specified nano app on the system
222 *
223 * @param hubHandle handle of hub to search for nano app
224 * @param filter filter specifying the search criteria for app
225 *
226 * @see NanoAppFilter
227 *
destradaa8bad3fe2016-03-15 12:33:40 -0700228 * @return int[] Array of handles to any found nano apps
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800229 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -0600230 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
Arthur Ishiguroac7b9592018-01-02 09:46:42 -0800231 @NonNull public int[] findNanoAppOnHub(int hubHandle, @NonNull NanoAppFilter filter) {
Peng Xu9ff7d222016-02-11 13:02:05 -0800232 try {
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600233 return mService.findNanoAppOnHub(hubHandle, filter);
Peng Xu9ff7d222016-02-11 13:02:05 -0800234 } catch (RemoteException e) {
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600235 throw e.rethrowFromSystemServer();
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800236 }
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800237 }
238
239 /**
destradaa8bad3fe2016-03-15 12:33:40 -0700240 * Send a message to a specific nano app instance on a context hub.
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800241 *
Greg Kaiserfac5be22016-08-17 15:33:10 -0700242 * Note that the return value of this method only speaks of success
243 * up to the point of sending this to the Context Hub. It is not
244 * an assurance that the Context Hub successfully sent this message
245 * on to the nanoapp. If assurance is desired, a protocol should be
246 * established between your code and the nanoapp, with the nanoapp
247 * sending a confirmation message (which will be reported via
248 * Callback.onMessageReceipt).
249 *
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800250 * @param hubHandle handle of the hub to send the message to
251 * @param nanoAppHandle handle of the nano app to send to
destradaa8bad3fe2016-03-15 12:33:40 -0700252 * @param message Message to be sent
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800253 *
254 * @see ContextHubMessage
255 *
256 * @return int 0 on success, -1 otherwise
257 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -0600258 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
Arthur Ishiguroac7b9592018-01-02 09:46:42 -0800259 public int sendMessage(int hubHandle, int nanoAppHandle, @NonNull ContextHubMessage message) {
Peng Xu9ff7d222016-02-11 13:02:05 -0800260 try {
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600261 return mService.sendMessage(hubHandle, nanoAppHandle, message);
Peng Xu9ff7d222016-02-11 13:02:05 -0800262 } catch (RemoteException e) {
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600263 throw e.rethrowFromSystemServer();
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800264 }
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800265 }
266
Peng Xu9ff7d222016-02-11 13:02:05 -0800267 /**
Arthur Ishigurofdbbd462017-11-27 16:33:36 -0800268 * Returns the list of ContextHubInfo objects describing the available Context Hubs.
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700269 *
Arthur Ishigurofdbbd462017-11-27 16:33:36 -0800270 * @return the list of ContextHubInfo objects
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700271 *
272 * @see ContextHubInfo
273 *
274 * @hide
275 */
276 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
Arthur Ishiguroac7b9592018-01-02 09:46:42 -0800277 @NonNull public List<ContextHubInfo> getContextHubs() {
Arthur Ishigurofdbbd462017-11-27 16:33:36 -0800278 try {
279 return mService.getContextHubs();
280 } catch (RemoteException e) {
281 throw e.rethrowFromSystemServer();
282 }
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700283 }
284
Arthur Ishiguro0ed545c2017-12-12 15:01:32 -0800285 /**
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -0700286 * Helper function to generate a stub for a non-query transaction callback.
287 *
288 * @param transaction the transaction to unblock when complete
289 *
290 * @return the callback
291 *
292 * @hide
293 */
294 private IContextHubTransactionCallback createTransactionCallback(
295 ContextHubTransaction<Void> transaction) {
296 return new IContextHubTransactionCallback.Stub() {
297 @Override
298 public void onQueryResponse(int result, List<NanoAppState> nanoappList) {
299 Log.e(TAG, "Received a query callback on a non-query request");
300 transaction.setResponse(new ContextHubTransaction.Response<Void>(
Arthur Ishiguro6100aa72017-12-20 09:35:00 -0800301 ContextHubTransaction.RESULT_FAILED_SERVICE_INTERNAL_FAILURE, null));
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -0700302 }
303
304 @Override
305 public void onTransactionComplete(int result) {
306 transaction.setResponse(new ContextHubTransaction.Response<Void>(result, null));
307 }
308 };
309 }
310
Arthur Ishiguro0ed545c2017-12-12 15:01:32 -0800311 /**
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -0700312 * Helper function to generate a stub for a query transaction callback.
313 *
314 * @param transaction the transaction to unblock when complete
315 *
316 * @return the callback
317 *
318 * @hide
319 */
320 private IContextHubTransactionCallback createQueryCallback(
321 ContextHubTransaction<List<NanoAppState>> transaction) {
322 return new IContextHubTransactionCallback.Stub() {
323 @Override
324 public void onQueryResponse(int result, List<NanoAppState> nanoappList) {
325 transaction.setResponse(new ContextHubTransaction.Response<List<NanoAppState>>(
326 result, nanoappList));
327 }
328
329 @Override
330 public void onTransactionComplete(int result) {
331 Log.e(TAG, "Received a non-query callback on a query request");
332 transaction.setResponse(new ContextHubTransaction.Response<List<NanoAppState>>(
Arthur Ishiguro6100aa72017-12-20 09:35:00 -0800333 ContextHubTransaction.RESULT_FAILED_SERVICE_INTERNAL_FAILURE, null));
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -0700334 }
335 };
336 }
337
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700338 /**
339 * Loads a nanoapp at the specified Context Hub.
340 *
341 * After the nanoapp binary is successfully loaded at the specified hub, the nanoapp will be in
342 * the enabled state.
343 *
344 * @param hubInfo the hub to load the nanoapp on
345 * @param appBinary The app binary to load
346 *
347 * @return the ContextHubTransaction of the request
348 *
Arthur Ishiguroac7b9592018-01-02 09:46:42 -0800349 * @throws NullPointerException if hubInfo or NanoAppBinary is null
350 *
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700351 * @see NanoAppBinary
352 *
353 * @hide
354 */
355 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
Arthur Ishiguroac7b9592018-01-02 09:46:42 -0800356 @NonNull public ContextHubTransaction<Void> loadNanoApp(
357 @NonNull ContextHubInfo hubInfo, @NonNull NanoAppBinary appBinary) {
358 Preconditions.checkNotNull(hubInfo, "ContextHubInfo cannot be null");
359 Preconditions.checkNotNull(appBinary, "NanoAppBinary cannot be null");
360
Arthur Ishiguroe1ade432017-11-27 10:45:33 -0800361 ContextHubTransaction<Void> transaction =
362 new ContextHubTransaction<>(ContextHubTransaction.TYPE_LOAD_NANOAPP);
363 IContextHubTransactionCallback callback = createTransactionCallback(transaction);
364
365 try {
366 mService.loadNanoAppOnHub(hubInfo.getId(), callback, appBinary);
367 } catch (RemoteException e) {
368 throw e.rethrowFromSystemServer();
369 }
370
371 return transaction;
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700372 }
373
374 /**
375 * Unloads a nanoapp at the specified Context Hub.
376 *
377 * @param hubInfo the hub to unload the nanoapp from
378 * @param nanoAppId the app to unload
379 *
380 * @return the ContextHubTransaction of the request
381 *
Arthur Ishiguroac7b9592018-01-02 09:46:42 -0800382 * @throws NullPointerException if hubInfo is null
383 *
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700384 * @hide
385 */
386 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
Arthur Ishiguroac7b9592018-01-02 09:46:42 -0800387 @NonNull public ContextHubTransaction<Void> unloadNanoApp(
388 @NonNull ContextHubInfo hubInfo, long nanoAppId) {
389 Preconditions.checkNotNull(hubInfo, "ContextHubInfo cannot be null");
390
Arthur Ishiguroe1ade432017-11-27 10:45:33 -0800391 ContextHubTransaction<Void> transaction =
392 new ContextHubTransaction<>(ContextHubTransaction.TYPE_UNLOAD_NANOAPP);
393 IContextHubTransactionCallback callback = createTransactionCallback(transaction);
394
395 try {
396 mService.unloadNanoAppFromHub(hubInfo.getId(), callback, nanoAppId);
397 } catch (RemoteException e) {
398 throw e.rethrowFromSystemServer();
399 }
400
401 return transaction;
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700402 }
403
404 /**
405 * Enables a nanoapp at the specified Context Hub.
406 *
407 * @param hubInfo the hub to enable the nanoapp on
408 * @param nanoAppId the app to enable
409 *
410 * @return the ContextHubTransaction of the request
411 *
Arthur Ishiguroac7b9592018-01-02 09:46:42 -0800412 * @throws NullPointerException if hubInfo is null
413 *
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700414 * @hide
415 */
416 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
Arthur Ishiguroac7b9592018-01-02 09:46:42 -0800417 @NonNull public ContextHubTransaction<Void> enableNanoApp(
418 @NonNull ContextHubInfo hubInfo, long nanoAppId) {
419 Preconditions.checkNotNull(hubInfo, "ContextHubInfo cannot be null");
420
Arthur Ishiguro0ed545c2017-12-12 15:01:32 -0800421 ContextHubTransaction<Void> transaction =
422 new ContextHubTransaction<>(ContextHubTransaction.TYPE_ENABLE_NANOAPP);
423 IContextHubTransactionCallback callback = createTransactionCallback(transaction);
424
425 try {
426 mService.enableNanoApp(hubInfo.getId(), callback, nanoAppId);
427 } catch (RemoteException e) {
428 throw e.rethrowFromSystemServer();
429 }
430
431 return transaction;
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700432 }
433
434 /**
435 * Disables a nanoapp at the specified Context Hub.
436 *
437 * @param hubInfo the hub to disable the nanoapp on
438 * @param nanoAppId the app to disable
439 *
440 * @return the ContextHubTransaction of the request
441 *
Arthur Ishiguroac7b9592018-01-02 09:46:42 -0800442 * @throws NullPointerException if hubInfo is null
443 *
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700444 * @hide
445 */
446 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
Arthur Ishiguroac7b9592018-01-02 09:46:42 -0800447 @NonNull public ContextHubTransaction<Void> disableNanoApp(
448 @NonNull ContextHubInfo hubInfo, long nanoAppId) {
449 Preconditions.checkNotNull(hubInfo, "ContextHubInfo cannot be null");
450
Arthur Ishiguro54e1a892017-12-12 15:09:31 -0800451 ContextHubTransaction<Void> transaction =
452 new ContextHubTransaction<>(ContextHubTransaction.TYPE_DISABLE_NANOAPP);
453 IContextHubTransactionCallback callback = createTransactionCallback(transaction);
454
455 try {
456 mService.disableNanoApp(hubInfo.getId(), callback, nanoAppId);
457 } catch (RemoteException e) {
458 throw e.rethrowFromSystemServer();
459 }
460
461 return transaction;
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700462 }
463
464 /**
465 * Requests a query for nanoapps loaded at the specified Context Hub.
466 *
467 * @param hubInfo the hub to query a list of nanoapps from
468 *
469 * @return the ContextHubTransaction of the request
470 *
Arthur Ishiguroac7b9592018-01-02 09:46:42 -0800471 * @throws NullPointerException if hubInfo is null
472 *
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700473 * @hide
474 */
475 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
Arthur Ishiguroac7b9592018-01-02 09:46:42 -0800476 @NonNull public ContextHubTransaction<List<NanoAppState>> queryNanoApps(
477 @NonNull ContextHubInfo hubInfo) {
478 Preconditions.checkNotNull(hubInfo, "ContextHubInfo cannot be null");
479
Arthur Ishiguro4493e142017-11-27 16:26:34 -0800480 ContextHubTransaction<List<NanoAppState>> transaction =
481 new ContextHubTransaction<>(ContextHubTransaction.TYPE_QUERY_NANOAPPS);
482 IContextHubTransactionCallback callback = createQueryCallback(transaction);
483
484 try {
485 mService.queryNanoApps(hubInfo.getId(), callback);
486 } catch (RemoteException e) {
487 throw e.rethrowFromSystemServer();
488 }
489
490 return transaction;
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700491 }
492
493 /**
Peng Xu9ff7d222016-02-11 13:02:05 -0800494 * Set a callback to receive messages from the context hub
495 *
Peng Xu9ff7d222016-02-11 13:02:05 -0800496 * @param callback Callback object
497 *
Greg Kaiser6ba60e62016-03-18 10:08:39 -0700498 * @see Callback
Peng Xu9ff7d222016-02-11 13:02:05 -0800499 *
500 * @return int 0 on success, -1 otherwise
501 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -0600502 @SuppressLint("Doclava125")
Arthur Ishiguroac7b9592018-01-02 09:46:42 -0800503 public int registerCallback(@NonNull Callback callback) {
Greg Kaiser6ba60e62016-03-18 10:08:39 -0700504 return registerCallback(callback, null);
Peng Xu9ff7d222016-02-11 13:02:05 -0800505 }
506
507 /**
destradaa78cebca2016-04-14 18:40:14 -0700508 * @deprecated Use {@link #registerCallback(Callback)} instead.
509 * @hide
510 */
511 @Deprecated
512 public int registerCallback(ICallback callback) {
513 if (mLocalCallback != null) {
514 Log.w(TAG, "Max number of local callbacks reached!");
515 return -1;
516 }
517 mLocalCallback = callback;
518 return 0;
519 }
520
521 /**
Peng Xu9ff7d222016-02-11 13:02:05 -0800522 * Set a callback to receive messages from the context hub
523 *
Peng Xu9ff7d222016-02-11 13:02:05 -0800524 * @param callback Callback object
destradaa8bad3fe2016-03-15 12:33:40 -0700525 * @param handler Handler object
Peng Xu9ff7d222016-02-11 13:02:05 -0800526 *
Greg Kaiser6ba60e62016-03-18 10:08:39 -0700527 * @see Callback
Peng Xu9ff7d222016-02-11 13:02:05 -0800528 *
529 * @return int 0 on success, -1 otherwise
530 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -0600531 @SuppressLint("Doclava125")
Greg Kaiser6ba60e62016-03-18 10:08:39 -0700532 public int registerCallback(Callback callback, Handler handler) {
Peng Xu9ff7d222016-02-11 13:02:05 -0800533 synchronized(this) {
534 if (mCallback != null) {
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700535 Log.w(TAG, "Max number of callbacks reached!");
Peng Xu9ff7d222016-02-11 13:02:05 -0800536 return -1;
537 }
538 mCallback = callback;
539 mCallbackHandler = handler;
540 }
541 return 0;
542 }
543
544 /**
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800545 * Creates an interface to the ContextHubClient to send down to the service.
546 *
547 * @param callback the callback to invoke at the client process
Arthur Ishiguroe35a6de2017-12-20 15:30:51 -0800548 * @param executor the executor to invoke callbacks for this client
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800549 *
550 * @return the callback interface
551 */
552 private IContextHubClientCallback createClientCallback(
Arthur Ishiguroe35a6de2017-12-20 15:30:51 -0800553 ContextHubClientCallback callback, Executor executor) {
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800554 return new IContextHubClientCallback.Stub() {
555 @Override
556 public void onMessageFromNanoApp(NanoAppMessage message) {
Arthur Ishiguroe35a6de2017-12-20 15:30:51 -0800557 executor.execute(() -> callback.onMessageFromNanoApp(message));
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800558 }
559
560 @Override
561 public void onHubReset() {
Arthur Ishiguroe35a6de2017-12-20 15:30:51 -0800562 executor.execute(() -> callback.onHubReset());
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800563 }
564
565 @Override
566 public void onNanoAppAborted(long nanoAppId, int abortCode) {
Arthur Ishiguroe35a6de2017-12-20 15:30:51 -0800567 executor.execute(() -> callback.onNanoAppAborted(nanoAppId, abortCode));
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800568 }
569
570 @Override
571 public void onNanoAppLoaded(long nanoAppId) {
Arthur Ishiguroe35a6de2017-12-20 15:30:51 -0800572 executor.execute(() -> callback.onNanoAppLoaded(nanoAppId));
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800573 }
574
575 @Override
576 public void onNanoAppUnloaded(long nanoAppId) {
Arthur Ishiguroe35a6de2017-12-20 15:30:51 -0800577 executor.execute(() -> callback.onNanoAppUnloaded(nanoAppId));
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800578 }
579
580 @Override
581 public void onNanoAppEnabled(long nanoAppId) {
Arthur Ishiguroe35a6de2017-12-20 15:30:51 -0800582 executor.execute(() -> callback.onNanoAppEnabled(nanoAppId));
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800583 }
584
585 @Override
586 public void onNanoAppDisabled(long nanoAppId) {
Arthur Ishiguroe35a6de2017-12-20 15:30:51 -0800587 executor.execute(() -> callback.onNanoAppDisabled(nanoAppId));
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800588 }
589 };
590 }
591
592 /**
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700593 * Creates and registers a client and its callback with the Context Hub Service.
594 *
595 * A client is registered with the Context Hub Service for a specified Context Hub. When the
596 * registration succeeds, the client can send messages to nanoapps through the returned
597 * {@link ContextHubClient} object, and receive notifications through the provided callback.
598 *
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800599 * @param hubInfo the hub to attach this client to
Arthur Ishiguroe35a6de2017-12-20 15:30:51 -0800600 * @param callback the notification callback to register
601 * @param executor the executor to invoke the callback
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700602 * @return the registered client object
603 *
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800604 * @throws IllegalArgumentException if hubInfo does not represent a valid hub
605 * @throws IllegalStateException if there were too many registered clients at the service
Arthur Ishiguroac7b9592018-01-02 09:46:42 -0800606 * @throws NullPointerException if callback, hubInfo, or executor is null
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700607 *
608 * @hide
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800609 * @see ContextHubClientCallback
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700610 */
Arthur Ishiguroe35a6de2017-12-20 15:30:51 -0800611 @NonNull public ContextHubClient createClient(
612 @NonNull ContextHubInfo hubInfo, @NonNull ContextHubClientCallback callback,
613 @NonNull @CallbackExecutor Executor executor) {
Arthur Ishiguroac7b9592018-01-02 09:46:42 -0800614 Preconditions.checkNotNull(callback, "Callback cannot be null");
615 Preconditions.checkNotNull(hubInfo, "ContextHubInfo cannot be null");
616 Preconditions.checkNotNull(executor, "Executor cannot be null");
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800617
Arthur Ishiguroe35a6de2017-12-20 15:30:51 -0800618 IContextHubClientCallback clientInterface = createClientCallback(callback, executor);
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800619
620 IContextHubClient client;
621 try {
622 client = mService.createClient(clientInterface, hubInfo.getId());
623 } catch (RemoteException e) {
624 throw e.rethrowFromSystemServer();
625 }
626
627 return new ContextHubClient(client, clientInterface, hubInfo);
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700628 }
629
630 /**
Arthur Ishiguro9b9c9d82017-12-20 16:11:53 -0800631 * Equivalent to {@link #createClient(ContextHubInfo, ContextHubClientCallback, Executor)}
632 * with the executor using the main thread's Looper.
633 *
634 * @param hubInfo the hub to attach this client to
635 * @param callback the notification callback to register
636 * @return the registered client object
637 *
638 * @throws IllegalArgumentException if hubInfo does not represent a valid hub
639 * @throws IllegalStateException if there were too many registered clients at the service
640 * @throws NullPointerException if callback or hubInfo is null
641 * @hide
642 * @see ContextHubClientCallback
643 */
644 @NonNull public ContextHubClient createClient(
645 @NonNull ContextHubInfo hubInfo, @NonNull ContextHubClientCallback callback) {
646 return createClient(hubInfo, callback, new HandlerExecutor(Handler.getMain()));
647 }
648
649 /**
destradaa8bad3fe2016-03-15 12:33:40 -0700650 * Unregister a callback for receive messages from the context hub.
Peng Xu9ff7d222016-02-11 13:02:05 -0800651 *
Greg Kaiser6ba60e62016-03-18 10:08:39 -0700652 * @see Callback
Peng Xu9ff7d222016-02-11 13:02:05 -0800653 *
654 * @param callback method to deregister
655 *
656 * @return int 0 on success, -1 otherwise
657 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -0600658 @SuppressLint("Doclava125")
Arthur Ishiguroac7b9592018-01-02 09:46:42 -0800659 public int unregisterCallback(@NonNull Callback callback) {
Peng Xu9ff7d222016-02-11 13:02:05 -0800660 synchronized(this) {
661 if (callback != mCallback) {
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700662 Log.w(TAG, "Cannot recognize callback!");
Peng Xu9ff7d222016-02-11 13:02:05 -0800663 return -1;
664 }
665
666 mCallback = null;
667 mCallbackHandler = null;
668 }
669 return 0;
670 }
671
destradaa78cebca2016-04-14 18:40:14 -0700672 /**
673 * @deprecated Use {@link #unregisterCallback(Callback)} instead.
674 * @hide
675 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -0700676 @Deprecated
destradaa78cebca2016-04-14 18:40:14 -0700677 public synchronized int unregisterCallback(ICallback callback) {
678 if (callback != mLocalCallback) {
679 Log.w(TAG, "Cannot recognize local callback!");
680 return -1;
681 }
682 mLocalCallback = null;
683 return 0;
684 }
685
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600686 private final IContextHubCallback.Stub mClientCallback = new IContextHubCallback.Stub() {
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800687 @Override
Peng Xu9ff7d222016-02-11 13:02:05 -0800688 public void onMessageReceipt(final int hubId, final int nanoAppId,
destradaa8bad3fe2016-03-15 12:33:40 -0700689 final ContextHubMessage message) {
Peng Xu9ff7d222016-02-11 13:02:05 -0800690 if (mCallback != null) {
691 synchronized(this) {
Greg Kaiser6ba60e62016-03-18 10:08:39 -0700692 final Callback callback = mCallback;
Peng Xu9ff7d222016-02-11 13:02:05 -0800693 Handler handler = mCallbackHandler == null ?
694 new Handler(mMainLooper) : mCallbackHandler;
695 handler.post(new Runnable() {
696 @Override
697 public void run() {
698 callback.onMessageReceipt(hubId, nanoAppId, message);
699 }
700 });
701 }
destradaa78cebca2016-04-14 18:40:14 -0700702 } else if (mLocalCallback != null) {
703 // we always ensure that mCallback takes precedence, because mLocalCallback is only
704 // for internal compatibility
705 synchronized (this) {
706 mLocalCallback.onMessageReceipt(hubId, nanoAppId, message);
707 }
Peng Xu9ff7d222016-02-11 13:02:05 -0800708 } else {
709 Log.d(TAG, "Context hub manager client callback is NULL");
710 }
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800711 }
712 };
713
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600714 /** @throws ServiceNotFoundException
715 * @hide */
716 public ContextHubManager(Context context, Looper mainLooper) throws ServiceNotFoundException {
Peng Xu9ff7d222016-02-11 13:02:05 -0800717 mMainLooper = mainLooper;
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600718 mService = IContextHubService.Stub.asInterface(
Ashutosh Joshi420e45e2016-12-20 16:34:41 -0800719 ServiceManager.getServiceOrThrow(Context.CONTEXTHUB_SERVICE));
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600720 try {
721 mService.registerCallback(mClientCallback);
722 } catch (RemoteException e) {
723 Log.w(TAG, "Could not register callback:" + e);
Peng Xu9ff7d222016-02-11 13:02:05 -0800724 }
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800725 }
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800726}