/* * 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. */ #define LOG_TAG "ActivityRecognitionHAL" //#define LOG_NDEBUG 0 #include #include "activity.h" #include 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 }; ActivityContext::ActivityContext(const struct hw_module_t *module) : mHubConnection(HubConnection::getInstance()), mHubAlive(true), 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(module); device.common.close = CloseWrapper; device.register_activity_callback = RegisterActivityCallbackWrapper; device.enable_activity_event = EnableActivityEventWrapper; device.disable_activity_event = DisableActivityEventWrapper; device.flush = FlushWrapper; if (mHubConnection->initCheck() != (status_t)OK) { mHubAlive = false; } else { if (mHubConnection->getAliveCheck() != (status_t)OK) { mHubAlive = false; } else { mHubConnection->setActivityCallback( this, &ActivityContext::HubCallbackWrapper); mHubConnection->queueActivate(COMMS_SENSOR_ACTIVITY, false /* enable */); } } } ActivityContext::~ActivityContext() { mHubConnection->setActivityCallback(NULL, NULL); } int ActivityContext::close() { ALOGI("close"); delete this; return 0; } void ActivityContext::onActivityEvent( uint64_t when_us, bool is_flush, float x, float, float) { Mutex::Autolock autoLock(mLock); if (!mCallback) { return; } if (is_flush) { activity_event_t ev; memset(&ev, 0, sizeof(ev)); ev.event_type = ACTIVITY_EVENT_FLUSH_COMPLETE; ev.activity = 0; ev.timestamp = 0ll; (*mCallback->activity_callback)(mCallback, &ev, 1); return; } int activityRaw = (int)x; 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 = when_us * 1000ll; // timestamp is in ns. 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 = when_us * 1000ll; // timestamp is in ns. 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 = when_us * 1000ll; // timestamp is in ns. 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 = when_us * 1000ll; // timestamp is in ns. 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 = when_us * 1000ll; // timestamp is in ns. 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::registerActivityCallback( const activity_recognition_callback_procs_t *callback) { ALOGI("registerActivityCallback"); Mutex::Autolock autoLock(mLock); mCallback = callback; } int ActivityContext::enableActivityEvent( uint32_t activity_handle, uint32_t event_type, int64_t max_batch_report_latency_ns) { ALOGI("enableActivityEvent"); bool wasEnabled = !mMaxBatchReportLatencyNs.isEmpty(); int64_t prev_latency = calculateReportLatencyNs(); ALOGD_IF(DEBUG_ACTIVITY_RECOGNITION, "ACTVT type = %u, latency = %d sec", (unsigned) event_type, (int)(max_batch_report_latency_ns/1000000000ull)); 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, SENSOR_FLAG_ON_CHANGE_MODE, 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, SENSOR_FLAG_ON_CHANGE_MODE, 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] 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; } // static int ActivityContext::CloseWrapper(struct hw_device_t *dev) { return reinterpret_cast(dev)->close(); } // static void ActivityContext::RegisterActivityCallbackWrapper( const struct activity_recognition_device *dev, const activity_recognition_callback_procs_t *callback) { const_cast( reinterpret_cast(dev)) ->registerActivityCallback(callback); } // static int ActivityContext::EnableActivityEventWrapper( const struct activity_recognition_device *dev, uint32_t activity_handle, uint32_t event_type, int64_t max_batch_report_latency_ns) { return const_cast( reinterpret_cast(dev)) ->enableActivityEvent( activity_handle, event_type, max_batch_report_latency_ns); } // static int ActivityContext::DisableActivityEventWrapper( const struct activity_recognition_device *dev, uint32_t activity_handle, uint32_t event_type) { return const_cast( reinterpret_cast(dev)) ->disableActivityEvent(activity_handle, event_type); } // static int ActivityContext::FlushWrapper( const struct activity_recognition_device *dev) { return const_cast( reinterpret_cast(dev))->flush(); } // static void ActivityContext::HubCallbackWrapper( void *me, uint64_t time_ms, bool is_flush, float x, float y, float z) { static_cast(me)->onActivityEvent(time_ms, is_flush, x, y, z); } bool ActivityContext::getHubAlive() { return mHubAlive; } //////////////////////////////////////////////////////////////////////////////// static bool gHubAlive = false; static int open_activity( const struct hw_module_t *module, const char *, struct hw_device_t **dev) { ALOGI("open_activity"); ActivityContext *ctx = new ActivityContext(module); gHubAlive = ctx->getHubAlive(); *dev = &ctx->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 (gHubAlive) { *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, };