blob: 9c27c22dfd002175c4607968bd5afbacbd30de11 [file] [log] [blame]
/*
* Copyright (C) 2020 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 com.android.server.location.contexthub;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.hardware.contexthub.HostEndpointInfo;
import android.hardware.contexthub.MessageDeliveryStatus;
import android.hardware.contexthub.NanSessionRequest;
import android.hardware.contexthub.V1_0.ContextHub;
import android.hardware.contexthub.V1_0.ContextHubMsg;
import android.hardware.contexthub.V1_0.TransactionResult;
import android.hardware.contexthub.V1_1.Setting;
import android.hardware.contexthub.V1_1.SettingValue;
import android.hardware.contexthub.V1_2.HubAppInfo;
import android.hardware.contexthub.V1_2.IContexthubCallback;
import android.hardware.location.ContextHubInfo;
import android.hardware.location.ContextHubTransaction;
import android.hardware.location.NanoAppBinary;
import android.hardware.location.NanoAppMessage;
import android.hardware.location.NanoAppState;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.util.Log;
import android.util.Pair;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
/**
* @hide
*/
public abstract class IContextHubWrapper {
private static final String TAG = "IContextHubWrapper";
/**
* The callback interface to use in registerCallback.
*/
public interface ICallback {
/**
* @param transactionId The ID of the transaction that completed.
* @param success true if the transaction succeeded.
*/
void handleTransactionResult(int transactionId, boolean success);
/**
* @param eventType The Context Hub event type defined by ContextHubService
* .CONTEXT_HUB_EVENT_*.
*/
void handleContextHubEvent(int eventType);
/**
* @param nanoappId The ID of the nanoapp that aborted.
* @param abortCode The nanoapp-defined abort code.
*/
void handleNanoappAbort(long nanoappId, int abortCode);
/**
* @param nanoappStateList The list of loaded nanoapps on the Context Hub.
*/
void handleNanoappInfo(List<NanoAppState> nanoappStateList);
/**
* Handles a message from a nanoapp to a ContextHubClient.
*
* @param hostEndpointId The host endpoint ID of the recipient.
* @param message The message from the nanoapp.
* @param nanoappPermissions The list of permissions held by the nanoapp.
* @param messagePermissions The list of permissions required to receive the message.
*/
void handleNanoappMessage(short hostEndpointId, NanoAppMessage message,
List<String> nanoappPermissions, List<String> messagePermissions);
/**
* Handles a restart of the service
*/
void handleServiceRestart();
}
/**
* @return the IContextHubWrapper interface
*/
public static IContextHubWrapper getContextHubWrapper() {
IContextHubWrapper wrapper = maybeConnectToAidl();
if (wrapper == null) {
wrapper = maybeConnectTo1_2();
}
if (wrapper == null) {
wrapper = maybeConnectTo1_1();
}
if (wrapper == null) {
wrapper = maybeConnectTo1_0();
}
return wrapper;
}
/**
* Attempts to connect to the Contexthub HAL 1.0 service, if it exists.
*
* @return A valid IContextHubWrapper if the connection was successful, null otherwise.
*/
@Nullable
public static IContextHubWrapper maybeConnectTo1_0() {
android.hardware.contexthub.V1_0.IContexthub proxy = null;
try {
proxy = android.hardware.contexthub.V1_0.IContexthub.getService(true /* retry */);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException while attaching to Context Hub HAL proxy", e);
} catch (NoSuchElementException e) {
Log.i(TAG, "Context Hub HAL service not found");
}
return (proxy == null) ? null : new ContextHubWrapperV1_0(proxy);
}
/**
* Attempts to connect to the Contexthub HAL 1.1 service, if it exists.
*
* @return A valid IContextHubWrapper if the connection was successful, null otherwise.
*/
@Nullable
public static IContextHubWrapper maybeConnectTo1_1() {
android.hardware.contexthub.V1_1.IContexthub proxy = null;
try {
proxy = android.hardware.contexthub.V1_1.IContexthub.getService(true /* retry */);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException while attaching to Context Hub HAL proxy", e);
} catch (NoSuchElementException e) {
Log.i(TAG, "Context Hub HAL service not found");
}
return (proxy == null) ? null : new ContextHubWrapperV1_1(proxy);
}
/**
* Attempts to connect to the Contexthub HAL 1.2 service, if it exists.
*
* @return A valid IContextHubWrapper if the connection was successful, null otherwise.
*/
@Nullable
public static IContextHubWrapper maybeConnectTo1_2() {
android.hardware.contexthub.V1_2.IContexthub proxy = null;
try {
proxy = android.hardware.contexthub.V1_2.IContexthub.getService(true /* retry */);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException while attaching to Context Hub HAL proxy", e);
} catch (NoSuchElementException e) {
Log.i(TAG, "Context Hub HAL service not found");
}
return (proxy == null) ? null : new ContextHubWrapperV1_2(proxy);
}
/**
* Attempts to connect to the AIDL HAL and returns the proxy IContextHub.
*/
public static android.hardware.contexthub.IContextHub maybeConnectToAidlGetProxy() {
android.hardware.contexthub.IContextHub proxy = null;
final String aidlServiceName =
android.hardware.contexthub.IContextHub.class.getCanonicalName() + "/default";
if (ServiceManager.isDeclared(aidlServiceName)) {
proxy = android.hardware.contexthub.IContextHub.Stub.asInterface(
ServiceManager.waitForService(aidlServiceName));
if (proxy == null) {
Log.e(TAG, "Context Hub AIDL service was declared but was not found");
}
} else {
Log.d(TAG, "Context Hub AIDL service is not declared");
}
return proxy;
}
/**
* Attempts to connect to the Contexthub HAL AIDL service, if it exists.
*
* @return A valid IContextHubWrapper if the connection was successful, null otherwise.
*/
@Nullable
public static IContextHubWrapper maybeConnectToAidl() {
android.hardware.contexthub.IContextHub proxy = maybeConnectToAidlGetProxy();
return proxy == null ? null : new ContextHubWrapperAidl(proxy);
}
/**
* Calls the appropriate getHubs function depending on the HAL version.
*/
public abstract Pair<List<ContextHubInfo>, List<String>> getHubs() throws RemoteException;
/**
* @return True if this version of the Contexthub HAL supports Location setting notifications.
*/
public abstract boolean supportsLocationSettingNotifications();
/**
* Notifies the Contexthub implementation of a user Location setting change.
*
* @param enabled True if the Location setting has been enabled.
*/
public abstract void onLocationSettingChanged(boolean enabled);
/**
* @return True if this version of the Contexthub HAL supports WiFi availability setting
* notifications.
*/
public abstract boolean supportsWifiSettingNotifications();
/**
* Notifies the Contexthub implementation of a user WiFi availability setting change.
*
* @param enabled true if the WiFi availability setting has been enabled.
*/
public abstract void onWifiSettingChanged(boolean enabled);
/**
* Notifies the Contexthub implementation of a user WiFi main setting change.
*
* @param enabled true if the WiFi main setting has been enabled.
*/
public abstract void onWifiMainSettingChanged(boolean enabled);
/**
* Notifies the Contexthub implementation of a user WiFi scanning setting change.
*
* @param enabled true if the WiFi scanning setting has been enabled.
*/
public abstract void onWifiScanningSettingChanged(boolean enabled);
/**
* @return True if this version of the Contexthub HAL supports airplane mode setting
* notifications.
*/
public abstract boolean supportsAirplaneModeSettingNotifications();
/**
* Notifies the Contexthub implementation of an airplane mode setting change.
*
* @param enabled true if the airplane mode setting has been enabled.
*/
public abstract void onAirplaneModeSettingChanged(boolean enabled);
/**
* @return True if this version of the Contexthub HAL supports microphone setting
* notifications.
*/
public abstract boolean supportsMicrophoneSettingNotifications();
/**
* Notifies the Contexthub implementation of a microphone setting change.
*/
public abstract void onMicrophoneSettingChanged(boolean enabled);
/**
* @return True if this version of the Contexthub HAL supports BT availability setting
* notifications.
*/
public abstract boolean supportsBtSettingNotifications();
/**
* Notifies the Contexthub implementation of a BT main setting change.
*/
public abstract void onBtMainSettingChanged(boolean enabled);
/**
* Notifies the Contexthub implementation of a BT scanning setting change.
*/
public abstract void onBtScanningSettingChanged(boolean enabled);
/**
* Invoked whenever a host client connects with the framework.
*
* @param info The host endpoint info.
*/
public void onHostEndpointConnected(HostEndpointInfo info) {}
/**
* Invoked whenever a host client disconnects from the framework.
*
* @param hostEndpointId The ID of the host endpoint that disconnected.
*/
public void onHostEndpointDisconnected(short hostEndpointId) {}
/**
* Sends a message to the Context Hub.
*
* @param hostEndpointId The host endpoint ID of the sender.
* @param contextHubId The ID of the Context Hub to send the message to.
* @param message The message to send.
* @return the result of the message sending.
*/
@ContextHubTransaction.Result
public abstract int sendMessageToContextHub(
short hostEndpointId, int contextHubId, NanoAppMessage message)
throws RemoteException;
/**
* Loads a nanoapp on the Context Hub.
*
* @param contextHubId The ID of the Context Hub to load the nanoapp to.
* @param binary The nanoapp binary to load.
* @param transactionId The transaction ID of this load.
* @return the result of this load transaction.
*/
@ContextHubTransaction.Result
public abstract int loadNanoapp(int contextHubId, NanoAppBinary binary,
int transactionId) throws RemoteException;
/**
* Unloads a nanoapp on the Context Hub. Semantics are similar to loadNanoapp().
*/
@ContextHubTransaction.Result
public abstract int unloadNanoapp(int contextHubId, long nanoappId,
int transactionId) throws RemoteException;
/**
* Enables a nanoapp on the Context Hub. Semantics are similar to loadNanoapp().
*/
@ContextHubTransaction.Result
public abstract int enableNanoapp(int contextHubId, long nanoappId,
int transactionId) throws RemoteException;
/**
* Disables a nanoapp on the Context Hub. Semantics are similar to loadNanoapp().
*/
@ContextHubTransaction.Result
public abstract int disableNanoapp(int contextHubId, long nanoappId,
int transactionId) throws RemoteException;
/**
* Queries a list of nanoapp from the Context hub.
*
* @param contextHubId The ID of the Context Hub to query.
* @return the result of this query transaction.
*/
@ContextHubTransaction.Result
public abstract int queryNanoapps(int contextHubId) throws RemoteException;
/**
* Provides the list of preloaded nanoapp IDs on the system. The output of this API must
* not change.
*
* @param contextHubId The context Hub ID.
*
* @return The list of preloaded nanoapp IDs.
*/
public abstract long[] getPreloadedNanoappIds(int contextHubId);
/**
* Registers a callback with the Context Hub.
*
* @param contextHubId The ID of the Context Hub to register the callback with.
* @param callback The callback to register.
*/
public abstract void registerCallback(int contextHubId, @NonNull ICallback callback)
throws RemoteException;
/**
* Registers an existing callback with the Context Hub.
*
* @param contextHubId The ID of the Context Hub to register the callback with.
*/
public abstract void registerExistingCallback(int contextHubId) throws RemoteException;
/**
* Puts the context hub in and out of test mode. Test mode is a clean state
* where tests can be executed in the same environment. If enable is true,
* this will enable test mode by unloading all nanoapps. If enable is false,
* this will disable test mode and reverse the actions of enabling test mode
* by loading all preloaded nanoapps. This puts CHRE in a normal state.
*
* This should only be used for a test environment, either through a
* @TestApi or development tools. This should not be used in a production
* environment.
*
* @param enable If true, put the context hub in test mode. If false, disable
* test mode.
* @return If true, the operation was successful; false otherwise.
*/
public abstract boolean setTestMode(boolean enable);
private static class ContextHubWrapperAidl extends IContextHubWrapper
implements IBinder.DeathRecipient {
private android.hardware.contexthub.IContextHub mHub;
private final Map<Integer, ContextHubAidlCallback> mAidlCallbackMap =
new HashMap<>();
private Runnable mHandleServiceRestartCallback = null;
// Use this thread in case where the execution requires to be on a service thread.
// For instance, AppOpsManager.noteOp requires the UPDATE_APP_OPS_STATS permission.
private HandlerThread mHandlerThread =
new HandlerThread("Context Hub AIDL callback", Process.THREAD_PRIORITY_BACKGROUND);
private Handler mHandler;
private class ContextHubAidlCallback extends
android.hardware.contexthub.IContextHubCallback.Stub {
private final int mContextHubId;
private final ICallback mCallback;
// 9a17008d-6bf1-445a-9011-6d21bd985b6c
private static final byte[] UUID = {-102, 23, 0, -115, 107, -15, 68, 90,
-112, 17, 109, 33, -67, -104, 91, 108};
private static final String NAME = "ContextHubService";
ContextHubAidlCallback(int contextHubId, ICallback callback) {
mContextHubId = contextHubId;
mCallback = callback;
}
public void handleNanoappInfo(android.hardware.contexthub.NanoappInfo[] appInfo) {
List<NanoAppState> nanoAppStateList =
ContextHubServiceUtil.createNanoAppStateList(appInfo);
mHandler.post(() -> {
mCallback.handleNanoappInfo(nanoAppStateList);
});
}
public void handleContextHubMessage(android.hardware.contexthub.ContextHubMessage msg,
String[] msgContentPerms) {
mHandler.post(() -> {
mCallback.handleNanoappMessage(
(short) msg.hostEndPoint,
ContextHubServiceUtil.createNanoAppMessage(msg),
new ArrayList<>(Arrays.asList(msg.permissions)),
new ArrayList<>(Arrays.asList(msgContentPerms)));
});
}
public void handleContextHubAsyncEvent(int evt) {
mHandler.post(() -> {
mCallback.handleContextHubEvent(
ContextHubServiceUtil.toContextHubEventFromAidl(evt));
});
}
public void handleTransactionResult(int transactionId, boolean success) {
mHandler.post(() -> {
mCallback.handleTransactionResult(transactionId, success);
});
}
public void handleNanSessionRequest(NanSessionRequest request) {
// TODO(271471342): Implement
}
public void handleMessageDeliveryStatus(char hostEndPointId,
MessageDeliveryStatus messageDeliveryStatus) {
// TODO(b/312417087): Implement reliable message support
}
public byte[] getUuid() {
return UUID;
}
public String getName() {
return NAME;
}
@Override
public String getInterfaceHash() {
return android.hardware.contexthub.IContextHubCallback.HASH;
}
@Override
public int getInterfaceVersion() {
return android.hardware.contexthub.IContextHubCallback.VERSION;
}
}
ContextHubWrapperAidl(android.hardware.contexthub.IContextHub hub) {
setHub(hub);
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
linkWrapperToHubDeath();
}
private synchronized android.hardware.contexthub.IContextHub getHub() {
return mHub;
}
private synchronized void setHub(android.hardware.contexthub.IContextHub hub) {
mHub = hub;
}
@Override
public void binderDied() {
Log.i(TAG, "Context Hub AIDL HAL died");
setHub(maybeConnectToAidlGetProxy());
if (getHub() == null) {
// TODO(b/256860015): Make this reconnection more robust
Log.e(TAG, "Could not reconnect to Context Hub AIDL HAL");
return;
}
linkWrapperToHubDeath();
if (mHandleServiceRestartCallback != null) {
mHandleServiceRestartCallback.run();
} else {
Log.e(TAG, "mHandleServiceRestartCallback is not set");
}
}
public Pair<List<ContextHubInfo>, List<String>> getHubs() throws RemoteException {
android.hardware.contexthub.IContextHub hub = getHub();
if (hub == null) {
return new Pair<List<ContextHubInfo>, List<String>>(new ArrayList<ContextHubInfo>(),
new ArrayList<String>());
}
Set<String> supportedPermissions = new HashSet<>();
ArrayList<ContextHubInfo> hubInfoList = new ArrayList<>();
for (android.hardware.contexthub.ContextHubInfo hubInfo : hub.getContextHubs()) {
hubInfoList.add(new ContextHubInfo(hubInfo));
for (String permission : hubInfo.supportedPermissions) {
supportedPermissions.add(permission);
}
}
return new Pair(hubInfoList, new ArrayList<String>(supportedPermissions));
}
public boolean supportsLocationSettingNotifications() {
return true;
}
public boolean supportsWifiSettingNotifications() {
return true;
}
public boolean supportsAirplaneModeSettingNotifications() {
return true;
}
public boolean supportsMicrophoneSettingNotifications() {
return true;
}
public boolean supportsBtSettingNotifications() {
return true;
}
public void onLocationSettingChanged(boolean enabled) {
onSettingChanged(android.hardware.contexthub.Setting.LOCATION, enabled);
}
public void onWifiSettingChanged(boolean enabled) {
}
public void onAirplaneModeSettingChanged(boolean enabled) {
onSettingChanged(android.hardware.contexthub.Setting.AIRPLANE_MODE, enabled);
}
public void onMicrophoneSettingChanged(boolean enabled) {
onSettingChanged(android.hardware.contexthub.Setting.MICROPHONE, enabled);
}
public void onWifiMainSettingChanged(boolean enabled) {
onSettingChanged(android.hardware.contexthub.Setting.WIFI_MAIN, enabled);
}
public void onWifiScanningSettingChanged(boolean enabled) {
onSettingChanged(android.hardware.contexthub.Setting.WIFI_SCANNING, enabled);
}
public void onBtMainSettingChanged(boolean enabled) {
onSettingChanged(android.hardware.contexthub.Setting.BT_MAIN, enabled);
}
public void onBtScanningSettingChanged(boolean enabled) {
onSettingChanged(android.hardware.contexthub.Setting.BT_SCANNING, enabled);
}
@Override
public void onHostEndpointConnected(HostEndpointInfo info) {
android.hardware.contexthub.IContextHub hub = getHub();
if (hub == null) {
return;
}
try {
hub.onHostEndpointConnected(info);
} catch (RemoteException | ServiceSpecificException e) {
Log.e(TAG, "Exception in onHostEndpointConnected" + e.getMessage());
}
}
@Override
public void onHostEndpointDisconnected(short hostEndpointId) {
android.hardware.contexthub.IContextHub hub = getHub();
if (hub == null) {
return;
}
try {
hub.onHostEndpointDisconnected((char) hostEndpointId);
} catch (RemoteException | ServiceSpecificException e) {
Log.e(TAG, "Exception in onHostEndpointDisconnected" + e.getMessage());
}
}
@ContextHubTransaction.Result
public int sendMessageToContextHub(
short hostEndpointId, int contextHubId, NanoAppMessage message)
throws RemoteException {
android.hardware.contexthub.IContextHub hub = getHub();
if (hub == null) {
return ContextHubTransaction.RESULT_FAILED_BAD_PARAMS;
}
try {
hub.sendMessageToHub(contextHubId,
ContextHubServiceUtil.createAidlContextHubMessage(hostEndpointId, message));
return ContextHubTransaction.RESULT_SUCCESS;
} catch (RemoteException | ServiceSpecificException e) {
return ContextHubTransaction.RESULT_FAILED_UNKNOWN;
} catch (IllegalArgumentException e) {
return ContextHubTransaction.RESULT_FAILED_BAD_PARAMS;
}
}
@ContextHubTransaction.Result
public int loadNanoapp(int contextHubId, NanoAppBinary binary,
int transactionId) throws RemoteException {
android.hardware.contexthub.IContextHub hub = getHub();
if (hub == null) {
return ContextHubTransaction.RESULT_FAILED_BAD_PARAMS;
}
android.hardware.contexthub.NanoappBinary aidlNanoAppBinary =
ContextHubServiceUtil.createAidlNanoAppBinary(binary);
try {
hub.loadNanoapp(contextHubId, aidlNanoAppBinary, transactionId);
return ContextHubTransaction.RESULT_SUCCESS;
} catch (RemoteException | ServiceSpecificException | UnsupportedOperationException e) {
return ContextHubTransaction.RESULT_FAILED_UNKNOWN;
} catch (IllegalArgumentException e) {
return ContextHubTransaction.RESULT_FAILED_BAD_PARAMS;
}
}
@ContextHubTransaction.Result
public int unloadNanoapp(int contextHubId, long nanoappId, int transactionId)
throws RemoteException {
android.hardware.contexthub.IContextHub hub = getHub();
if (hub == null) {
return ContextHubTransaction.RESULT_FAILED_BAD_PARAMS;
}
try {
hub.unloadNanoapp(contextHubId, nanoappId, transactionId);
return ContextHubTransaction.RESULT_SUCCESS;
} catch (RemoteException | ServiceSpecificException | UnsupportedOperationException e) {
return ContextHubTransaction.RESULT_FAILED_UNKNOWN;
} catch (IllegalArgumentException e) {
return ContextHubTransaction.RESULT_FAILED_BAD_PARAMS;
}
}
@ContextHubTransaction.Result
public int enableNanoapp(int contextHubId, long nanoappId, int transactionId)
throws RemoteException {
android.hardware.contexthub.IContextHub hub = getHub();
if (hub == null) {
return ContextHubTransaction.RESULT_FAILED_BAD_PARAMS;
}
try {
hub.enableNanoapp(contextHubId, nanoappId, transactionId);
return ContextHubTransaction.RESULT_SUCCESS;
} catch (RemoteException | ServiceSpecificException | UnsupportedOperationException e) {
return ContextHubTransaction.RESULT_FAILED_UNKNOWN;
} catch (IllegalArgumentException e) {
return ContextHubTransaction.RESULT_FAILED_BAD_PARAMS;
}
}
@ContextHubTransaction.Result
public int disableNanoapp(int contextHubId, long nanoappId, int transactionId)
throws RemoteException {
android.hardware.contexthub.IContextHub hub = getHub();
if (hub == null) {
return ContextHubTransaction.RESULT_FAILED_BAD_PARAMS;
}
try {
hub.disableNanoapp(contextHubId, nanoappId, transactionId);
return ContextHubTransaction.RESULT_SUCCESS;
} catch (RemoteException | ServiceSpecificException | UnsupportedOperationException e) {
return ContextHubTransaction.RESULT_FAILED_UNKNOWN;
} catch (IllegalArgumentException e) {
return ContextHubTransaction.RESULT_FAILED_BAD_PARAMS;
}
}
@ContextHubTransaction.Result
public int queryNanoapps(int contextHubId) throws RemoteException {
android.hardware.contexthub.IContextHub hub = getHub();
if (hub == null) {
return ContextHubTransaction.RESULT_FAILED_BAD_PARAMS;
}
try {
hub.queryNanoapps(contextHubId);
return ContextHubTransaction.RESULT_SUCCESS;
} catch (RemoteException | ServiceSpecificException | UnsupportedOperationException e) {
return ContextHubTransaction.RESULT_FAILED_UNKNOWN;
} catch (IllegalArgumentException e) {
return ContextHubTransaction.RESULT_FAILED_BAD_PARAMS;
}
}
public long[] getPreloadedNanoappIds(int contextHubId) {
android.hardware.contexthub.IContextHub hub = getHub();
if (hub == null) {
return null;
}
try {
return hub.getPreloadedNanoappIds(contextHubId);
} catch (RemoteException e) {
Log.e(TAG, "Exception while getting preloaded nanoapp IDs: " + e.getMessage());
return null;
}
}
public void registerExistingCallback(int contextHubId) {
android.hardware.contexthub.IContextHub hub = getHub();
if (hub == null) {
return;
}
ContextHubAidlCallback callback = mAidlCallbackMap.get(contextHubId);
if (callback == null) {
Log.e(TAG, "Could not find existing callback to register for context hub ID = "
+ contextHubId);
return;
}
try {
hub.registerCallback(contextHubId, callback);
} catch (RemoteException | ServiceSpecificException | IllegalArgumentException e) {
Log.e(TAG, "Exception while registering callback: " + e.getMessage());
}
}
public void registerCallback(int contextHubId, ICallback callback) {
android.hardware.contexthub.IContextHub hub = getHub();
if (hub == null) {
return;
}
mHandleServiceRestartCallback = callback::handleServiceRestart;
mAidlCallbackMap.put(contextHubId, new ContextHubAidlCallback(contextHubId, callback));
registerExistingCallback(contextHubId);
}
public boolean setTestMode(boolean enable) {
android.hardware.contexthub.IContextHub hub = getHub();
if (hub == null) {
return false;
}
try {
hub.setTestMode(enable);
return true;
} catch (RemoteException | ServiceSpecificException e) {
Log.e(TAG, "Exception while setting test mode (enable: "
+ (enable ? "true" : "false") + "): " + e.getMessage());
return false;
}
}
private void onSettingChanged(byte setting, boolean enabled) {
android.hardware.contexthub.IContextHub hub = getHub();
if (hub == null) {
return;
}
try {
hub.onSettingChanged(setting, enabled);
} catch (RemoteException | ServiceSpecificException e) {
Log.e(TAG, "Exception while sending setting update: " + e.getMessage());
}
}
/**
* Links the mHub death handler to this
*/
private void linkWrapperToHubDeath() {
android.hardware.contexthub.IContextHub hub = getHub();
if (hub == null) {
return;
}
try {
hub.asBinder().linkToDeath(this, 0);
} catch (RemoteException exception) {
Log.e(TAG, "Context Hub AIDL service death receipt could not be linked");
}
}
}
/**
* An abstract call that defines methods common to all HIDL IContextHubWrappers.
*/
private abstract static class ContextHubWrapperHidl extends IContextHubWrapper {
private android.hardware.contexthub.V1_0.IContexthub mHub;
protected ICallback mCallback = null;
protected final Map<Integer, ContextHubWrapperHidlCallback> mHidlCallbackMap =
new HashMap<>();
protected class ContextHubWrapperHidlCallback extends IContexthubCallback.Stub {
private final int mContextHubId;
private final ICallback mCallback;
ContextHubWrapperHidlCallback(int contextHubId, ICallback callback) {
mContextHubId = contextHubId;
mCallback = callback;
}
@Override
public void handleClientMsg(ContextHubMsg message) {
mCallback.handleNanoappMessage(
message.hostEndPoint,
ContextHubServiceUtil.createNanoAppMessage(message),
Collections.emptyList() /* nanoappPermissions */,
Collections.emptyList() /* messagePermissions */);
}
@Override
public void handleTxnResult(int transactionId, int result) {
mCallback.handleTransactionResult(transactionId,
result == TransactionResult.SUCCESS);
}
@Override
public void handleHubEvent(int eventType) {
mCallback.handleContextHubEvent(
ContextHubServiceUtil.toContextHubEvent(eventType));
}
@Override
public void handleAppAbort(long nanoAppId, int abortCode) {
mCallback.handleNanoappAbort(nanoAppId, abortCode);
}
@Override
public void handleAppsInfo(
ArrayList<android.hardware.contexthub.V1_0.HubAppInfo> nanoAppInfoList) {
handleAppsInfo_1_2(ContextHubServiceUtil.toHubAppInfo_1_2(nanoAppInfoList));
}
@Override
public void handleClientMsg_1_2(android.hardware.contexthub.V1_2.ContextHubMsg message,
ArrayList<String> messagePermissions) {
mCallback.handleNanoappMessage(
message.msg_1_0.hostEndPoint,
ContextHubServiceUtil.createNanoAppMessage(message.msg_1_0),
message.permissions, messagePermissions);
}
@Override
public void handleAppsInfo_1_2(ArrayList<HubAppInfo> nanoAppInfoList) {
List<NanoAppState> nanoAppStateList =
ContextHubServiceUtil.createNanoAppStateList(nanoAppInfoList);
mCallback.handleNanoappInfo(nanoAppStateList);
}
}
ContextHubWrapperHidl(android.hardware.contexthub.V1_0.IContexthub hub) {
mHub = hub;
}
@ContextHubTransaction.Result
public int sendMessageToContextHub(
short hostEndpointId, int contextHubId, NanoAppMessage message)
throws RemoteException {
ContextHubMsg messageToNanoApp =
ContextHubServiceUtil.createHidlContextHubMessage(hostEndpointId, message);
return ContextHubServiceUtil.toTransactionResult(
mHub.sendMessageToHub(contextHubId, messageToNanoApp));
}
@ContextHubTransaction.Result
public int loadNanoapp(int contextHubId, NanoAppBinary binary,
int transactionId) throws RemoteException {
android.hardware.contexthub.V1_0.NanoAppBinary hidlNanoAppBinary =
ContextHubServiceUtil.createHidlNanoAppBinary(binary);
return ContextHubServiceUtil.toTransactionResult(mHub.loadNanoApp(
contextHubId, hidlNanoAppBinary, transactionId));
}
@ContextHubTransaction.Result
public int unloadNanoapp(int contextHubId, long nanoappId, int transactionId)
throws RemoteException {
return ContextHubServiceUtil.toTransactionResult(mHub.unloadNanoApp(
contextHubId, nanoappId, transactionId));
}
@ContextHubTransaction.Result
public int enableNanoapp(int contextHubId, long nanoappId, int transactionId)
throws RemoteException {
return ContextHubServiceUtil.toTransactionResult(mHub.enableNanoApp(
contextHubId, nanoappId, transactionId));
}
@ContextHubTransaction.Result
public int disableNanoapp(int contextHubId, long nanoappId, int transactionId)
throws RemoteException {
return ContextHubServiceUtil.toTransactionResult(mHub.disableNanoApp(
contextHubId, nanoappId, transactionId));
}
@ContextHubTransaction.Result
public int queryNanoapps(int contextHubId) throws RemoteException {
return ContextHubServiceUtil.toTransactionResult(
mHub.queryApps(contextHubId));
}
public long[] getPreloadedNanoappIds(int contextHubId) {
return new long[0];
}
public void registerCallback(int contextHubId, ICallback callback) throws RemoteException {
mHidlCallbackMap.put(contextHubId,
new ContextHubWrapperHidlCallback(contextHubId, callback));
mHub.registerCallback(contextHubId, mHidlCallbackMap.get(contextHubId));
}
public void registerExistingCallback(int contextHubId) throws RemoteException {
ContextHubWrapperHidlCallback callback = mHidlCallbackMap.get(contextHubId);
if (callback == null) {
Log.e(TAG, "Could not find existing callback for context hub with ID = "
+ contextHubId);
return;
}
mHub.registerCallback(contextHubId, callback);
}
public boolean setTestMode(boolean enable) {
return false;
}
public boolean supportsBtSettingNotifications() {
return false;
}
public void onWifiMainSettingChanged(boolean enabled) {}
public void onWifiScanningSettingChanged(boolean enabled) {}
public void onBtMainSettingChanged(boolean enabled) {}
public void onBtScanningSettingChanged(boolean enabled) {}
}
private static class ContextHubWrapperV1_0 extends ContextHubWrapperHidl {
private android.hardware.contexthub.V1_0.IContexthub mHub;
ContextHubWrapperV1_0(android.hardware.contexthub.V1_0.IContexthub hub) {
super(hub);
mHub = hub;
}
public Pair<List<ContextHubInfo>, List<String>> getHubs() throws RemoteException {
ArrayList<ContextHubInfo> hubInfoList = new ArrayList<>();
for (ContextHub hub : mHub.getHubs()) {
hubInfoList.add(new ContextHubInfo(hub));
}
return new Pair(hubInfoList, new ArrayList<String>());
}
public boolean supportsLocationSettingNotifications() {
return false;
}
public boolean supportsWifiSettingNotifications() {
return false;
}
public boolean supportsAirplaneModeSettingNotifications() {
return false;
}
public boolean supportsMicrophoneSettingNotifications() {
return false;
}
public void onLocationSettingChanged(boolean enabled) {
}
public void onWifiSettingChanged(boolean enabled) {
}
public void onAirplaneModeSettingChanged(boolean enabled) {
}
public void onMicrophoneSettingChanged(boolean enabled) {
}
}
private static class ContextHubWrapperV1_1 extends ContextHubWrapperHidl {
private android.hardware.contexthub.V1_1.IContexthub mHub;
ContextHubWrapperV1_1(android.hardware.contexthub.V1_1.IContexthub hub) {
super(hub);
mHub = hub;
}
public Pair<List<ContextHubInfo>, List<String>> getHubs() throws RemoteException {
ArrayList<ContextHubInfo> hubInfoList = new ArrayList<>();
for (ContextHub hub : mHub.getHubs()) {
hubInfoList.add(new ContextHubInfo(hub));
}
return new Pair(hubInfoList, new ArrayList<String>());
}
public boolean supportsLocationSettingNotifications() {
return true;
}
public boolean supportsWifiSettingNotifications() {
return false;
}
public boolean supportsAirplaneModeSettingNotifications() {
return false;
}
public boolean supportsMicrophoneSettingNotifications() {
return false;
}
public void onLocationSettingChanged(boolean enabled) {
try {
mHub.onSettingChanged(Setting.LOCATION,
enabled ? SettingValue.ENABLED : SettingValue.DISABLED);
} catch (RemoteException e) {
Log.e(TAG, "Failed to send setting change to Contexthub", e);
}
}
public void onWifiSettingChanged(boolean enabled) {
}
public void onAirplaneModeSettingChanged(boolean enabled) {
}
public void onMicrophoneSettingChanged(boolean enabled) {
}
}
private static class ContextHubWrapperV1_2 extends ContextHubWrapperHidl
implements android.hardware.contexthub.V1_2.IContexthub.getHubs_1_2Callback {
private final android.hardware.contexthub.V1_2.IContexthub mHub;
private Pair<List<ContextHubInfo>, List<String>> mHubInfo =
new Pair<>(Collections.emptyList(), Collections.emptyList());
ContextHubWrapperV1_2(android.hardware.contexthub.V1_2.IContexthub hub) {
super(hub);
mHub = hub;
}
@Override
public void onValues(ArrayList<ContextHub> hubs, ArrayList<String> supportedPermissions) {
ArrayList<ContextHubInfo> hubInfoList = new ArrayList<>();
for (ContextHub hub : hubs) {
hubInfoList.add(new ContextHubInfo(hub));
}
mHubInfo = new Pair(hubInfoList, supportedPermissions);
}
public Pair<List<ContextHubInfo>, List<String>> getHubs() throws RemoteException {
mHub.getHubs_1_2(this);
return mHubInfo;
}
public boolean supportsLocationSettingNotifications() {
return true;
}
public boolean supportsWifiSettingNotifications() {
return true;
}
public boolean supportsAirplaneModeSettingNotifications() {
return true;
}
public boolean supportsMicrophoneSettingNotifications() {
return true;
}
public void onLocationSettingChanged(boolean enabled) {
sendSettingChanged(Setting.LOCATION,
enabled ? SettingValue.ENABLED : SettingValue.DISABLED);
}
public void onWifiSettingChanged(boolean enabled) {
sendSettingChanged(android.hardware.contexthub.V1_2.Setting.WIFI_AVAILABLE,
enabled ? SettingValue.ENABLED : SettingValue.DISABLED);
}
public void onAirplaneModeSettingChanged(boolean enabled) {
sendSettingChanged(android.hardware.contexthub.V1_2.Setting.AIRPLANE_MODE,
enabled ? SettingValue.ENABLED : SettingValue.DISABLED);
}
public void onMicrophoneSettingChanged(boolean enabled) {
sendSettingChanged(android.hardware.contexthub.V1_2.Setting.MICROPHONE,
enabled ? SettingValue.ENABLED : SettingValue.DISABLED);
}
public void registerCallback(int contextHubId, ICallback callback) throws RemoteException {
mHidlCallbackMap.put(contextHubId,
new ContextHubWrapperHidlCallback(contextHubId, callback));
mHub.registerCallback_1_2(contextHubId, mHidlCallbackMap.get(contextHubId));
}
private void sendSettingChanged(byte setting, byte newValue) {
try {
mHub.onSettingChanged_1_2(setting, newValue);
} catch (RemoteException e) {
Log.e(TAG, "Failed to send setting change to Contexthub", e);
}
}
}
}