diff options
24 files changed, 1385 insertions, 0 deletions
diff --git a/Android.bp b/Android.bp index 8e53738e97be..dfc521df6ffd 100644 --- a/Android.bp +++ b/Android.bp @@ -191,6 +191,10 @@ java_defaults { "core/java/android/hardware/input/IInputDevicesChangedListener.aidl", "core/java/android/hardware/input/ITabletModeChangedListener.aidl", "core/java/android/hardware/iris/IIrisService.aidl", + "core/java/android/hardware/location/IActivityRecognitionHardware.aidl", + "core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl", + "core/java/android/hardware/location/IActivityRecognitionHardwareSink.aidl", + "core/java/android/hardware/location/IActivityRecognitionHardwareWatcher.aidl", "core/java/android/hardware/location/IGeofenceHardware.aidl", "core/java/android/hardware/location/IGeofenceHardwareCallback.aidl", "core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl", diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt index 3ec0db4d99ce..c2e441b35f48 100644 --- a/config/boot-image-profile.txt +++ b/config/boot-image-profile.txt @@ -2768,6 +2768,11 @@ HPLandroid/hardware/location/GeofenceHardwareService$1;->getStatusOfMonitoringTy HPLandroid/hardware/location/GeofenceHardwareService$1;->registerForMonitorStateChangeCallback(ILandroid/hardware/location/IGeofenceHardwareMonitorCallback;)Z HPLandroid/hardware/location/GeofenceHardwareService$1;->removeGeofence(II)Z HPLandroid/hardware/location/GeofenceHardwareService;->checkPermission(III)V +HPLandroid/hardware/location/IActivityRecognitionHardwareClient$Stub$Proxy;->onAvailabilityChanged(ZLandroid/hardware/location/IActivityRecognitionHardware;)V +HPLandroid/hardware/location/IActivityRecognitionHardwareClient$Stub;-><init>()V +HPLandroid/hardware/location/IActivityRecognitionHardwareClient$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/location/IActivityRecognitionHardwareClient; +HPLandroid/hardware/location/IActivityRecognitionHardwareClient$Stub;->onTransact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z +HPLandroid/hardware/location/IActivityRecognitionHardwareClient;->onAvailabilityChanged(ZLandroid/hardware/location/IActivityRecognitionHardware;)V HPLandroid/hardware/location/IContextHubCallback$Stub;->asBinder()Landroid/os/IBinder; HPLandroid/hardware/location/IContextHubCallback$Stub;->onTransact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z HPLandroid/hardware/location/IContextHubService$Stub$Proxy;->findNanoAppOnHub(ILandroid/hardware/location/NanoAppFilter;)[I @@ -21777,6 +21782,7 @@ HSPLandroid/hardware/input/KeyboardLayout$1;-><init>()V HSPLandroid/hardware/input/TouchCalibration$1;-><init>()V HSPLandroid/hardware/input/TouchCalibration;-><init>()V HSPLandroid/hardware/input/TouchCalibration;->getAffineTransform()[F +HSPLandroid/hardware/location/ActivityRecognitionHardware;->isSupported()Z HSPLandroid/hardware/location/ContextHubInfo$1;-><init>()V HSPLandroid/hardware/location/ContextHubInfo;-><init>(Landroid/hardware/contexthub/V1_0/ContextHub;)V HSPLandroid/hardware/location/ContextHubMessage$1;-><init>()V @@ -21796,6 +21802,13 @@ HSPLandroid/hardware/location/GeofenceHardwareService$1;->setGpsGeofenceHardware HSPLandroid/hardware/location/GeofenceHardwareService;-><init>()V HSPLandroid/hardware/location/GeofenceHardwareService;->onBind(Landroid/content/Intent;)Landroid/os/IBinder; HSPLandroid/hardware/location/GeofenceHardwareService;->onCreate()V +HSPLandroid/hardware/location/IActivityRecognitionHardware;->disableActivityEvent(Ljava/lang/String;I)Z +HSPLandroid/hardware/location/IActivityRecognitionHardware;->enableActivityEvent(Ljava/lang/String;IJ)Z +HSPLandroid/hardware/location/IActivityRecognitionHardware;->flush()Z +HSPLandroid/hardware/location/IActivityRecognitionHardware;->getSupportedActivities()[Ljava/lang/String; +HSPLandroid/hardware/location/IActivityRecognitionHardware;->isActivitySupported(Ljava/lang/String;)Z +HSPLandroid/hardware/location/IActivityRecognitionHardware;->registerSink(Landroid/hardware/location/IActivityRecognitionHardwareSink;)Z +HSPLandroid/hardware/location/IActivityRecognitionHardware;->unregisterSink(Landroid/hardware/location/IActivityRecognitionHardwareSink;)Z HSPLandroid/hardware/location/IContextHubCallback$Stub$Proxy;->asBinder()Landroid/os/IBinder; HSPLandroid/hardware/location/IContextHubCallback$Stub$Proxy;->onMessageReceipt(IILandroid/hardware/location/ContextHubMessage;)V HSPLandroid/hardware/location/IContextHubCallback;->onMessageReceipt(IILandroid/hardware/location/ContextHubMessage;)V @@ -55637,6 +55650,7 @@ Landroid/hardware/input/InputManagerInternal; Landroid/hardware/input/KeyboardLayout$1; Landroid/hardware/input/TouchCalibration$1; Landroid/hardware/input/TouchCalibration; +Landroid/hardware/location/ActivityRecognitionHardware; Landroid/hardware/location/ContextHubInfo$1; Landroid/hardware/location/ContextHubInfo; Landroid/hardware/location/ContextHubManager; @@ -55652,6 +55666,11 @@ Landroid/hardware/location/GeofenceHardwareMonitorEvent; Landroid/hardware/location/GeofenceHardwareRequestParcelable$1; Landroid/hardware/location/GeofenceHardwareService$1; Landroid/hardware/location/GeofenceHardwareService; +Landroid/hardware/location/IActivityRecognitionHardware$Stub; +Landroid/hardware/location/IActivityRecognitionHardware; +Landroid/hardware/location/IActivityRecognitionHardwareClient$Stub$Proxy; +Landroid/hardware/location/IActivityRecognitionHardwareClient$Stub; +Landroid/hardware/location/IActivityRecognitionHardwareClient; Landroid/hardware/location/IContextHubCallback$Stub$Proxy; Landroid/hardware/location/IContextHubCallback; Landroid/hardware/location/IContextHubClient$Stub; diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt index 3a4d9043d189..fc47f67f174c 100644 --- a/config/hiddenapi-greylist.txt +++ b/config/hiddenapi-greylist.txt @@ -462,6 +462,8 @@ Landroid/hardware/input/IInputManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Landroid/hardware/input/IInputManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/input/IInputManager; Landroid/hardware/input/IInputManager$Stub;->TRANSACTION_injectInputEvent:I Landroid/hardware/input/IInputManager;->injectInputEvent(Landroid/view/InputEvent;I)Z +Landroid/hardware/location/IActivityRecognitionHardwareClient$Stub;-><init>()V +Landroid/hardware/location/IActivityRecognitionHardwareClient;->onAvailabilityChanged(ZLandroid/hardware/location/IActivityRecognitionHardware;)V Landroid/hardware/location/IContextHubService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/location/IContextHubService; Landroid/hardware/usb/IUsbManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Landroid/hardware/usb/IUsbManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/usb/IUsbManager; diff --git a/config/preloaded-classes b/config/preloaded-classes index cd798adf5d44..c8a2a9c19b28 100644 --- a/config/preloaded-classes +++ b/config/preloaded-classes @@ -1405,7 +1405,10 @@ android.hardware.input.InputManager android.hardware.input.InputManager$InputDeviceListener android.hardware.input.InputManager$InputDeviceListenerDelegate android.hardware.input.InputManager$InputDevicesChangedListener +android.hardware.location.ActivityRecognitionHardware android.hardware.location.ContextHubManager +android.hardware.location.IActivityRecognitionHardware +android.hardware.location.IActivityRecognitionHardware$Stub android.hardware.radio.RadioManager android.hardware.soundtrigger.SoundTrigger android.hardware.soundtrigger.SoundTrigger$ConfidenceLevel diff --git a/core/java/android/hardware/location/ActivityChangedEvent.aidl b/core/java/android/hardware/location/ActivityChangedEvent.aidl new file mode 100644 index 000000000000..21f24459ac85 --- /dev/null +++ b/core/java/android/hardware/location/ActivityChangedEvent.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2014 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; + +parcelable ActivityChangedEvent;
\ No newline at end of file diff --git a/core/java/android/hardware/location/ActivityChangedEvent.java b/core/java/android/hardware/location/ActivityChangedEvent.java new file mode 100644 index 000000000000..16cfe6e23e88 --- /dev/null +++ b/core/java/android/hardware/location/ActivityChangedEvent.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2014 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.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +import java.security.InvalidParameterException; +import java.util.Arrays; +import java.util.List; + +/** + * A class representing an event for Activity changes. + * + * @hide + */ +public class ActivityChangedEvent implements Parcelable { + private final List<ActivityRecognitionEvent> mActivityRecognitionEvents; + + public ActivityChangedEvent(ActivityRecognitionEvent[] activityRecognitionEvents) { + if (activityRecognitionEvents == null) { + throw new InvalidParameterException( + "Parameter 'activityRecognitionEvents' must not be null."); + } + + mActivityRecognitionEvents = Arrays.asList(activityRecognitionEvents); + } + + @NonNull + public Iterable<ActivityRecognitionEvent> getActivityRecognitionEvents() { + return mActivityRecognitionEvents; + } + + public static final Creator<ActivityChangedEvent> CREATOR = + new Creator<ActivityChangedEvent>() { + @Override + public ActivityChangedEvent createFromParcel(Parcel source) { + int activityRecognitionEventsLength = source.readInt(); + ActivityRecognitionEvent[] activityRecognitionEvents = + new ActivityRecognitionEvent[activityRecognitionEventsLength]; + source.readTypedArray(activityRecognitionEvents, ActivityRecognitionEvent.CREATOR); + + return new ActivityChangedEvent(activityRecognitionEvents); + } + + @Override + public ActivityChangedEvent[] newArray(int size) { + return new ActivityChangedEvent[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + ActivityRecognitionEvent[] activityRecognitionEventArray = + mActivityRecognitionEvents.toArray(new ActivityRecognitionEvent[0]); + parcel.writeInt(activityRecognitionEventArray.length); + parcel.writeTypedArray(activityRecognitionEventArray, flags); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder("[ ActivityChangedEvent:"); + + for (ActivityRecognitionEvent event : mActivityRecognitionEvents) { + builder.append("\n "); + builder.append(event.toString()); + } + builder.append("\n]"); + + return builder.toString(); + } +} diff --git a/core/java/android/hardware/location/ActivityRecognitionEvent.java b/core/java/android/hardware/location/ActivityRecognitionEvent.java new file mode 100644 index 000000000000..190030a82d6b --- /dev/null +++ b/core/java/android/hardware/location/ActivityRecognitionEvent.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2014 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.os.Parcel; +import android.os.Parcelable; + +/** + * A class that represents an Activity Recognition Event. + * + * @hide + */ +public class ActivityRecognitionEvent implements Parcelable { + private final String mActivity; + private final int mEventType; + private final long mTimestampNs; + + public ActivityRecognitionEvent(String activity, int eventType, long timestampNs) { + mActivity = activity; + mEventType = eventType; + mTimestampNs = timestampNs; + } + + public String getActivity() { + return mActivity; + } + + public int getEventType() { + return mEventType; + } + + public long getTimestampNs() { + return mTimestampNs; + } + + public static final Creator<ActivityRecognitionEvent> CREATOR = + new Creator<ActivityRecognitionEvent>() { + @Override + public ActivityRecognitionEvent createFromParcel(Parcel source) { + String activity = source.readString(); + int eventType = source.readInt(); + long timestampNs = source.readLong(); + + return new ActivityRecognitionEvent(activity, eventType, timestampNs); + } + + @Override + public ActivityRecognitionEvent[] newArray(int size) { + return new ActivityRecognitionEvent[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeString(mActivity); + parcel.writeInt(mEventType); + parcel.writeLong(mTimestampNs); + } + + @Override + public String toString() { + return String.format( + "Activity='%s', EventType=%s, TimestampNs=%s", + mActivity, + mEventType, + mTimestampNs); + } +} diff --git a/core/java/android/hardware/location/ActivityRecognitionHardware.java b/core/java/android/hardware/location/ActivityRecognitionHardware.java new file mode 100644 index 000000000000..8acd1ff27917 --- /dev/null +++ b/core/java/android/hardware/location/ActivityRecognitionHardware.java @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2014 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.Manifest; +import android.content.Context; +import android.os.RemoteCallbackList; +import android.os.RemoteException; +import android.text.TextUtils; +import android.util.Log; + +/** + * A class that implements an {@link IActivityRecognitionHardware} backed up by the Activity + * Recognition HAL. + * + * @hide + */ +public class ActivityRecognitionHardware extends IActivityRecognitionHardware.Stub { + private static final String TAG = "ActivityRecognitionHW"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + private static final String HARDWARE_PERMISSION = Manifest.permission.LOCATION_HARDWARE; + private static final String ENFORCE_HW_PERMISSION_MESSAGE = "Permission '" + + HARDWARE_PERMISSION + "' not granted to access ActivityRecognitionHardware"; + + private static final int INVALID_ACTIVITY_TYPE = -1; + private static final int NATIVE_SUCCESS_RESULT = 0; + private static final int EVENT_TYPE_DISABLED = 0; + private static final int EVENT_TYPE_ENABLED = 1; + + /** + * Contains the number of supported Event Types. + * + * NOTE: increment this counter every time a new EVENT_TYPE_ is added to + * com.android.location.provider.ActivityRecognitionProvider + */ + private static final int EVENT_TYPE_COUNT = 3; + + private static ActivityRecognitionHardware sSingletonInstance; + private static final Object sSingletonInstanceLock = new Object(); + + private final Context mContext; + private final int mSupportedActivitiesCount; + private final String[] mSupportedActivities; + private final int[][] mSupportedActivitiesEnabledEvents; + private final SinkList mSinks = new SinkList(); + + private static class Event { + public int activity; + public int type; + public long timestamp; + } + + private ActivityRecognitionHardware(Context context) { + nativeInitialize(); + + mContext = context; + mSupportedActivities = fetchSupportedActivities(); + mSupportedActivitiesCount = mSupportedActivities.length; + mSupportedActivitiesEnabledEvents = new int[mSupportedActivitiesCount][EVENT_TYPE_COUNT]; + } + + public static ActivityRecognitionHardware getInstance(Context context) { + synchronized (sSingletonInstanceLock) { + if (sSingletonInstance == null) { + sSingletonInstance = new ActivityRecognitionHardware(context); + } + + return sSingletonInstance; + } + } + + public static boolean isSupported() { + return nativeIsSupported(); + } + + @Override + public String[] getSupportedActivities() { + checkPermissions(); + return mSupportedActivities; + } + + @Override + public boolean isActivitySupported(String activity) { + checkPermissions(); + int activityType = getActivityType(activity); + return activityType != INVALID_ACTIVITY_TYPE; + } + + @Override + public boolean registerSink(IActivityRecognitionHardwareSink sink) { + checkPermissions(); + return mSinks.register(sink); + } + + @Override + public boolean unregisterSink(IActivityRecognitionHardwareSink sink) { + checkPermissions(); + return mSinks.unregister(sink); + } + + @Override + public boolean enableActivityEvent(String activity, int eventType, long reportLatencyNs) { + checkPermissions(); + + int activityType = getActivityType(activity); + if (activityType == INVALID_ACTIVITY_TYPE) { + return false; + } + + int result = nativeEnableActivityEvent(activityType, eventType, reportLatencyNs); + if (result == NATIVE_SUCCESS_RESULT) { + mSupportedActivitiesEnabledEvents[activityType][eventType] = EVENT_TYPE_ENABLED; + return true; + } + return false; + } + + @Override + public boolean disableActivityEvent(String activity, int eventType) { + checkPermissions(); + + int activityType = getActivityType(activity); + if (activityType == INVALID_ACTIVITY_TYPE) { + return false; + } + + int result = nativeDisableActivityEvent(activityType, eventType); + if (result == NATIVE_SUCCESS_RESULT) { + mSupportedActivitiesEnabledEvents[activityType][eventType] = EVENT_TYPE_DISABLED; + return true; + } + return false; + } + + @Override + public boolean flush() { + checkPermissions(); + int result = nativeFlush(); + return result == NATIVE_SUCCESS_RESULT; + } + + /** + * Called by the Activity-Recognition HAL. + */ + private void onActivityChanged(Event[] events) { + if (events == null || events.length == 0) { + if (DEBUG) Log.d(TAG, "No events to broadcast for onActivityChanged."); + return; + } + + int eventsLength = events.length; + ActivityRecognitionEvent activityRecognitionEventArray[] = + new ActivityRecognitionEvent[eventsLength]; + for (int i = 0; i < eventsLength; ++i) { + Event event = events[i]; + String activityName = getActivityName(event.activity); + activityRecognitionEventArray[i] = + new ActivityRecognitionEvent(activityName, event.type, event.timestamp); + } + ActivityChangedEvent activityChangedEvent = + new ActivityChangedEvent(activityRecognitionEventArray); + + int size = mSinks.beginBroadcast(); + for (int i = 0; i < size; ++i) { + IActivityRecognitionHardwareSink sink = mSinks.getBroadcastItem(i); + try { + sink.onActivityChanged(activityChangedEvent); + } catch (RemoteException e) { + Log.e(TAG, "Error delivering activity changed event.", e); + } + } + mSinks.finishBroadcast(); + } + + private String getActivityName(int activityType) { + if (activityType < 0 || activityType >= mSupportedActivities.length) { + String message = String.format( + "Invalid ActivityType: %d, SupportedActivities: %d", + activityType, + mSupportedActivities.length); + Log.e(TAG, message); + return null; + } + + return mSupportedActivities[activityType]; + } + + private int getActivityType(String activity) { + if (TextUtils.isEmpty(activity)) { + return INVALID_ACTIVITY_TYPE; + } + + int supportedActivitiesLength = mSupportedActivities.length; + for (int i = 0; i < supportedActivitiesLength; ++i) { + if (activity.equals(mSupportedActivities[i])) { + return i; + } + } + + return INVALID_ACTIVITY_TYPE; + } + + private void checkPermissions() { + mContext.enforceCallingPermission(HARDWARE_PERMISSION, ENFORCE_HW_PERMISSION_MESSAGE); + } + + private String[] fetchSupportedActivities() { + String[] supportedActivities = nativeGetSupportedActivities(); + if (supportedActivities != null) { + return supportedActivities; + } + + return new String[0]; + } + + private class SinkList extends RemoteCallbackList<IActivityRecognitionHardwareSink> { + @Override + public void onCallbackDied(IActivityRecognitionHardwareSink callback) { + int callbackCount = mSinks.getRegisteredCallbackCount(); + if (DEBUG) Log.d(TAG, "RegisteredCallbackCount: " + callbackCount); + if (callbackCount != 0) { + return; + } + // currently there is only one client for this, so if all its sinks have died, we clean + // up after them, this ensures that the AR HAL is not out of sink + for (int activity = 0; activity < mSupportedActivitiesCount; ++activity) { + for (int event = 0; event < EVENT_TYPE_COUNT; ++event) { + disableActivityEventIfEnabled(activity, event); + } + } + } + + private void disableActivityEventIfEnabled(int activityType, int eventType) { + if (mSupportedActivitiesEnabledEvents[activityType][eventType] != EVENT_TYPE_ENABLED) { + return; + } + + int result = nativeDisableActivityEvent(activityType, eventType); + mSupportedActivitiesEnabledEvents[activityType][eventType] = EVENT_TYPE_DISABLED; + String message = String.format( + "DisableActivityEvent: activityType=%d, eventType=%d, result=%d", + activityType, + eventType, + result); + Log.e(TAG, message); + } + } + + // native bindings + static { nativeClassInit(); } + + private static native void nativeClassInit(); + private static native boolean nativeIsSupported(); + + private native void nativeInitialize(); + private native void nativeRelease(); + private native String[] nativeGetSupportedActivities(); + private native int nativeEnableActivityEvent( + int activityType, + int eventType, + long reportLatenceNs); + private native int nativeDisableActivityEvent(int activityType, int eventType); + private native int nativeFlush(); +} diff --git a/core/java/android/hardware/location/IActivityRecognitionHardware.aidl b/core/java/android/hardware/location/IActivityRecognitionHardware.aidl new file mode 100644 index 000000000000..bc6b1830cd4f --- /dev/null +++ b/core/java/android/hardware/location/IActivityRecognitionHardware.aidl @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2014, 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/license/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.hardware.location.IActivityRecognitionHardwareSink; + +/** + * Activity Recognition Hardware provider interface. + * This interface can be used to implement hardware based activity recognition. + * + * @hide + */ +interface IActivityRecognitionHardware { + /** + * Gets an array of supported activities by hardware. + */ + String[] getSupportedActivities(); + + /** + * Returns true if the given activity is supported, false otherwise. + */ + boolean isActivitySupported(in String activityType); + + /** + * Registers a sink with Hardware Activity-Recognition. + */ + boolean registerSink(in IActivityRecognitionHardwareSink sink); + + /** + * Unregisters a sink with Hardware Activity-Recognition. + */ + boolean unregisterSink(in IActivityRecognitionHardwareSink sink); + + /** + * Enables tracking of a given activity/event type, if the activity is supported. + */ + boolean enableActivityEvent(in String activityType, int eventType, long reportLatencyNs); + + /** + * Disables tracking of a given activity/eventy type. + */ + boolean disableActivityEvent(in String activityType, int eventType); + + /** + * Requests hardware for all the activity events detected up to the given point in time. + */ + boolean flush(); +}
\ No newline at end of file diff --git a/core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl b/core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl new file mode 100644 index 000000000000..3fe645c59a30 --- /dev/null +++ b/core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015, 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/license/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.hardware.location.IActivityRecognitionHardware; + +/** + * Activity Recognition Hardware client interface. + * This interface can be used to receive interfaces to implementations of + * {@link IActivityRecognitionHardware}. + * + * @hide + */ +oneway interface IActivityRecognitionHardwareClient { + /** + * Hardware Activity-Recognition availability event. + * + * @param isSupported whether the platform has hardware support for the feature + * @param instance the available instance to provide access to the feature + */ + void onAvailabilityChanged(in boolean isSupported, in IActivityRecognitionHardware instance); +} diff --git a/core/java/android/hardware/location/IActivityRecognitionHardwareSink.aidl b/core/java/android/hardware/location/IActivityRecognitionHardwareSink.aidl new file mode 100644 index 000000000000..21c8e87e6c6d --- /dev/null +++ b/core/java/android/hardware/location/IActivityRecognitionHardwareSink.aidl @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2014, 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/license/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.hardware.location.ActivityChangedEvent; + +/** + * Activity Recognition Hardware provider Sink interface. + * This interface can be used to implement sinks to receive activity notifications. + * + * @hide + */ +interface IActivityRecognitionHardwareSink { + /** + * Activity changed event. + */ + void onActivityChanged(in ActivityChangedEvent event); +}
\ No newline at end of file diff --git a/core/java/android/hardware/location/IActivityRecognitionHardwareWatcher.aidl b/core/java/android/hardware/location/IActivityRecognitionHardwareWatcher.aidl new file mode 100644 index 000000000000..12e3117259e1 --- /dev/null +++ b/core/java/android/hardware/location/IActivityRecognitionHardwareWatcher.aidl @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2014, 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/license/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.hardware.location.IActivityRecognitionHardware; + +/** + * Activity Recognition Hardware watcher. This interface can be used to receive interfaces to + * implementations of {@link IActivityRecognitionHardware}. + * + * @deprecated use {@link IActivityRecognitionHardwareClient} instead. + + * @hide + */ +interface IActivityRecognitionHardwareWatcher { + /** + * Hardware Activity-Recognition availability event. + */ + void onInstanceChanged(in IActivityRecognitionHardware instance); +} diff --git a/core/jni/Android.bp b/core/jni/Android.bp index c5dfe6c94463..be127009a21d 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -186,6 +186,7 @@ cc_library_shared { "android_hardware_UsbDevice.cpp", "android_hardware_UsbDeviceConnection.cpp", "android_hardware_UsbRequest.cpp", + "android_hardware_location_ActivityRecognitionHardware.cpp", "android_util_FileObserver.cpp", "android/opengl/poly_clip.cpp", // TODO: .arm "android/opengl/util.cpp", diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 5befab93b8d2..18d9b5aeb1c8 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -101,6 +101,7 @@ extern int register_android_hardware_SoundTrigger(JNIEnv *env); extern int register_android_hardware_UsbDevice(JNIEnv *env); extern int register_android_hardware_UsbDeviceConnection(JNIEnv *env); extern int register_android_hardware_UsbRequest(JNIEnv *env); +extern int register_android_hardware_location_ActivityRecognitionHardware(JNIEnv* env); extern int register_android_media_AudioEffectDescriptor(JNIEnv *env); extern int register_android_media_AudioRecord(JNIEnv *env); @@ -1460,6 +1461,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_hardware_UsbDevice), REG_JNI(register_android_hardware_UsbDeviceConnection), REG_JNI(register_android_hardware_UsbRequest), + REG_JNI(register_android_hardware_location_ActivityRecognitionHardware), REG_JNI(register_android_media_AudioEffectDescriptor), REG_JNI(register_android_media_AudioSystem), REG_JNI(register_android_media_AudioRecord), diff --git a/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp b/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp new file mode 100644 index 000000000000..1c9ab9403298 --- /dev/null +++ b/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp @@ -0,0 +1,132 @@ +/* + * Copyright 2014, 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. + */ + +#define LOG_TAG "ActivityRecognitionHardware" + +#include <jni.h> +#include <nativehelper/JNIHelp.h> + +#include <android_runtime/AndroidRuntime.h> +#include <android_runtime/Log.h> + +// #include <hardware/activity_recognition.h> +// The activity recognition HAL is being deprecated. This means - +// i) Android framework code shall not depend on activity recognition +// being provided through the activity_recognition.h interface. +// ii) activity recognition HAL will not be binderized as the other HALs. +// + +/** + * Initializes the ActivityRecognitionHardware class from the native side. + */ +static void class_init(JNIEnv* /*env*/, jclass /*clazz*/) { + ALOGE("activity_recognition HAL is deprecated. %s is effectively a no-op", + __FUNCTION__); +} + +/** + * Initializes and connect the callbacks handlers in the HAL. + */ +static void initialize(JNIEnv* /*env*/, jobject /*obj*/) { + ALOGE("activity_recognition HAL is deprecated. %s is effectively a no-op", + __FUNCTION__); +} + +/** + * De-initializes the ActivityRecognitionHardware from the native side. + */ +static void release(JNIEnv* /*env*/, jobject /*obj*/) { + ALOGE("activity_recognition HAL is deprecated. %s is effectively a no-op", + __FUNCTION__); +} + +/** + * Returns true if ActivityRecognition HAL is supported, false otherwise. + */ +static jboolean is_supported(JNIEnv* /*env*/, jclass /*clazz*/) { + ALOGE("activity_recognition HAL is deprecated. %s is effectively a no-op", + __FUNCTION__); + return JNI_FALSE; +} + +/** + * Gets an array representing the supported activities. + */ +static jobjectArray get_supported_activities(JNIEnv* /*env*/, jobject /*obj*/) { + ALOGE("activity_recognition HAL is deprecated. %s is effectively a no-op", + __FUNCTION__); + return NULL; +} + +/** + * Enables a given activity event to be actively monitored. + */ +static int enable_activity_event( + JNIEnv* /*env*/, + jobject /*obj*/, + jint /*activity_handle*/, + jint /*event_type*/, + jlong /*report_latency_ns*/) { + ALOGE("activity_recognition HAL is deprecated. %s is effectively a no-op", + __FUNCTION__); + return android::NO_INIT; +} + +/** + * Disables a given activity event from being actively monitored. + */ +static int disable_activity_event( + JNIEnv* /*env*/, + jobject /*obj*/, + jint /*activity_handle*/, + jint /*event_type*/) { + ALOGE("activity_recognition HAL is deprecated. %s is effectively a no-op", + __FUNCTION__); + return android::NO_INIT; +} + +/** + * Request flush for al batch buffers. + */ +static int flush(JNIEnv* /*env*/, jobject /*obj*/) { + ALOGE("activity_recognition HAL is deprecated. %s is effectively a no-op", + __FUNCTION__); + return android::NO_INIT; +} + + +static const JNINativeMethod sMethods[] = { + // {"name", "signature", (void*) functionPointer }, + { "nativeClassInit", "()V", (void*) class_init }, + { "nativeInitialize", "()V", (void*) initialize }, + { "nativeRelease", "()V", (void*) release }, + { "nativeIsSupported", "()Z", (void*) is_supported }, + { "nativeGetSupportedActivities", "()[Ljava/lang/String;", (void*) get_supported_activities }, + { "nativeEnableActivityEvent", "(IIJ)I", (void*) enable_activity_event }, + { "nativeDisableActivityEvent", "(II)I", (void*) disable_activity_event }, + { "nativeFlush", "()I", (void*) flush }, +}; + +/** + * Registration method invoked in JNI load. + */ +int register_android_hardware_location_ActivityRecognitionHardware(JNIEnv* env) { + return jniRegisterNativeMethods( + env, + "android/hardware/location/ActivityRecognitionHardware", + sMethods, + NELEM(sMethods)); +} diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 75038c8d00fb..dd2a9899854c 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1747,6 +1747,19 @@ config_enableGeofenceOverlay is false. --> <string name="config_geofenceProviderPackageName" translatable="false">@null</string> + <!-- Whether to enable Hardware Activity-Recognition overlay which allows Hardware + Activity-Recognition to be replaced by an app at run-time. When disabled, only the + config_activityRecognitionHardwarePackageName package will be searched for + its implementation, otherwise packages whose signature matches the + signatures of config_locationProviderPackageNames will be searched, and + the service with the highest version number will be picked. Anyone who + wants to disable the overlay mechanism can set it to false. + --> + <bool name="config_enableActivityRecognitionHardwareOverlay" translatable="false">true</bool> + <!-- Package name providing Hardware Activity-Recognition API support. Used only when + config_enableActivityRecognitionHardwareOverlay is false. --> + <string name="config_activityRecognitionHardwarePackageName" translatable="false">@null</string> + <!-- Package name(s) containing location provider support. These packages can contain services implementing location providers, such as the Geocode Provider, Network Location Provider, and diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 8867539b02ae..1bbbf8d49621 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1853,6 +1853,7 @@ <java-symbol type="bool" name="config_enableNightMode" /> <java-symbol type="bool" name="config_tintNotificationActionButtons" /> <java-symbol type="bool" name="config_dozeAfterScreenOffByDefault" /> + <java-symbol type="bool" name="config_enableActivityRecognitionHardwareOverlay" /> <java-symbol type="bool" name="config_enableFusedLocationOverlay" /> <java-symbol type="bool" name="config_enableHardwareFlpOverlay" /> <java-symbol type="bool" name="config_enableGeocoderOverlay" /> @@ -2021,6 +2022,7 @@ <java-symbol type="string" name="car_mode_disable_notification_title" /> <java-symbol type="string" name="chooser_wallpaper" /> <java-symbol type="string" name="config_datause_iface" /> + <java-symbol type="string" name="config_activityRecognitionHardwarePackageName" /> <java-symbol type="string" name="config_fusedLocationProviderPackageName" /> <java-symbol type="string" name="config_hardwareFlpPackageName" /> <java-symbol type="string" name="config_geocoderProviderPackageName" /> diff --git a/location/lib/java/com/android/location/provider/ActivityChangedEvent.java b/location/lib/java/com/android/location/provider/ActivityChangedEvent.java new file mode 100644 index 000000000000..843dd670315a --- /dev/null +++ b/location/lib/java/com/android/location/provider/ActivityChangedEvent.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2014 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.location.provider; + +import android.annotation.NonNull; + +import java.security.InvalidParameterException; +import java.util.List; + +/** + * A class representing an event for Activity changes. + * @hide + */ +public class ActivityChangedEvent { + private final List<ActivityRecognitionEvent> mActivityRecognitionEvents; + + public ActivityChangedEvent(List<ActivityRecognitionEvent> activityRecognitionEvents) { + if (activityRecognitionEvents == null) { + throw new InvalidParameterException( + "Parameter 'activityRecognitionEvents' must not be null."); + } + + mActivityRecognitionEvents = activityRecognitionEvents; + } + + @NonNull + public Iterable<ActivityRecognitionEvent> getActivityRecognitionEvents() { + return mActivityRecognitionEvents; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder("[ ActivityChangedEvent:"); + + for (ActivityRecognitionEvent event : mActivityRecognitionEvents) { + builder.append("\n "); + builder.append(event.toString()); + } + builder.append("\n]"); + + return builder.toString(); + } +} diff --git a/location/lib/java/com/android/location/provider/ActivityRecognitionEvent.java b/location/lib/java/com/android/location/provider/ActivityRecognitionEvent.java new file mode 100644 index 000000000000..e54dea40d690 --- /dev/null +++ b/location/lib/java/com/android/location/provider/ActivityRecognitionEvent.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2014 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.location.provider; + +/** + * A class that represents an Activity Recognition Event. + * @hide + */ +public class ActivityRecognitionEvent { + private final String mActivity; + private final int mEventType; + private final long mTimestampNs; + + public ActivityRecognitionEvent(String activity, int eventType, long timestampNs) { + mActivity = activity; + mEventType = eventType; + mTimestampNs = timestampNs; + } + + public String getActivity() { + return mActivity; + } + + public int getEventType() { + return mEventType; + } + + public long getTimestampNs() { + return mTimestampNs; + } + + @Override + public String toString() { + String eventString; + switch (mEventType) { + case ActivityRecognitionProvider.EVENT_TYPE_ENTER: + eventString = "Enter"; + break; + case ActivityRecognitionProvider.EVENT_TYPE_EXIT: + eventString = "Exit"; + break; + case ActivityRecognitionProvider.EVENT_TYPE_FLUSH_COMPLETE: + eventString = "FlushComplete"; + break; + default: + eventString = "<Invalid>"; + break; + } + + return String.format( + "Activity='%s', EventType=%s(%s), TimestampNs=%s", + mActivity, + eventString, + mEventType, + mTimestampNs); + } +} diff --git a/location/lib/java/com/android/location/provider/ActivityRecognitionProvider.java b/location/lib/java/com/android/location/provider/ActivityRecognitionProvider.java new file mode 100644 index 000000000000..0eff7d3f2014 --- /dev/null +++ b/location/lib/java/com/android/location/provider/ActivityRecognitionProvider.java @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2014 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.location.provider; + +import com.android.internal.util.Preconditions; + +import android.hardware.location.IActivityRecognitionHardware; +import android.hardware.location.IActivityRecognitionHardwareSink; +import android.os.RemoteException; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; + +/** + * A class that exposes {@link IActivityRecognitionHardware} functionality to unbundled services. + * @hide + */ +public final class ActivityRecognitionProvider { + private final IActivityRecognitionHardware mService; + private final HashSet<Sink> mSinkSet = new HashSet<>(); + + // the following constants must remain in sync with activity_recognition.h + + public static final String ACTIVITY_IN_VEHICLE = "android.activity_recognition.in_vehicle"; + public static final String ACTIVITY_ON_BICYCLE = "android.activity_recognition.on_bicycle"; + public static final String ACTIVITY_WALKING = "android.activity_recognition.walking"; + public static final String ACTIVITY_RUNNING = "android.activity_recognition.running"; + public static final String ACTIVITY_STILL = "android.activity_recognition.still"; + public static final String ACTIVITY_TILTING = "android.activity_recognition.tilting"; + + // NOTE: when adding an additional EVENT_TYPE_, EVENT_TYPE_COUNT needs to be updated in + // android.hardware.location.ActivityRecognitionHardware + public static final int EVENT_TYPE_FLUSH_COMPLETE = 0; + public static final int EVENT_TYPE_ENTER = 1; + public static final int EVENT_TYPE_EXIT = 2; + + // end constants activity_recognition.h + + /** + * Used to receive Activity-Recognition events. + */ + public interface Sink { + void onActivityChanged(ActivityChangedEvent event); + } + + public ActivityRecognitionProvider(IActivityRecognitionHardware service) + throws RemoteException { + Preconditions.checkNotNull(service); + mService = service; + mService.registerSink(new SinkTransport()); + } + + public String[] getSupportedActivities() throws RemoteException { + return mService.getSupportedActivities(); + } + + public boolean isActivitySupported(String activity) throws RemoteException { + return mService.isActivitySupported(activity); + } + + public void registerSink(Sink sink) { + Preconditions.checkNotNull(sink); + synchronized (mSinkSet) { + mSinkSet.add(sink); + } + } + + // TODO: if this functionality is exposed to 3rd party developers, handle unregistration (here + // and in the service) of all sinks while failing to disable all events + public void unregisterSink(Sink sink) { + Preconditions.checkNotNull(sink); + synchronized (mSinkSet) { + mSinkSet.remove(sink); + } + } + + public boolean enableActivityEvent(String activity, int eventType, long reportLatencyNs) + throws RemoteException { + return mService.enableActivityEvent(activity, eventType, reportLatencyNs); + } + + public boolean disableActivityEvent(String activity, int eventType) throws RemoteException { + return mService.disableActivityEvent(activity, eventType); + } + + public boolean flush() throws RemoteException { + return mService.flush(); + } + + private final class SinkTransport extends IActivityRecognitionHardwareSink.Stub { + @Override + public void onActivityChanged(android.hardware.location.ActivityChangedEvent event) { + Collection<Sink> sinks; + synchronized (mSinkSet) { + if (mSinkSet.isEmpty()) { + return; + } + sinks = new ArrayList<>(mSinkSet); + } + + // translate the event from platform internal and GmsCore types + ArrayList<ActivityRecognitionEvent> gmsEvents = new ArrayList<>(); + for (android.hardware.location.ActivityRecognitionEvent reportingEvent + : event.getActivityRecognitionEvents()) { + ActivityRecognitionEvent gmsEvent = new ActivityRecognitionEvent( + reportingEvent.getActivity(), + reportingEvent.getEventType(), + reportingEvent.getTimestampNs()); + gmsEvents.add(gmsEvent); + } + ActivityChangedEvent gmsEvent = new ActivityChangedEvent(gmsEvents); + + for (Sink sink : sinks) { + sink.onActivityChanged(gmsEvent); + } + } + } +} diff --git a/location/lib/java/com/android/location/provider/ActivityRecognitionProviderClient.java b/location/lib/java/com/android/location/provider/ActivityRecognitionProviderClient.java new file mode 100644 index 000000000000..326d901b9daa --- /dev/null +++ b/location/lib/java/com/android/location/provider/ActivityRecognitionProviderClient.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2015 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.location.provider; + +import android.annotation.NonNull; +import android.hardware.location.IActivityRecognitionHardware; +import android.hardware.location.IActivityRecognitionHardwareClient; +import android.os.Binder; +import android.os.IBinder; +import android.os.Process; +import android.os.RemoteException; +import android.util.Log; + +/** + * A client class for interaction with an Activity-Recognition provider. + * @hide + */ +public abstract class ActivityRecognitionProviderClient { + private static final String TAG = "ArProviderClient"; + + protected ActivityRecognitionProviderClient() {} + + private IActivityRecognitionHardwareClient.Stub mClient = + new IActivityRecognitionHardwareClient.Stub() { + @Override + public void onAvailabilityChanged( + boolean isSupported, + IActivityRecognitionHardware instance) { + int callingUid = Binder.getCallingUid(); + if (callingUid != Process.SYSTEM_UID) { + Log.d(TAG, "Ignoring calls from non-system server. Uid: " + callingUid); + return; + } + ActivityRecognitionProvider provider; + try { + provider = isSupported ? new ActivityRecognitionProvider(instance) : null; + } catch (RemoteException e) { + Log.e(TAG, "Error creating Hardware Activity-Recognition Provider.", e); + return; + } + onProviderChanged(isSupported, provider); + } + }; + + /** + * Gets the binder needed to interact with proxy provider in the platform. + */ + @NonNull + public IBinder getBinder() { + return mClient; + } + + /** + * Called when a change in the availability of {@link ActivityRecognitionProvider} is detected. + * + * @param isSupported whether the platform supports the provider natively + * @param instance the available provider's instance + */ + public abstract void onProviderChanged( + boolean isSupported, + ActivityRecognitionProvider instance); +} diff --git a/location/lib/java/com/android/location/provider/ActivityRecognitionProviderWatcher.java b/location/lib/java/com/android/location/provider/ActivityRecognitionProviderWatcher.java new file mode 100644 index 000000000000..42f77b42766f --- /dev/null +++ b/location/lib/java/com/android/location/provider/ActivityRecognitionProviderWatcher.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2014 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.location.provider; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.hardware.location.IActivityRecognitionHardware; +import android.hardware.location.IActivityRecognitionHardwareWatcher; +import android.os.Binder; +import android.os.IBinder; +import android.os.Process; +import android.os.RemoteException; +import android.util.Log; + +/** + * A watcher class for Activity-Recognition instances. + * + * @deprecated use {@link ActivityRecognitionProviderClient} instead. + * @hide + */ +@Deprecated +public class ActivityRecognitionProviderWatcher { + private static final String TAG = "ActivityRecognitionProviderWatcher"; + + private static ActivityRecognitionProviderWatcher sWatcher; + private static final Object sWatcherLock = new Object(); + + private ActivityRecognitionProvider mActivityRecognitionProvider; + + private ActivityRecognitionProviderWatcher() {} + + public static ActivityRecognitionProviderWatcher getInstance() { + synchronized (sWatcherLock) { + if (sWatcher == null) { + sWatcher = new ActivityRecognitionProviderWatcher(); + } + return sWatcher; + } + } + + private IActivityRecognitionHardwareWatcher.Stub mWatcherStub = + new IActivityRecognitionHardwareWatcher.Stub() { + @Override + public void onInstanceChanged(IActivityRecognitionHardware instance) { + int callingUid = Binder.getCallingUid(); + if (callingUid != Process.SYSTEM_UID) { + Log.d(TAG, "Ignoring calls from non-system server. Uid: " + callingUid); + return; + } + + try { + mActivityRecognitionProvider = new ActivityRecognitionProvider(instance); + } catch (RemoteException e) { + Log.e(TAG, "Error creating Hardware Activity-Recognition", e); + } + } + }; + + /** + * Gets the binder needed to interact with proxy provider in the platform. + */ + @NonNull + public IBinder getBinder() { + return mWatcherStub; + } + + /** + * Gets an object that supports the functionality of {@link ActivityRecognitionProvider}. + * + * @return Non-null value if the functionality is supported by the platform, false otherwise. + */ + @Nullable + public ActivityRecognitionProvider getActivityRecognitionProvider() { + return mActivityRecognitionProvider; + } +} diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index add5e5feaa8a..0b4c01ef90bd 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -46,6 +46,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.Signature; import android.content.res.Resources; import android.database.ContentObserver; +import android.hardware.location.ActivityRecognitionHardware; import android.location.Address; import android.location.Criteria; import android.location.GeocoderParams; @@ -92,6 +93,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.Preconditions; import com.android.server.location.AbstractLocationProvider; +import com.android.server.location.ActivityRecognitionProxy; import com.android.server.location.GeocoderProxy; import com.android.server.location.GeofenceManager; import com.android.server.location.GeofenceProxy; @@ -736,6 +738,25 @@ public class LocationManagerService extends ILocationManager.Stub { Slog.d(TAG, "Unable to bind FLP Geofence proxy."); } + // bind to hardware activity recognition + boolean activityRecognitionHardwareIsSupported = ActivityRecognitionHardware.isSupported(); + ActivityRecognitionHardware activityRecognitionHardware = null; + if (activityRecognitionHardwareIsSupported) { + activityRecognitionHardware = ActivityRecognitionHardware.getInstance(mContext); + } else { + Slog.d(TAG, "Hardware Activity-Recognition not supported."); + } + ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind( + mContext, + activityRecognitionHardwareIsSupported, + activityRecognitionHardware, + com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay, + com.android.internal.R.string.config_activityRecognitionHardwarePackageName, + com.android.internal.R.array.config_locationProviderPackageNames); + if (proxy == null) { + Slog.d(TAG, "Unable to bind ActivityRecognitionProxy."); + } + String[] testProviderStrings = resources.getStringArray( com.android.internal.R.array.config_testLocationProviders); for (String testProviderString : testProviderStrings) { diff --git a/services/core/java/com/android/server/location/ActivityRecognitionProxy.java b/services/core/java/com/android/server/location/ActivityRecognitionProxy.java new file mode 100644 index 000000000000..22fabb2cdd3e --- /dev/null +++ b/services/core/java/com/android/server/location/ActivityRecognitionProxy.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2014 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; + +import android.content.Context; +import android.hardware.location.ActivityRecognitionHardware; +import android.hardware.location.IActivityRecognitionHardwareClient; +import android.hardware.location.IActivityRecognitionHardwareWatcher; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +import com.android.internal.os.BackgroundThread; +import com.android.server.ServiceWatcher; + +/** + * Proxy class to bind GmsCore to the ActivityRecognitionHardware. + * + * @hide + */ +public class ActivityRecognitionProxy { + + private static final String TAG = "ActivityRecognitionProxy"; + + /** + * Creates an instance of the proxy and binds it to the appropriate FusedProvider. + * + * @return An instance of the proxy if it could be bound, null otherwise. + */ + public static ActivityRecognitionProxy createAndBind( + Context context, + boolean activityRecognitionHardwareIsSupported, + ActivityRecognitionHardware activityRecognitionHardware, + int overlaySwitchResId, + int defaultServicePackageNameResId, + int initialPackageNameResId) { + ActivityRecognitionProxy activityRecognitionProxy = new ActivityRecognitionProxy( + context, + activityRecognitionHardwareIsSupported, + activityRecognitionHardware, + overlaySwitchResId, + defaultServicePackageNameResId, + initialPackageNameResId); + + if (activityRecognitionProxy.mServiceWatcher.start()) { + return activityRecognitionProxy; + } else { + return null; + } + } + + private final ServiceWatcher mServiceWatcher; + private final boolean mIsSupported; + private final ActivityRecognitionHardware mInstance; + + private ActivityRecognitionProxy( + Context context, + boolean activityRecognitionHardwareIsSupported, + ActivityRecognitionHardware activityRecognitionHardware, + int overlaySwitchResId, + int defaultServicePackageNameResId, + int initialPackageNameResId) { + mIsSupported = activityRecognitionHardwareIsSupported; + mInstance = activityRecognitionHardware; + + mServiceWatcher = new ServiceWatcher( + context, + TAG, + "com.android.location.service.ActivityRecognitionProvider", + overlaySwitchResId, + defaultServicePackageNameResId, + initialPackageNameResId, + BackgroundThread.getHandler()) { + @Override + protected void onBind() { + runOnBinder(ActivityRecognitionProxy.this::initializeService); + } + }; + } + + private void initializeService(IBinder binder) { + try { + String descriptor = binder.getInterfaceDescriptor(); + + if (IActivityRecognitionHardwareWatcher.class.getCanonicalName().equals( + descriptor)) { + IActivityRecognitionHardwareWatcher watcher = + IActivityRecognitionHardwareWatcher.Stub.asInterface(binder); + if (mInstance != null) { + watcher.onInstanceChanged(mInstance); + } + } else if (IActivityRecognitionHardwareClient.class.getCanonicalName() + .equals(descriptor)) { + IActivityRecognitionHardwareClient client = + IActivityRecognitionHardwareClient.Stub.asInterface(binder); + client.onAvailabilityChanged(mIsSupported, mInstance); + } else { + Log.e(TAG, "Invalid descriptor found on connection: " + descriptor); + } + } catch (RemoteException e) { + Log.w(TAG, e); + } + } +} |