Add support for folio cases

Bug: 35243564
Test: Used magnet to wake and lock device. Also tested during suspend.
Change-Id: I4b819e12cc23a3d7a8ce048e208c15eac4f8d6c5
This commit is contained in:
Andrew Lehmer
2017-03-29 10:17:06 -07:00
parent 1e723fbe13
commit 99cbc8d596
6 changed files with 187 additions and 0 deletions

View File

@@ -453,3 +453,7 @@ endif
# Dumpstate HAL
PRODUCT_PACKAGES += \
android.hardware.dumpstate@1.0-service.wahoo
# Use daemon to detect folio open/close
PRODUCT_PACKAGES += \
folio_daemon

22
folio_daemon/Android.mk Executable file
View File

@@ -0,0 +1,22 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SHARED_LIBRARIES := \
libandroid \
libcutils \
liblog
LOCAL_SRC_FILES := \
main.cpp
LOCAL_C_INCLUDES :=
LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"folio_daemon\" -DLOG_NDEBUG=0
LOCAL_CLANG := true
LOCAL_MODULE := folio_daemon
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_OWNER := google
LOCAL_PROPRIETARY_MODULE := true
include $(BUILD_EXECUTABLE)

147
folio_daemon/main.cpp Normal file
View File

@@ -0,0 +1,147 @@
/*
* Copyright 2017 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 <fcntl.h>
#include <unistd.h>
#include <linux/input.h>
#include <linux/uinput.h>
#include <android/looper.h>
#include <android/sensor.h>
#include <cutils/log.h>
// Hall-effect sensor type
#define SENSOR_TYPE 33171016
/*
* This simple daemon listens for events from the Hall-effect sensor and writes
* the appropriate SW_LID event to a uinput node. This allows the screen to be
* locked with a magnetic folio case.
*/
int main(void) {
int uinputFd;
int err;
struct uinput_user_dev uidev;
ASensorManager *sensorManager = nullptr;
ASensorRef hallSensor;
ALooper *looper;
ASensorEventQueue *eventQueue = nullptr;
ALOGI("Started");
uinputFd = TEMP_FAILURE_RETRY(open("/dev/uinput", O_WRONLY | O_NONBLOCK));
if (uinputFd < 0) {
ALOGE("Unable to open uinput node: %s", strerror(errno));
goto out;
}
err = TEMP_FAILURE_RETRY(ioctl(uinputFd, UI_SET_EVBIT, EV_SW))
| TEMP_FAILURE_RETRY(ioctl(uinputFd, UI_SET_EVBIT, EV_SYN))
| TEMP_FAILURE_RETRY(ioctl(uinputFd, UI_SET_SWBIT, SW_LID));
if (err != 0) {
ALOGE("Unable to enable SW_LID events: %s", strerror(errno));
goto out;
}
memset(&uidev, 0, sizeof (uidev));
snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput-folio");
uidev.id.bustype = BUS_VIRTUAL;
uidev.id.vendor = 0;
uidev.id.product = 0;
uidev.id.version = 0;
err = TEMP_FAILURE_RETRY(write(uinputFd, &uidev, sizeof (uidev)));
if (err < 0) {
ALOGE("Write user device to uinput node failed: %s", strerror(errno));
goto out;
}
err = TEMP_FAILURE_RETRY(ioctl(uinputFd, UI_DEV_CREATE));
if (err < 0) {
ALOGE("Unable to create uinput device: %s", strerror(errno));
goto out;
}
ALOGI("Successfully registered uinput-folio for SW_LID events");
// Get Hall-effect sensor events from the NDK
sensorManager = ASensorManager_getInstanceForPackage(nullptr);
hallSensor = ASensorManager_getDefaultSensor(sensorManager, SENSOR_TYPE);
if (hallSensor == nullptr) {
ALOGE("Unable to get Hall-effect sensor");
goto out;
}
looper = ALooper_forThread();
if (looper == nullptr) {
looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
}
eventQueue = ASensorManager_createEventQueue(sensorManager, looper, 0, NULL,
NULL);
err = ASensorEventQueue_registerSensor(eventQueue, hallSensor,
ASensor_getMinDelay(hallSensor),
10000);
if (err < 0) {
ALOGE("Unable to register for Hall-effect sensor events");
goto out;
}
ALOGI("Starting polling loop");
// Polling loop
while (ALooper_pollAll(-1, NULL, NULL, NULL) == 0) {
ASensorEvent sensorEvent;
while (ASensorEventQueue_getEvents(eventQueue, &sensorEvent, 1) > 0) {
// 1 means closed; 0 means open
int isClosed = sensorEvent.data[0] > 0.0f ? 1 : 0;
struct input_event event;
event.type = EV_SW;
event.code = SW_LID;
event.value = isClosed;
err = TEMP_FAILURE_RETRY(write(uinputFd, &event, sizeof (event)));
if (err < 0) {
ALOGE("Write EV_SW to uinput node failed: %s", strerror(errno));
goto out;
}
// Force a flush with an EV_SYN
event.type = EV_SYN;
event.code = SYN_REPORT;
event.value = 0;
err = TEMP_FAILURE_RETRY(write(uinputFd, &event, sizeof (event)));
if (err < 0) {
ALOGE("Write EV_SYN to uinput node failed: %s",
strerror(errno));
goto out;
}
ALOGI("Sent lid %s event", isClosed ? "closed" : "open");
}
}
out:
// Clean up
if (sensorManager != nullptr && eventQueue != nullptr) {
ASensorManager_destroyEventQueue(sensorManager, eventQueue);
}
if (uinputFd >= 0) {
close(uinputFd);
}
// The loop can only be exited via failure or signal
return 1;
}

View File

@@ -256,6 +256,11 @@ service init-radio-sh /system/bin/init.radio.sh
group root radio
oneshot
service folio_daemon /vendor/bin/folio_daemon
class late_start
user root
group root
service perfd /vendor/bin/perfd
class main
user root

View File

@@ -130,6 +130,7 @@
/vendor/bin/cnd u:object_r:cnd_exec:s0
/vendor/bin/hw/android\.hardware\.usb@1\.0-service.device u:object_r:hal_usb_default_exec:s0
/vendor/bin/chre u:object_r:chre_exec:s0
/vendor/bin/folio_daemon u:object_r:folio_daemon_exec:s0
# data files
/data/misc/radio(/.*)? u:object_r:radio_data_file:s0

8
sepolicy/folio_daemon.te Normal file
View File

@@ -0,0 +1,8 @@
type folio_daemon, domain;
type folio_daemon_exec, exec_type, file_type;
init_daemon_domain(folio_daemon)
userdebug_or_eng(`
permissive folio_daemon;
')