| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package android.hardware.location; |
| |
| import android.annotation.SystemApi; |
| import android.content.Context; |
| import android.os.Handler; |
| import android.os.IBinder; |
| import android.os.Looper; |
| import android.os.RemoteException; |
| import android.os.ServiceManager; |
| import android.util.Log; |
| |
| /** |
| * A class that exposes the Context hubs on a device to applications. |
| * |
| * Please note that this class is not expected to be used by unbundled applications. Also, calling |
| * applications are expected to have LOCATION_HARDWARE permissions to use this class. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public final class ContextHubManager { |
| |
| private static final String TAG = "ContextHubManager"; |
| |
| private final Looper mMainLooper; |
| private IContextHubService mContextHubService; |
| private Callback mCallback; |
| private Handler mCallbackHandler; |
| |
| /** |
| * @deprecated Use {@code mCallback} instead. |
| */ |
| @Deprecated |
| private ICallback mLocalCallback; |
| |
| /** |
| * An interface to receive asynchronous communication from the context hub. |
| */ |
| public abstract static class Callback { |
| protected Callback() {} |
| |
| /** |
| * Callback function called on message receipt from context hub. |
| * |
| * @param hubHandle Handle (system-wide unique identifier) of the hub of the message. |
| * @param nanoAppHandle Handle (unique identifier) for app instance that sent the message. |
| * @param message The context hub message. |
| * |
| * @see ContextHubMessage |
| */ |
| public abstract void onMessageReceipt( |
| int hubHandle, |
| int nanoAppHandle, |
| ContextHubMessage message); |
| } |
| |
| /** |
| * @deprecated Use {@link Callback} instead. |
| * @hide |
| */ |
| @Deprecated |
| public interface ICallback { |
| /** |
| * Callback function called on message receipt from context hub. |
| * |
| * @param hubHandle Handle (system-wide unique identifier) of the hub of the message. |
| * @param nanoAppHandle Handle (unique identifier) for app instance that sent the message. |
| * @param message The context hub message. |
| * |
| * @see ContextHubMessage |
| */ |
| void onMessageReceipt(int hubHandle, int nanoAppHandle, ContextHubMessage message); |
| } |
| |
| /** |
| * Get a handle to all the context hubs in the system |
| * @return array of context hub handles |
| */ |
| public int[] getContextHubHandles() { |
| int[] retVal = null; |
| try { |
| retVal = getBinder().getContextHubHandles(); |
| } catch (RemoteException e) { |
| Log.w(TAG, "Could not fetch context hub handles : " + e); |
| } |
| return retVal; |
| } |
| |
| /** |
| * Get more information about a specific hub. |
| * |
| * @param hubHandle Handle (system-wide unique identifier) of a context hub. |
| * @return ContextHubInfo Information about the requested context hub. |
| * |
| * @see ContextHubInfo |
| */ |
| public ContextHubInfo getContextHubInfo(int hubHandle) { |
| ContextHubInfo retVal = null; |
| try { |
| retVal = getBinder().getContextHubInfo(hubHandle); |
| } catch (RemoteException e) { |
| Log.w(TAG, "Could not fetch context hub info :" + e); |
| } |
| |
| return retVal; |
| } |
| |
| /** |
| * Load a nano app on a specified context hub. |
| * |
| * Note that loading is asynchronous. When we return from this method, |
| * the nano app (probably) hasn't loaded yet. Assuming a return of 0 |
| * from this method, then the final success/failure for the load, along |
| * with the "handle" for the nanoapp, is all delivered in a byte |
| * string via a call to Callback.onMessageReceipt. |
| * |
| * TODO(b/30784270): Provide a better success/failure and "handle" delivery. |
| * |
| * @param hubHandle handle of context hub to load the app on. |
| * @param app the nanoApp to load on the hub |
| * |
| * @return 0 if the command for loading was sent to the context hub; |
| * -1 otherwise |
| * |
| * @see NanoApp |
| */ |
| public int loadNanoApp(int hubHandle, NanoApp app) { |
| int retVal = -1; |
| |
| if (app == null) { |
| return retVal; |
| } |
| |
| try { |
| retVal = getBinder().loadNanoApp(hubHandle, app); |
| } catch (RemoteException e) { |
| Log.w(TAG, "Could not load nanoApp :" + e); |
| } |
| |
| return retVal; |
| } |
| |
| /** |
| * Unload a specified nanoApp |
| * |
| * Note that unloading is asynchronous. When we return from this method, |
| * the nano app (probably) hasn't unloaded yet. Assuming a return of 0 |
| * from this method, then the final success/failure for the unload is |
| * delivered in a byte string via a call to Callback.onMessageReceipt. |
| * |
| * TODO(b/30784270): Provide a better success/failure delivery. |
| * |
| * @param nanoAppHandle handle of the nanoApp to unload |
| * |
| * @return 0 if the command for unloading was sent to the context hub; |
| * -1 otherwise |
| */ |
| public int unloadNanoApp(int nanoAppHandle) { |
| int retVal = -1; |
| |
| try { |
| retVal = getBinder().unloadNanoApp(nanoAppHandle); |
| } catch (RemoteException e) { |
| Log.w(TAG, "Could not fetch unload nanoApp :" + e); |
| } |
| |
| return retVal; |
| } |
| |
| /** |
| * get information about the nano app instance |
| * |
| * NOTE: The returned NanoAppInstanceInfo does _not_ contain correct |
| * information for several fields, specifically: |
| * - getName() |
| * - getPublisher() |
| * - getNeededExecMemBytes() |
| * - getNeededReadMemBytes() |
| * - getNeededWriteMemBytes() |
| * |
| * For example, say you call loadNanoApp() with a NanoApp that has |
| * getName() returning "My Name". Later, if you call getNanoAppInstanceInfo |
| * for that nanoapp, the returned NanoAppInstanceInfo's getName() |
| * method will claim "Preloaded app, unknown", even though you would |
| * have expected "My Name". For now, as the user, you'll need to |
| * separately track the above fields if they are of interest to you. |
| * |
| * TODO(b/30943489): Have the returned NanoAppInstanceInfo contain the |
| * correct information. |
| * |
| * @param nanoAppHandle handle of the nanoAppInstance |
| * @return NanoAppInstanceInfo Information about the nano app instance. |
| * |
| * @see NanoAppInstanceInfo |
| */ |
| public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppHandle) { |
| NanoAppInstanceInfo retVal = null; |
| |
| try { |
| retVal = getBinder().getNanoAppInstanceInfo(nanoAppHandle); |
| } catch (RemoteException e) { |
| Log.w(TAG, "Could not fetch nanoApp info :" + e); |
| } |
| |
| return retVal; |
| } |
| |
| /** |
| * Find a specified nano app on the system |
| * |
| * @param hubHandle handle of hub to search for nano app |
| * @param filter filter specifying the search criteria for app |
| * |
| * @see NanoAppFilter |
| * |
| * @return int[] Array of handles to any found nano apps |
| */ |
| public int[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) { |
| int[] retVal = null; |
| try { |
| retVal = getBinder().findNanoAppOnHub(hubHandle, filter); |
| } catch (RemoteException e) { |
| Log.w(TAG, "Could not query nanoApp instance :" + e); |
| } |
| return retVal; |
| } |
| |
| /** |
| * Send a message to a specific nano app instance on a context hub. |
| * |
| * Note that the return value of this method only speaks of success |
| * up to the point of sending this to the Context Hub. It is not |
| * an assurance that the Context Hub successfully sent this message |
| * on to the nanoapp. If assurance is desired, a protocol should be |
| * established between your code and the nanoapp, with the nanoapp |
| * sending a confirmation message (which will be reported via |
| * Callback.onMessageReceipt). |
| * |
| * @param hubHandle handle of the hub to send the message to |
| * @param nanoAppHandle handle of the nano app to send to |
| * @param message Message to be sent |
| * |
| * @see ContextHubMessage |
| * |
| * @return int 0 on success, -1 otherwise |
| */ |
| public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage message) { |
| int retVal = -1; |
| |
| if (message == null || message.getData() == null) { |
| Log.w(TAG, "null ptr"); |
| return retVal; |
| } |
| try { |
| retVal = getBinder().sendMessage(hubHandle, nanoAppHandle, message); |
| } catch (RemoteException e) { |
| Log.w(TAG, "Could not send message :" + e.toString()); |
| } |
| |
| return retVal; |
| } |
| |
| /** |
| * Set a callback to receive messages from the context hub |
| * |
| * @param callback Callback object |
| * |
| * @see Callback |
| * |
| * @return int 0 on success, -1 otherwise |
| */ |
| public int registerCallback(Callback callback) { |
| return registerCallback(callback, null); |
| } |
| |
| /** |
| * @deprecated Use {@link #registerCallback(Callback)} instead. |
| * @hide |
| */ |
| @Deprecated |
| public int registerCallback(ICallback callback) { |
| if (mLocalCallback != null) { |
| Log.w(TAG, "Max number of local callbacks reached!"); |
| return -1; |
| } |
| mLocalCallback = callback; |
| return 0; |
| } |
| |
| /** |
| * Set a callback to receive messages from the context hub |
| * |
| * @param callback Callback object |
| * @param handler Handler object |
| * |
| * @see Callback |
| * |
| * @return int 0 on success, -1 otherwise |
| */ |
| public int registerCallback(Callback callback, Handler handler) { |
| synchronized(this) { |
| if (mCallback != null) { |
| Log.w(TAG, "Max number of callbacks reached!"); |
| return -1; |
| } |
| mCallback = callback; |
| mCallbackHandler = handler; |
| } |
| return 0; |
| } |
| |
| /** |
| * Unregister a callback for receive messages from the context hub. |
| * |
| * @see Callback |
| * |
| * @param callback method to deregister |
| * |
| * @return int 0 on success, -1 otherwise |
| */ |
| public int unregisterCallback(Callback callback) { |
| synchronized(this) { |
| if (callback != mCallback) { |
| Log.w(TAG, "Cannot recognize callback!"); |
| return -1; |
| } |
| |
| mCallback = null; |
| mCallbackHandler = null; |
| } |
| return 0; |
| } |
| |
| /** |
| * @deprecated Use {@link #unregisterCallback(Callback)} instead. |
| * @hide |
| */ |
| public synchronized int unregisterCallback(ICallback callback) { |
| if (callback != mLocalCallback) { |
| Log.w(TAG, "Cannot recognize local callback!"); |
| return -1; |
| } |
| mLocalCallback = null; |
| return 0; |
| } |
| |
| private IContextHubCallback.Stub mClientCallback = new IContextHubCallback.Stub() { |
| @Override |
| public void onMessageReceipt(final int hubId, final int nanoAppId, |
| final ContextHubMessage message) { |
| if (mCallback != null) { |
| synchronized(this) { |
| final Callback callback = mCallback; |
| Handler handler = mCallbackHandler == null ? |
| new Handler(mMainLooper) : mCallbackHandler; |
| handler.post(new Runnable() { |
| @Override |
| public void run() { |
| callback.onMessageReceipt(hubId, nanoAppId, message); |
| } |
| }); |
| } |
| } else if (mLocalCallback != null) { |
| // we always ensure that mCallback takes precedence, because mLocalCallback is only |
| // for internal compatibility |
| synchronized (this) { |
| mLocalCallback.onMessageReceipt(hubId, nanoAppId, message); |
| } |
| } else { |
| Log.d(TAG, "Context hub manager client callback is NULL"); |
| } |
| } |
| }; |
| |
| /** @hide */ |
| public ContextHubManager(Context context, Looper mainLooper) { |
| mMainLooper = mainLooper; |
| |
| IBinder b = ServiceManager.getService(ContextHubService.CONTEXTHUB_SERVICE); |
| if (b != null) { |
| mContextHubService = IContextHubService.Stub.asInterface(b); |
| |
| try { |
| getBinder().registerCallback(mClientCallback); |
| } catch (RemoteException e) { |
| Log.w(TAG, "Could not register callback:" + e); |
| } |
| |
| } else { |
| Log.w(TAG, "failed to getService"); |
| } |
| } |
| |
| private IContextHubService getBinder() throws RemoteException { |
| if (mContextHubService == null) { |
| throw new RemoteException("Service not connected."); |
| } |
| return mContextHubService; |
| } |
| } |