Revert "Remove Activity Recognition from the Android Code."

This reverts commit e24f1b095b020382f555c7f34f22ff3fb5005f90.

Reason for revert: b/123172409

Change-Id: Ic5863a8e8b36c8c4d8636cc4c004ad9606a3f523
diff --git a/Android.bp b/Android.bp
index 8e53738..dfc521d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -191,6 +191,10 @@
         "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 3ec0db4..c2e441b 100644
--- a/config/boot-image-profile.txt
+++ b/config/boot-image-profile.txt
@@ -2768,6 +2768,11 @@
 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/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;-><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/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/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 3a4d904..fc47f67 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -462,6 +462,8 @@
 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 cd798ad..c8a2a9c 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -1405,7 +1405,10 @@
 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 0000000..21f2445
--- /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 0000000..16cfe6e
--- /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 0000000..190030a
--- /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 0000000..8acd1ff
--- /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 0000000..bc6b183
--- /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 0000000..3fe645c
--- /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 0000000..21c8e87
--- /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 0000000..12e3117
--- /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 c5dfe6c..be12700 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -186,6 +186,7 @@
         "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 5befab9..18d9b5a 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -101,6 +101,7 @@
 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 @@
     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 0000000..1c9ab94
--- /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 75038c8..dd2a989 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 8867539b0..1bbbf8d 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 0000000..843dd67
--- /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 0000000..e54dea4
--- /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 0000000..0eff7d3
--- /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 0000000..326d901
--- /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 0000000..42f77b4
--- /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 add5e5f..0b4c01e 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.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.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 @@
             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 0000000..22fabb2
--- /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);
+        }
+    }
+}