blob: 30c4f3b0b3046e029890f17d1478ae97051d665f [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 */
16
Ashutosh Joshi420e45e2016-12-20 16:34:41 -080017package com.android.server.location;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080018
Ashutosh Joshi54787a52016-04-27 11:19:16 -070019import java.io.FileDescriptor;
20import java.io.PrintWriter;
Greg Kaiser1983f9b2016-09-27 13:38:13 -070021import java.nio.ByteBuffer;
22import java.nio.ByteOrder;
Ashutosh Joshi54787a52016-04-27 11:19:16 -070023import java.util.ArrayList;
24import java.util.HashMap;
25
destradaa8bad3fe2016-03-15 12:33:40 -070026import android.Manifest;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080027import android.content.Context;
Ashutosh Joshi6239cc62016-04-04 16:19:29 -070028import android.content.pm.PackageManager;
Ashutosh Joshi420e45e2016-12-20 16:34:41 -080029import android.hardware.location.ContextHubInfo;
30import android.hardware.location.ContextHubManager;
31import android.hardware.location.ContextHubMessage;
32import android.hardware.location.IContextHubService;
33import android.hardware.location.IContextHubCallback;
34import android.hardware.location.NanoAppFilter;
35import android.hardware.location.NanoApp;
36import android.hardware.location.NanoAppInstanceInfo;
destradaa78cebca2016-04-14 18:40:14 -070037import android.os.RemoteCallbackList;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080038import android.os.RemoteException;
Brian Duddiec3d8a522016-06-14 15:12:26 -070039import android.os.ServiceManager;
40import android.service.vr.IVrManager;
41import android.service.vr.IVrStateCallbacks;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080042import android.util.Log;
43
Ashutosh Joshi6239cc62016-04-04 16:19:29 -070044import java.io.FileDescriptor;
45import java.io.PrintWriter;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080046import java.util.ArrayList;
Brian Duddiec3d8a522016-06-14 15:12:26 -070047import java.util.concurrent.ConcurrentHashMap;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080048
49/**
50 * @hide
51 */
Peng Xu9ff7d222016-02-11 13:02:05 -080052public class ContextHubService extends IContextHubService.Stub {
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080053 private static final String TAG = "ContextHubService";
destradaa8bad3fe2016-03-15 12:33:40 -070054 private static final String HARDWARE_PERMISSION = Manifest.permission.LOCATION_HARDWARE;
55 private static final String ENFORCE_HW_PERMISSION_MESSAGE = "Permission '"
Ashutosh Joshi6239cc62016-04-04 16:19:29 -070056 + HARDWARE_PERMISSION + "' not granted to access ContextHub Hardware";
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080057
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070058
59 public static final int ANY_HUB = -1;
Ashutosh Joshicafdee92016-04-04 16:19:29 -070060 public static final int MSG_LOAD_NANO_APP = 3;
61 public static final int MSG_UNLOAD_NANO_APP = 4;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070062
63 private static final String PRE_LOADED_GENERIC_UNKNOWN = "Preloaded app, unknown";
64 private static final String PRE_LOADED_APP_NAME = PRE_LOADED_GENERIC_UNKNOWN;
65 private static final String PRE_LOADED_APP_PUBLISHER = PRE_LOADED_GENERIC_UNKNOWN;
66 private static final int PRE_LOADED_APP_MEM_REQ = 0;
67
68 private static final int MSG_HEADER_SIZE = 4;
Ashutosh Joshi54787a52016-04-27 11:19:16 -070069 private static final int HEADER_FIELD_MSG_TYPE = 0;
70 private static final int HEADER_FIELD_MSG_VERSION = 1;
71 private static final int HEADER_FIELD_HUB_HANDLE = 2;
72 private static final int HEADER_FIELD_APP_INSTANCE = 3;
73
74 private static final int HEADER_FIELD_LOAD_APP_ID_LO = MSG_HEADER_SIZE;
75 private static final int HEADER_FIELD_LOAD_APP_ID_HI = MSG_HEADER_SIZE + 1;
76 private static final int MSG_LOAD_APP_HEADER_SIZE = MSG_HEADER_SIZE + 2;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070077
78 private static final int OS_APP_INSTANCE = -1;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080079
Brian Duddiec3d8a522016-06-14 15:12:26 -070080 private static final long APP_ID_ACTIVITY_RECOGNITION = 0x476f6f676c001000L;
81
Peng Xu9ff7d222016-02-11 13:02:05 -080082 private final Context mContext;
Brian Duddiec3d8a522016-06-14 15:12:26 -070083 private final ConcurrentHashMap<Integer, NanoAppInstanceInfo> mNanoAppHash =
84 new ConcurrentHashMap<>();
destradaa78cebca2016-04-14 18:40:14 -070085 private final ContextHubInfo[] mContextHubInfo;
86 private final RemoteCallbackList<IContextHubCallback> mCallbacksList =
87 new RemoteCallbackList<>();
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080088
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070089 private native int nativeSendMessage(int[] header, byte[] data);
90 private native ContextHubInfo[] nativeInitialize();
91
Brian Duddiec3d8a522016-06-14 15:12:26 -070092 private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
93 @Override
94 public void onVrStateChanged(boolean enabled) {
95 for (NanoAppInstanceInfo app : mNanoAppHash.values()) {
96 if (app.getAppId() == APP_ID_ACTIVITY_RECOGNITION) {
97 sendVrStateChangeMessageToApp(app, enabled);
98 break;
99 }
100 }
101 }
102 };
103
Peng Xu9ff7d222016-02-11 13:02:05 -0800104 public ContextHubService(Context context) {
105 mContext = context;
106 mContextHubInfo = nativeInitialize();
107
108 for (int i = 0; i < mContextHubInfo.length; i++) {
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700109 Log.d(TAG, "ContextHub[" + i + "] id: " + mContextHubInfo[i].getId()
Peng Xu9ff7d222016-02-11 13:02:05 -0800110 + ", name: " + mContextHubInfo[i].getName());
111 }
Brian Duddiec3d8a522016-06-14 15:12:26 -0700112
113 if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_VR_MODE)) {
114 IVrManager vrManager =
115 IVrManager.Stub.asInterface(ServiceManager.getService("vrmanager"));
116 if (vrManager != null) {
117 try {
118 vrManager.registerListener(mVrStateCallbacks);
119 } catch (RemoteException e) {
120 Log.e(TAG, "VR state listener registration failed", e);
121 }
122 }
123 }
Peng Xu9ff7d222016-02-11 13:02:05 -0800124 }
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800125
Peng Xu9ff7d222016-02-11 13:02:05 -0800126 @Override
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700127 public int registerCallback(IContextHubCallback callback) throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700128 checkPermissions();
destradaa78cebca2016-04-14 18:40:14 -0700129 mCallbacksList.register(callback);
Peng Xu9ff7d222016-02-11 13:02:05 -0800130 return 0;
131 }
132
133 @Override
134 public int[] getContextHubHandles() throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700135 checkPermissions();
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700136 int[] returnArray = new int[mContextHubInfo.length];
Peng Xu9ff7d222016-02-11 13:02:05 -0800137
138 for (int i = 0; i < returnArray.length; ++i) {
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700139 returnArray[i] = i;
Peng Xu9ff7d222016-02-11 13:02:05 -0800140 Log.d(TAG, String.format("Hub %s is mapped to %d",
141 mContextHubInfo[i].getName(), returnArray[i]));
142 }
143
144 return returnArray;
145 }
146
147 @Override
148 public ContextHubInfo getContextHubInfo(int contextHubHandle) throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700149 checkPermissions();
Peng Xu9ff7d222016-02-11 13:02:05 -0800150 if (!(contextHubHandle >= 0 && contextHubHandle < mContextHubInfo.length)) {
151 return null; // null means fail
152 }
153
154 return mContextHubInfo[contextHubHandle];
155 }
156
Greg Kaiser1983f9b2016-09-27 13:38:13 -0700157 // TODO(b/30808791): Remove this when NanoApp's API is correctly treating
158 // app IDs as 64-bits.
159 private static long parseAppId(NanoApp app) {
160 // NOTE: If this shifting seems odd (since it's actually "ONAN"), note
161 // that it matches how this is defined in context_hub.h.
162 final int HEADER_MAGIC =
163 (((int)'N' << 0) |
164 ((int)'A' << 8) |
165 ((int)'N' << 16) |
166 ((int)'O' << 24));
167 final int HEADER_MAGIC_OFFSET = 4;
168 final int HEADER_APP_ID_OFFSET = 8;
169
170 ByteBuffer header = ByteBuffer.wrap(app.getAppBinary())
171 .order(ByteOrder.LITTLE_ENDIAN);
172
173 try {
174 if (header.getInt(HEADER_MAGIC_OFFSET) == HEADER_MAGIC) {
175 // This is a legitimate nanoapp header. Let's grab the app ID.
176 return header.getLong(HEADER_APP_ID_OFFSET);
177 }
178 } catch (IndexOutOfBoundsException e) {
179 // The header is undersized. We'll fall through to our code
180 // path below, which handles being unable to parse the header.
181 }
182 // We failed to parse the header. Even through it's probably wrong,
183 // let's give NanoApp's idea of our ID. This is at least consistent.
184 return app.getAppId();
185 }
186
Peng Xu9ff7d222016-02-11 13:02:05 -0800187 @Override
188 public int loadNanoApp(int contextHubHandle, NanoApp app) throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700189 checkPermissions();
Peng Xu9ff7d222016-02-11 13:02:05 -0800190
191 if (!(contextHubHandle >= 0 && contextHubHandle < mContextHubInfo.length)) {
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700192 Log.e(TAG, "Invalid contextHubhandle " + contextHubHandle);
193 return -1;
Peng Xu9ff7d222016-02-11 13:02:05 -0800194 }
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600195 if (app == null) {
196 return -1;
197 }
Peng Xu9ff7d222016-02-11 13:02:05 -0800198
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700199 int[] msgHeader = new int[MSG_LOAD_APP_HEADER_SIZE];
200 msgHeader[HEADER_FIELD_HUB_HANDLE] = contextHubHandle;
201 msgHeader[HEADER_FIELD_APP_INSTANCE] = OS_APP_INSTANCE;
202 msgHeader[HEADER_FIELD_MSG_VERSION] = 0;
203 msgHeader[HEADER_FIELD_MSG_TYPE] = MSG_LOAD_NANO_APP;
204
205 long appId = app.getAppId();
Greg Kaiser1983f9b2016-09-27 13:38:13 -0700206 // TODO(b/30808791): Remove this hack when the NanoApp API is fixed,
207 // and getAppId() returns a 'long' instead of an 'int'.
Greg Kaiser5817ce02016-08-25 22:06:08 -0700208 if ((appId >> 32) != 0) {
209 // We're unlikely to notice this warning, but at least
210 // we can avoid running our hack logic.
211 Log.w(TAG, "Code has not been updated since API fix.");
212 } else {
Greg Kaiser1983f9b2016-09-27 13:38:13 -0700213 appId = parseAppId(app);
Greg Kaiser5817ce02016-08-25 22:06:08 -0700214 }
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700215
216 msgHeader[HEADER_FIELD_LOAD_APP_ID_LO] = (int)(appId & 0xFFFFFFFF);
217 msgHeader[HEADER_FIELD_LOAD_APP_ID_HI] = (int)((appId >> 32) & 0xFFFFFFFF);
Peng Xu9ff7d222016-02-11 13:02:05 -0800218
Ashutosh Joshi11864402016-07-15 13:46:22 -0700219 int errVal = nativeSendMessage(msgHeader, app.getAppBinary());
220 if (errVal != 0) {
221 Log.e(TAG, "Send Message returns error" + contextHubHandle);
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700222 return -1;
223 }
Ashutosh Joshi11864402016-07-15 13:46:22 -0700224
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700225 // Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app
226 return 0;
Peng Xu9ff7d222016-02-11 13:02:05 -0800227 }
228
destradaa8bad3fe2016-03-15 12:33:40 -0700229 @Override
230 public int unloadNanoApp(int nanoAppInstanceHandle) throws RemoteException {
231 checkPermissions();
Peng Xu9ff7d222016-02-11 13:02:05 -0800232 NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstanceHandle);
233 if (info == null) {
destradaa8bad3fe2016-03-15 12:33:40 -0700234 return -1; //means failed
Peng Xu9ff7d222016-02-11 13:02:05 -0800235 }
236
237 // Call Native interface here
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700238 int[] msgHeader = new int[MSG_HEADER_SIZE];
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700239 msgHeader[HEADER_FIELD_HUB_HANDLE] = ANY_HUB;
240 msgHeader[HEADER_FIELD_APP_INSTANCE] = nanoAppInstanceHandle;
241 msgHeader[HEADER_FIELD_MSG_VERSION] = 0;
242 msgHeader[HEADER_FIELD_MSG_TYPE] = MSG_UNLOAD_NANO_APP;
Peng Xu9ff7d222016-02-11 13:02:05 -0800243
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700244 byte msg[] = new byte[0];
245
246 if (nativeSendMessage(msgHeader, msg) != 0) {
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700247 return -1;
248 }
249
250 // Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app
251 return 0;
destradaa8bad3fe2016-03-15 12:33:40 -0700252 }
Peng Xu9ff7d222016-02-11 13:02:05 -0800253
254 @Override
destradaa8bad3fe2016-03-15 12:33:40 -0700255 public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle)
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700256 throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700257 checkPermissions();
Peng Xu9ff7d222016-02-11 13:02:05 -0800258 // This assumes that all the nanoAppInfo is current. This is reasonable
259 // for the use cases for tightly controlled nanoApps.
260 if (mNanoAppHash.containsKey(nanoAppInstanceHandle)) {
261 return mNanoAppHash.get(nanoAppInstanceHandle);
262 } else {
263 return null;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800264 }
265 }
266
267 @Override
Peng Xu9ff7d222016-02-11 13:02:05 -0800268 public int[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700269 checkPermissions();
Peng Xu9ff7d222016-02-11 13:02:05 -0800270 ArrayList<Integer> foundInstances = new ArrayList<Integer>();
271
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700272 for (Integer nanoAppInstance: mNanoAppHash.keySet()) {
Peng Xu9ff7d222016-02-11 13:02:05 -0800273 NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstance);
274
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700275 if (filter.testMatch(info)) {
Peng Xu9ff7d222016-02-11 13:02:05 -0800276 foundInstances.add(nanoAppInstance);
277 }
278 }
279
280 int[] retArray = new int[foundInstances.size()];
281 for (int i = 0; i < foundInstances.size(); i++) {
282 retArray[i] = foundInstances.get(i).intValue();
283 }
284
285 return retArray;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800286 }
287
288 @Override
destradaa8bad3fe2016-03-15 12:33:40 -0700289 public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage msg)
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700290 throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700291 checkPermissions();
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700292
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600293 if (msg == null || msg.getData() == null) {
294 Log.w(TAG, "null ptr");
295 return -1;
296 }
297
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700298 int[] msgHeader = new int[MSG_HEADER_SIZE];
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700299 msgHeader[HEADER_FIELD_HUB_HANDLE] = hubHandle;
300 msgHeader[HEADER_FIELD_APP_INSTANCE] = nanoAppHandle;
301 msgHeader[HEADER_FIELD_MSG_VERSION] = msg.getVersion();
302 msgHeader[HEADER_FIELD_MSG_TYPE] = msg.getMsgType();
Peng Xu9ff7d222016-02-11 13:02:05 -0800303
304 return nativeSendMessage(msgHeader, msg.getData());
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800305 }
destradaa8bad3fe2016-03-15 12:33:40 -0700306
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700307 @Override
308 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
309 if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
310 != PackageManager.PERMISSION_GRANTED) {
Ashutosh Joshi420e45e2016-12-20 16:34:41 -0800311 pw.println("Permission Denial: can't dump contexthub service");
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700312 return;
313 }
314
315 pw.println("Dumping ContextHub Service");
316
317 pw.println("");
318 // dump ContextHubInfo
319 pw.println("=================== CONTEXT HUBS ====================");
320 for (int i = 0; i < mContextHubInfo.length; i++) {
321 pw.println("Handle " + i + " : " + mContextHubInfo[i].toString());
322 }
323 pw.println("");
324 pw.println("=================== NANOAPPS ====================");
325 // Dump nanoAppHash
326 for (Integer nanoAppInstance: mNanoAppHash.keySet()) {
327 pw.println(nanoAppInstance + " : " + mNanoAppHash.get(nanoAppInstance).toString());
328 }
329
330 // dump eventLog
331 }
332
destradaa8bad3fe2016-03-15 12:33:40 -0700333 private void checkPermissions() {
334 mContext.enforceCallingPermission(HARDWARE_PERMISSION, ENFORCE_HW_PERMISSION_MESSAGE);
335 }
Ashutosh Joshi2c697fb2016-04-01 20:48:13 +0000336
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700337 private int onMessageReceipt(int[] header, byte[] data) {
338 if (header == null || data == null || header.length < MSG_HEADER_SIZE) {
339 return -1;
340 }
destradaa78cebca2016-04-14 18:40:14 -0700341 int callbacksCount = mCallbacksList.beginBroadcast();
342 if (callbacksCount < 1) {
343 Log.v(TAG, "No message callbacks registered.");
344 return 0;
345 }
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700346
347 ContextHubMessage msg = new ContextHubMessage(header[HEADER_FIELD_MSG_TYPE],
348 header[HEADER_FIELD_MSG_VERSION],
349 data);
destradaa78cebca2016-04-14 18:40:14 -0700350 for (int i = 0; i < callbacksCount; ++i) {
351 IContextHubCallback callback = mCallbacksList.getBroadcastItem(i);
352 try {
353 callback.onMessageReceipt(
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700354 header[HEADER_FIELD_HUB_HANDLE],
355 header[HEADER_FIELD_APP_INSTANCE],
356 msg);
destradaa78cebca2016-04-14 18:40:14 -0700357 } catch (RemoteException e) {
358 Log.i(TAG, "Exception (" + e + ") calling remote callback (" + callback + ").");
359 continue;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700360 }
361 }
destradaa78cebca2016-04-14 18:40:14 -0700362 mCallbacksList.finishBroadcast();
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700363 return 0;
364 }
365
366 private int addAppInstance(int hubHandle, int appInstanceHandle, long appId, int appVersion) {
367 // App Id encodes vendor & version
368 NanoAppInstanceInfo appInfo = new NanoAppInstanceInfo();
369
370 appInfo.setAppId(appId);
371 appInfo.setAppVersion(appVersion);
372 appInfo.setName(PRE_LOADED_APP_NAME);
373 appInfo.setContexthubId(hubHandle);
374 appInfo.setHandle(appInstanceHandle);
375 appInfo.setPublisher(PRE_LOADED_APP_PUBLISHER);
376 appInfo.setNeededExecMemBytes(PRE_LOADED_APP_MEM_REQ);
377 appInfo.setNeededReadMemBytes(PRE_LOADED_APP_MEM_REQ);
378 appInfo.setNeededWriteMemBytes(PRE_LOADED_APP_MEM_REQ);
379
Greg Kaiserfe6d4f52016-08-19 10:24:07 -0700380 String action;
381 if (mNanoAppHash.containsKey(appInstanceHandle)) {
382 action = "Updated";
383 } else {
384 action = "Added";
385 }
386
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700387 mNanoAppHash.put(appInstanceHandle, appInfo);
Greg Kaiserfe6d4f52016-08-19 10:24:07 -0700388 Log.d(TAG, action + " app instance " + appInstanceHandle + " with id "
389 + appId + " version " + appVersion);
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700390
391 return 0;
392 }
Brian Duddiec3d8a522016-06-14 15:12:26 -0700393
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700394 private int deleteAppInstance(int appInstanceHandle) {
395 if (mNanoAppHash.remove(appInstanceHandle) == null) {
396 return -1;
397 }
398
399 return 0;
400 }
401
Brian Duddiec3d8a522016-06-14 15:12:26 -0700402 private void sendVrStateChangeMessageToApp(NanoAppInstanceInfo app, boolean vrModeEnabled) {
403 int[] msgHeader = new int[MSG_HEADER_SIZE];
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700404 msgHeader[HEADER_FIELD_MSG_TYPE] = 0;
405 msgHeader[HEADER_FIELD_MSG_VERSION] = 0;
406 msgHeader[HEADER_FIELD_HUB_HANDLE] = ANY_HUB;
407 msgHeader[HEADER_FIELD_APP_INSTANCE] = app.getHandle();
Brian Duddiec3d8a522016-06-14 15:12:26 -0700408
409 byte[] data = new byte[1];
410 data[0] = (byte) ((vrModeEnabled) ? 1 : 0);
411 int ret = nativeSendMessage(msgHeader, data);
412 if (ret != 0) {
413 Log.e(TAG, "Couldn't send VR state change notification (" + ret + ")!");
414 }
415 }
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700416}