Exposing Context Hub service.

Adding the Context hub service. This is the service that exposes
the context hub HAL to the system. The API exposed is a System API.

Change-Id: I854141714ecd21f6386e6b15b7bc9a997483ccf6
diff --git a/core/java/android/hardware/location/ContextHubService.java b/core/java/android/hardware/location/ContextHubService.java
index a2a13c6..658d90b 100644
--- a/core/java/android/hardware/location/ContextHubService.java
+++ b/core/java/android/hardware/location/ContextHubService.java
@@ -29,175 +29,157 @@
 /**
  * @hide
  */
-public class ContextHubService extends Service {
+public class ContextHubService extends IContextHubService.Stub {
 
     private static final String TAG = "ContextHubService";
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
-    private static ContextHubService sSingletonInstance;
-    private static final Object sSingletonInstanceLock = new Object();
+    public static final String CONTEXTHUB_SERVICE = "contexthub_service";
 
-    private HashMap<Integer, ContextHubInfo> mHubHash;
+    private final Context mContext;
+
     private HashMap<Integer, NanoAppInstanceInfo> mNanoAppHash;
-    private ContextHubInfo[] mContexthubInfo;
+    private ContextHubInfo[] mContextHubInfo;
+    private IContextHubCallback mCallback;
 
+    public ContextHubService(Context context) {
+        mContext = context;
+        mContextHubInfo = nativeInitialize();
+
+        for (int i = 0; i < mContextHubInfo.length; i++) {
+            Log.v(TAG, "ContextHub[" + i + "] id: " + mContextHubInfo[i].getId()
+                  + ", name:  " + mContextHubInfo[i].getName());
+        }
+    }
 
     private native int nativeSendMessage(int[] header, byte[] data);
     private native ContextHubInfo[] nativeInitialize();
 
-    private int onMessageReceipt(int[] header, byte[] data) {
+    @Override
+    public int registerCallback(IContextHubCallback callback) throws RemoteException{
+        mCallback = callback;
         return 0;
     }
-    private void initialize() {
-        mContexthubInfo = nativeInitialize();
 
-        mHubHash = new HashMap<Integer, ContextHubInfo>();
 
-        for (int i = 0; i < mContexthubInfo.length; i++) {
-            mHubHash.put(i + 1, mContexthubInfo[i]); // Avoiding zero
-        }
-    }
+    private int onMessageReceipt(int[] header, byte[] data) {
+        if (mCallback != null) {
+            // TODO : Defend against unexpected header sizes
+            //        Add abstraction for magic numbers
+            //        onMessageRecipt should pass the right arguments
+            ContextHubMessage msg = new ContextHubMessage(header[0], header[1], data);
 
-    private ContextHubService(Context context) {
-        initialize();
-        Log.d(TAG, "Created from " + context.toString());
-    }
-
-    public static ContextHubService getInstance(Context context) {
-        synchronized (sSingletonInstanceLock) {
-            if (sSingletonInstance == null) {
-                sSingletonInstance = new ContextHubService(context);
+            try {
+                mCallback.onMessageReceipt(0, 0, msg);
+            } catch (Exception e) {
+                Log.e(TAG, "Exception " + e + " when calling remote callback");
+                return -1;
             }
-            return sSingletonInstance;
+        } else {
+            Log.d(TAG, "Message Callback is NULL");
+        }
+
+        return 0;
+    }
+
+    @Override
+    public int[] getContextHubHandles() throws RemoteException {
+        int [] returnArray = new int[mContextHubInfo.length];
+
+        for (int i = 0; i < returnArray.length; ++i) {
+            returnArray[i] = i + 1; //valid handles from 1...n
+            Log.d(TAG, String.format("Hub %s is mapped to %d",
+                                     mContextHubInfo[i].getName(), returnArray[i]));
+        }
+
+        return returnArray;
+    }
+
+    @Override
+    public ContextHubInfo getContextHubInfo(int contextHubHandle) throws RemoteException {
+        contextHubHandle -= 1;
+        if (!(contextHubHandle >= 0 && contextHubHandle < mContextHubInfo.length)) {
+            return null; // null means fail
+        }
+
+        return mContextHubInfo[contextHubHandle];
+    }
+
+    @Override
+    public int loadNanoApp(int contextHubHandle, NanoApp app) throws RemoteException {
+        contextHubHandle -= 1;
+
+        if (!(contextHubHandle >= 0 && contextHubHandle < mContextHubInfo.length)) {
+            return -1; // negative handle are invalid, means failed
+        }
+
+        // Call Native interface here
+        int[] msgHeader = new int[8];
+        msgHeader[0] = contextHubHandle;
+        msgHeader[1] = app.getAppId();
+        msgHeader[2] = app.getAppVersion();
+        msgHeader[3] = ContextHubManager.MSG_LOAD_NANO_APP;
+        msgHeader[4] = 0; // Loading hints
+
+        return nativeSendMessage(msgHeader, app.getAppBinary());
+    }
+
+      @Override
+      public int unloadNanoApp(int nanoAppInstanceHandle) throws RemoteException {
+        NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstanceHandle);
+        if (info == null) {
+          return -1; //means failed
+        }
+
+        // Call Native interface here
+        int[] msgHeader = new int[8];
+        msgHeader[0] = info.getContexthubId();
+        msgHeader[1] = ContextHubManager.MSG_UNLOAD_NANO_APP;
+        msgHeader[2] = info.getHandle();
+
+        return nativeSendMessage(msgHeader, null);
+      }
+
+    @Override
+    public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle) throws RemoteException {
+        // This assumes that all the nanoAppInfo is current. This is reasonable
+        // for the use cases for tightly controlled nanoApps.
+        if (mNanoAppHash.containsKey(nanoAppInstanceHandle)) {
+            return mNanoAppHash.get(nanoAppInstanceHandle);
+        } else {
+            return null;
         }
     }
 
     @Override
-    public void onCreate() {
-        super.onCreate();
+    public int[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) throws RemoteException {
+        ArrayList<Integer> foundInstances = new ArrayList<Integer>();
+
+        for(Integer nanoAppInstance : mNanoAppHash.keySet()) {
+            NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstance);
+
+            if(filter.testMatch(info)){
+                foundInstances.add(nanoAppInstance);
+            }
+        }
+
+        int[] retArray = new int[foundInstances.size()];
+        for (int i = 0; i < foundInstances.size(); i++) {
+            retArray[i] = foundInstances.get(i).intValue();
+        }
+
+        return retArray;
     }
 
     @Override
-    public IBinder onBind(Intent intent) {
-        return null;
+    public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage msg) throws RemoteException {
+        int[] msgHeader = new int[8];
+        msgHeader[0] = ContextHubManager.MSG_DATA_SEND;
+        msgHeader[1] = hubHandle;
+        msgHeader[2] = nanoAppHandle;
+        msgHeader[3] = msg.getMsgType();
+        msgHeader[4] = msg.getVersion();
+
+        return nativeSendMessage(msgHeader, msg.getData());
     }
-
-    private final IContextHubService.Stub mBinder = new IContextHubService.Stub() {
-
-        private  IContextHubCallback callback;
-
-        @Override
-        public int registerCallBack(IContextHubCallback callback) throws RemoteException{
-            this.callback = callback;
-            return 0;
-        }
-
-        @Override
-        public int[] getContextHubHandles() throws RemoteException {
-            int [] returnArray = new int[mHubHash.size()];
-            int i = 0;
-            for (int key : mHubHash.keySet()) {
-                // Add any filtering here
-                returnArray[i] = key;
-                i++;
-            }
-            return returnArray;
-        }
-
-        @Override
-        public ContextHubInfo getContextHubInfo(int contexthubHandle) throws RemoteException {
-            return mHubHash.get(contexthubHandle);
-        }
-
-        @Override
-        public int loadNanoApp(int hubHandle, NanoApp app) throws RemoteException {
-            if (!mHubHash.containsKey(hubHandle)) {
-                return -1;
-            } else {
-                // Call Native interface here
-                int[] msgHeader = new int[8];
-                msgHeader[0] = ContextHubManager.MSG_LOAD_NANO_APP;
-                msgHeader[1] = app.getAppId();
-                msgHeader[2] = app.getAppVersion();
-                msgHeader[3] = 0; // LOADING_HINTS
-                msgHeader[4] = hubHandle;
-
-                int handle = nativeSendMessage(msgHeader, app.getAppBinary());
-
-                // if successful, add an entry to mNanoAppHash
-
-                if(handle > 0) {
-                    return 0;
-                } else {
-
-                    return -1;
-                }
-            }
-        }
-
-        @Override
-        public int unloadNanoApp(int nanoAppInstanceHandle) throws RemoteException {
-            if(!mNanoAppHash.containsKey(nanoAppInstanceHandle)) {
-                return -1;
-            } else {
-                NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstanceHandle);
-                // Call Native interface here
-                int[] msgHeader = new int[8];
-                msgHeader[0] = ContextHubManager.MSG_UNLOAD_NANO_APP;
-                msgHeader[1] = info.getContexthubId();
-                msgHeader[2] = info.getHandle();
-
-                int result = nativeSendMessage(msgHeader, null);
-                // if successful, remove the entry in mNanoAppHash
-                if(result == 0) {
-                    mNanoAppHash.remove(nanoAppInstanceHandle);
-                }
-                return(result);
-            }
-        }
-
-        @Override
-        public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle) throws RemoteException {
-            // This assumes that all the nanoAppInfo is current. This is reasonable
-            // for the use cases for tightly controlled nanoApps.
-            //
-            if(!mNanoAppHash.containsKey(nanoAppInstanceHandle)) {
-                return(mNanoAppHash.get(nanoAppInstanceHandle));
-            } else {
-                return null;
-            }
-        }
-
-        @Override
-        public int[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) throws RemoteException {
-            ArrayList<Integer> foundInstances = new ArrayList<Integer>();
-
-            for(Integer nanoAppInstance : mNanoAppHash.keySet()) {
-                NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstance);
-
-                if(filter.testMatch(info)){
-                    foundInstances.add(nanoAppInstance);
-                }
-            }
-
-            int[] retArray = new int[foundInstances.size()];
-            for (int i = 0; i < foundInstances.size(); i++) {
-                retArray[i] = foundInstances.get(i).intValue();
-            }
-
-            return retArray;
-        }
-
-        @Override
-        public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage msg) throws RemoteException {
-            int[] msgHeader = new int[8];
-            msgHeader[0] = ContextHubManager.MSG_DATA_SEND;
-            msgHeader[1] = hubHandle;
-            msgHeader[2] = nanoAppHandle;
-            msgHeader[3] = msg.getMsgType();
-            msgHeader[4] = msg.getVersion();
-
-            return (nativeSendMessage(msgHeader, msg.getData()));
-        }
-    };
 }
+