Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a4fa3b5a authored by destradaa's avatar destradaa
Browse files

Add support in the platform for Activity Recognition Hardware.

Change-Id: I7c4fff3526583475a5edf1f4ba8fede4e9419ead
parent dfd6b4e9
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -156,6 +156,9 @@ LOCAL_SRC_FILES += \
	core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl \
	core/java/android/hardware/input/IInputManager.aidl \
	core/java/android/hardware/input/IInputDevicesChangedListener.aidl \
	core/java/android/hardware/location/IActivityRecognitionHardware.aidl \
	core/java/android/hardware/location/IActivityRecognitionHardwareSink.aidl \
	core/java/android/hardware/location/IActivityRecognitionHardwareWatcher.aidl \
	core/java/android/hardware/location/IFusedLocationHardware.aidl \
	core/java/android/hardware/location/IFusedLocationHardwareSink.aidl \
	core/java/android/hardware/location/IGeofenceHardware.aidl \
+19 −0
Original line number Diff line number Diff line
/*
 * 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
+79 −0
Original line number Diff line number Diff line
/*
 * 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);
    }
}
+78 −0
Original line number Diff line number Diff line
/*
 * 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);
    }
}
+224 −0
Original line number Diff line number Diff line
/*
 * 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 = "ActivityRecognitionHardware";

    private static final String HARDWARE_PERMISSION = Manifest.permission.LOCATION_HARDWARE;
    private static final int INVALID_ACTIVITY_TYPE = -1;
    private static final int NATIVE_SUCCESS_RESULT = 0;

    private static ActivityRecognitionHardware sSingletonInstance = null;
    private static final Object sSingletonInstanceLock = new Object();

    private final Context mContext;
    private final String[] mSupportedActivities;

    private final RemoteCallbackList<IActivityRecognitionHardwareSink> mSinks =
            new RemoteCallbackList<IActivityRecognitionHardwareSink>();

    private static class Event {
        public int activity;
        public int type;
        public long timestamp;
    }

    private ActivityRecognitionHardware(Context context) {
        nativeInitialize();

        mContext = context;
        mSupportedActivities = fetchSupportedActivities();
    }

    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);
        return result == NATIVE_SUCCESS_RESULT;
    }

    @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);
        return result == NATIVE_SUCCESS_RESULT;
    }

    @Override
    public boolean flush() {
        checkPermissions();
        int result = nativeFlush();
        return result == NATIVE_SUCCESS_RESULT;
    }

    /**
     * Called by the Activity-Recognition HAL.
     */
    private void onActivityChanged(Event[] events) {
        int size = mSinks.beginBroadcast();
        if (size == 0 || events == null || events.length == 0) {
            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);

        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 supporteActivitiesLength = mSupportedActivities.length;
        for (int i = 0; i < supporteActivitiesLength; ++i) {
            if (activity.equals(mSupportedActivities[i])) {
                return i;
            }
        }

        return INVALID_ACTIVITY_TYPE;
    }

    private void checkPermissions() {
        String message = String.format(
                "Permission '%s' not granted to access ActivityRecognitionHardware",
                HARDWARE_PERMISSION);
        mContext.enforceCallingPermission(HARDWARE_PERMISSION, message);
    }

    private static String[] fetchSupportedActivities() {
        String[] supportedActivities = nativeGetSupportedActivities();
        if (supportedActivities != null) {
            return supportedActivities;
        }

        return new String[0];
    }

    // native bindings
    static { nativeClassInit(); }

    private static native void nativeClassInit();
    private static native void nativeInitialize();
    private static native void nativeRelease();
    private static native boolean nativeIsSupported();
    private static native String[] nativeGetSupportedActivities();
    private static native int nativeEnableActivityEvent(
            int activityType,
            int eventType,
            long reportLatenceNs);
    private static native int nativeDisableActivityEvent(int activityType, int eventType);
    private static native int nativeFlush();
}
Loading