/* * 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. */ #include <inttypes.h> #define LOG_TAG "ActivityRecognitionHAL" #include <utils/Log.h> #include <media/stagefright/foundation/ADebug.h> #include "activity.h" using namespace android; static const int kVersionMajor = 1; static const int kVersionMinor = 0; static const int ACTIVITY_TYPE_TILTING_INDEX = 6; static const char *const kActivityList[] = { ACTIVITY_TYPE_IN_VEHICLE, ACTIVITY_TYPE_ON_BICYCLE, ACTIVITY_TYPE_WALKING, ACTIVITY_TYPE_RUNNING, ACTIVITY_TYPE_STILL, "com.google.android.contexthub.ar.inconsistent", ACTIVITY_TYPE_TILTING }; // The global ActivityContext singleton. static ActivityContext *gActivityContext = NULL; static int ActivityClose(struct hw_device_t *) { delete gActivityContext; gActivityContext = NULL; return 0; } static void RegisterActivityCallbackWrapper( const struct activity_recognition_device *, const activity_recognition_callback_procs_t *callback) { gActivityContext->registerActivityCallback(callback); } static int EnableActivityEventWrapper( const struct activity_recognition_device *, uint32_t activity_handle, uint32_t event_type, int64_t max_batch_report_latency_ns) { return gActivityContext->enableActivityEvent(activity_handle, event_type, max_batch_report_latency_ns); } static int DisableActivityEventWrapper( const struct activity_recognition_device *, uint32_t activity_handle, uint32_t event_type) { return gActivityContext->disableActivityEvent(activity_handle, event_type); } static int FlushWrapper(const struct activity_recognition_device *) { return gActivityContext->flush(); } ActivityContext::ActivityContext(const struct hw_module_t *module) : mHubConnection(HubConnection::getInstance()), mCallback(NULL), mPrevActivity(-1), mInitExitDone(false) { memset(&device, 0, sizeof(device)); device.common.tag = HARDWARE_DEVICE_TAG; device.common.version = ACTIVITY_RECOGNITION_API_VERSION_0_1; device.common.module = const_cast<hw_module_t *>(module); device.common.close = ActivityClose; device.register_activity_callback = RegisterActivityCallbackWrapper; device.enable_activity_event = EnableActivityEventWrapper; device.disable_activity_event = DisableActivityEventWrapper; device.flush = FlushWrapper; if (getHubAlive()) { mHubConnection->setActivityCallback(this); mHubConnection->queueActivate( COMMS_SENSOR_ACTIVITY, false /* enable */); } } ActivityContext::~ActivityContext() { mHubConnection->setActivityCallback(NULL); } void ActivityContext::OnActivityEvent(int activityRaw, uint64_t whenNs) { Mutex::Autolock autoLock(mCallbackLock); if (!mCallback) { return; } ALOGV("activityRaw = %d", activityRaw); if (mPrevActivity >= 0 && mPrevActivity == activityRaw) { // same old, same old... return; } activity_event_t ev[8]; memset(&ev, 0, 8*sizeof(activity_event_t)); int num_events = 0; // exit all other activities when first enabled. if (!mInitExitDone) { mInitExitDone = true; int numActivities = sizeof(kActivityList) / sizeof(kActivityList[0]); for (int i = 0; i < numActivities; ++i) { if ((i == activityRaw) || !isEnabled(i, ACTIVITY_EVENT_EXIT)) { continue; } activity_event_t *curr_ev = &ev[num_events]; curr_ev->event_type = ACTIVITY_EVENT_EXIT; curr_ev->activity = i; curr_ev->timestamp = whenNs; curr_ev->reserved[0] = curr_ev->reserved[1] = curr_ev->reserved[2] = curr_ev->reserved[3] = 0; num_events++; } } // tilt activities do not change the current activity type, but have a // simultaneous enter and exit event type if (activityRaw == ACTIVITY_TYPE_TILTING_INDEX) { if (isEnabled(activityRaw, ACTIVITY_EVENT_ENTER)) { activity_event_t *curr_ev = &ev[num_events]; curr_ev->event_type = ACTIVITY_EVENT_ENTER; curr_ev->activity = activityRaw; curr_ev->timestamp = whenNs; curr_ev->reserved[0] = curr_ev->reserved[1] = curr_ev->reserved[2] = curr_ev->reserved[3] = 0; num_events++; } if (isEnabled(activityRaw, ACTIVITY_EVENT_EXIT)) { activity_event_t *curr_ev = &ev[num_events]; curr_ev->event_type = ACTIVITY_EVENT_EXIT; curr_ev->activity = activityRaw; curr_ev->timestamp = whenNs; curr_ev->reserved[0] = curr_ev->reserved[1] = curr_ev->reserved[2] = curr_ev->reserved[3] = 0; num_events++; } } else { if ((mPrevActivity >= 0) && (isEnabled(mPrevActivity, ACTIVITY_EVENT_EXIT))) { activity_event_t *curr_ev = &ev[num_events]; curr_ev->event_type = ACTIVITY_EVENT_EXIT; curr_ev->activity = mPrevActivity; curr_ev->timestamp = whenNs; curr_ev->reserved[0] = curr_ev->reserved[1] = curr_ev->reserved[2] = curr_ev->reserved[3] = 0; num_events++; } if (isEnabled(activityRaw, ACTIVITY_EVENT_ENTER)) { activity_event_t *curr_ev = &ev[num_events]; curr_ev->event_type = ACTIVITY_EVENT_ENTER; curr_ev->activity = activityRaw; curr_ev->timestamp = whenNs; curr_ev->reserved[0] = curr_ev->reserved[1] = curr_ev->reserved[2] = curr_ev->reserved[3] = 0; num_events++; } mPrevActivity = activityRaw; } if (num_events > 0) { (*mCallback->activity_callback)(mCallback, ev, num_events); } } void ActivityContext::OnFlush() { Mutex::Autolock autoLock(mCallbackLock); if (!mCallback) { return; } activity_event_t ev = { .event_type = ACTIVITY_EVENT_FLUSH_COMPLETE, .activity = 0, .timestamp = 0ll, }; (*mCallback->activity_callback)(mCallback, &ev, 1); } void ActivityContext::registerActivityCallback( const activity_recognition_callback_procs_t *callback) { ALOGI("registerActivityCallback"); Mutex::Autolock autoLock(mCallbackLock); mCallback = callback; } int ActivityContext::enableActivityEvent( uint32_t activity_handle, uint32_t event_type, int64_t max_batch_report_latency_ns) { ALOGI("enableActivityEvent - activity_handle: %" PRIu32 ", event_type: %" PRIu32 ", latency: %" PRId64, activity_handle, event_type, max_batch_report_latency_ns); bool wasEnabled = !mMaxBatchReportLatencyNs.isEmpty(); int64_t prev_latency = calculateReportLatencyNs(); mMaxBatchReportLatencyNs.add( ((uint64_t)activity_handle << 32) | event_type, max_batch_report_latency_ns); if (!wasEnabled) { mPrevActivity = -1; mInitExitDone = false; mHubConnection->queueBatch(COMMS_SENSOR_ACTIVITY, 1000000, max_batch_report_latency_ns); mHubConnection->queueActivate(COMMS_SENSOR_ACTIVITY, true /* enable */); } else if (max_batch_report_latency_ns != prev_latency) { mHubConnection->queueBatch(COMMS_SENSOR_ACTIVITY, 1000000, max_batch_report_latency_ns); } return 0; } int64_t ActivityContext::calculateReportLatencyNs() { int64_t ret = INT64_MAX; for (size_t i = 0 ; i < mMaxBatchReportLatencyNs.size(); ++i) { if (mMaxBatchReportLatencyNs[i] <ret) { ret = mMaxBatchReportLatencyNs[i]; } } return ret; } int ActivityContext::disableActivityEvent( uint32_t activity_handle, uint32_t event_type) { ALOGI("disableActivityEvent"); bool wasEnabled = !mMaxBatchReportLatencyNs.isEmpty(); mMaxBatchReportLatencyNs.removeItem( ((uint64_t)activity_handle << 32) | event_type); bool isEnabled = !mMaxBatchReportLatencyNs.isEmpty(); if (wasEnabled && !isEnabled) { mHubConnection->queueActivate(COMMS_SENSOR_ACTIVITY, false /* enable */); } return 0; } bool ActivityContext::isEnabled( uint32_t activity_handle, uint32_t event_type) const { return mMaxBatchReportLatencyNs.indexOfKey( ((uint64_t)activity_handle << 32) | event_type) >= 0; } int ActivityContext::flush() { mHubConnection->queueFlush(COMMS_SENSOR_ACTIVITY); return 0; } bool ActivityContext::getHubAlive() { return mHubConnection->initCheck() == OK && mHubConnection->getAliveCheck() == OK; } //////////////////////////////////////////////////////////////////////////////// static int open_activity( const struct hw_module_t *module, const char *, struct hw_device_t **dev) { ALOGI("open_activity"); gActivityContext = new ActivityContext(module); *dev = &gActivityContext->device.common; return 0; } static struct hw_module_methods_t activity_module_methods = { .open = open_activity }; static int get_activity_list(struct activity_recognition_module *, char const* const **activity_list) { ALOGI("get_activity_list"); if (gActivityContext != NULL && gActivityContext->getHubAlive()) { *activity_list = kActivityList; return sizeof(kActivityList) / sizeof(kActivityList[0]); } else { *activity_list = {}; return 0; } } struct activity_recognition_module HAL_MODULE_INFO_SYM = { .common = { .tag = HARDWARE_MODULE_TAG, .version_major = kVersionMajor, .version_minor = kVersionMinor, .id = ACTIVITY_RECOGNITION_HARDWARE_MODULE_ID, .name = "Google Activity Recognition module", .author = "Google", .methods = &activity_module_methods, .dso = NULL, .reserved = {0}, }, .get_supported_activities_list = get_activity_list, };