diff --git a/DeviceSettings/res/values-de-rDE/strings.xml b/DeviceSettings/res/values-de-rDE/strings.xml index 4c722f7a..ca2aab91 100644 --- a/DeviceSettings/res/values-de-rDE/strings.xml +++ b/DeviceSettings/res/values-de-rDE/strings.xml @@ -91,4 +91,6 @@ Wert zwischen %1d und %2d Inaktivitätsdisplay Graustufen-Modus + Aktiviere Aufwecken mit Flip Cover + Schalte das Gerät AN und AUS mit einem magnetischen Flip Cover diff --git a/DeviceSettings/res/values-es-rES/strings.xml b/DeviceSettings/res/values-es-rES/strings.xml index 9c9d64fc..d7ca6084 100644 --- a/DeviceSettings/res/values-es-rES/strings.xml +++ b/DeviceSettings/res/values-es-rES/strings.xml @@ -107,6 +107,10 @@ Amoled Extremo Amoled caliente Mamba híbrido + + Despertar con funda flip + Activar levantamiento con funda flip + Despertar dispositivo con una funda flip magnética Valor por defecto diff --git a/DeviceSettings/res/values-in-rID/strings.xml b/DeviceSettings/res/values-in-rID/strings.xml index 11d8c1b9..bf980116 100644 --- a/DeviceSettings/res/values-in-rID/strings.xml +++ b/DeviceSettings/res/values-in-rID/strings.xml @@ -112,6 +112,9 @@ Amoled hangat Hibrid + Flip cover nyala + Aktifkan Flip Cover nyala + Nyalakan perangkat saat flip cover magnetik dibuka @string/presets_dialog_title Reset diff --git a/DeviceSettings/res/values-ja-rJP/strings.xml b/DeviceSettings/res/values-ja-rJP/strings.xml index 647ddeaa..558fb76f 100644 --- a/DeviceSettings/res/values-ja-rJP/strings.xml +++ b/DeviceSettings/res/values-ja-rJP/strings.xml @@ -106,6 +106,8 @@ 暖色 AMOLED Hybrid Mamba + + @string/presets_dialog_title リセット @@ -114,5 +116,9 @@ 新しい値を選択して下さい 既定値 値は %1$d と %2$d の間です - + + + フリップカバーの復帰 + フリップカバーの復帰の有効化 + マグネットフリップカバーでスリープ解除する diff --git a/DeviceSettings/res/values-pt-rBR/strings.xml b/DeviceSettings/res/values-pt-rBR/strings.xml index e4660ac9..f37fa314 100644 --- a/DeviceSettings/res/values-pt-rBR/strings.xml +++ b/DeviceSettings/res/values-pt-rBR/strings.xml @@ -114,6 +114,9 @@ Amoled Quente Mamba Híbrida + Flip Cover + Ativar a tela com Flip Cover + Ativa a tela ao usar uma Flip Cover magnética @string/presets_dialog_title Redefinir diff --git a/DeviceSettings/res/values-ru-rRU/strings.xml b/DeviceSettings/res/values-ru-rRU/strings.xml index 07170491..ade6c345 100644 --- a/DeviceSettings/res/values-ru-rRU/strings.xml +++ b/DeviceSettings/res/values-ru-rRU/strings.xml @@ -114,6 +114,9 @@ Теплый Amoled Гибридная Мамба + Пробуждение умным чехлом + Включить пробуждение откидной крышкой + Пробуждение устройства через магнитную откидную крышку @string/presets_dialog_title Сбросить diff --git a/DeviceSettings/res/values-sk-rSK/strings.xml b/DeviceSettings/res/values-sk-rSK/strings.xml index e1c95025..e7888eea 100644 --- a/DeviceSettings/res/values-sk-rSK/strings.xml +++ b/DeviceSettings/res/values-sk-rSK/strings.xml @@ -112,6 +112,9 @@ Teplý - Amoled Hybrid Mamba + Zobudenie preklopením krytu + Povoliť zobudenie preklopením krytu + Zobudenia zariadenia magnetickým krytom @string/presets_dialog_title Resetovať diff --git a/DeviceSettings/res/values/strings.xml b/DeviceSettings/res/values/strings.xml index 72c70195..ccc61816 100644 --- a/DeviceSettings/res/values/strings.xml +++ b/DeviceSettings/res/values/strings.xml @@ -69,6 +69,9 @@ Warm Amoled Hybrid Mamba + Flip Cover Wakeup + Enable Flip Cover Wakeup + Wakeup device via magnetic Flip Cover @string/presets_dialog_title Reset diff --git a/DeviceSettings/res/xml/preferences_xiaomi_parts.xml b/DeviceSettings/res/xml/preferences_xiaomi_parts.xml index e360cb4d..d748a815 100644 --- a/DeviceSettings/res/xml/preferences_xiaomi_parts.xml +++ b/DeviceSettings/res/xml/preferences_xiaomi_parts.xml @@ -15,7 +15,6 @@ --> - @@ -149,4 +148,15 @@ + + + + diff --git a/DeviceSettings/src/org/lineageos/settings/device/BootReceiver.java b/DeviceSettings/src/org/lineageos/settings/device/BootReceiver.java index dccf5754..5914c0d5 100644 --- a/DeviceSettings/src/org/lineageos/settings/device/BootReceiver.java +++ b/DeviceSettings/src/org/lineageos/settings/device/BootReceiver.java @@ -77,6 +77,10 @@ public class BootReceiver extends BroadcastReceiver implements Utils { // Vibration Strength FileUtils.setValue(DeviceSettings.VIBRATION_STRENGTH_PATH, Settings.Secure.getInt( context.getContentResolver(), DeviceSettings.PREF_VIBRATION_STRENGTH, 80) / 100.0 * (DeviceSettings.MAX_VIBRATION - DeviceSettings.MIN_VIBRATION) + DeviceSettings.MIN_VIBRATION); + FileUtils.setValue(DeviceSettings.HALL_WAKEUP_PATH, Settings.Secure.getInt( + context.getContentResolver(), DeviceSettings.PREF_HALL_WAKEUP, 1) == 1 ? "Y" : "N"); + FileUtils.setProp(DeviceSettings.HALL_WAKEUP_PROP, Settings.Secure.getInt( + context.getContentResolver(), DeviceSettings.PREF_HALL_WAKEUP, 1) == 1); // Dirac context.startService(new Intent(context, DiracService.class)); diff --git a/DeviceSettings/src/org/lineageos/settings/device/DeviceSettings.java b/DeviceSettings/src/org/lineageos/settings/device/DeviceSettings.java index e3c83290..e996d196 100644 --- a/DeviceSettings/src/org/lineageos/settings/device/DeviceSettings.java +++ b/DeviceSettings/src/org/lineageos/settings/device/DeviceSettings.java @@ -69,6 +69,11 @@ public class DeviceSettings extends PreferenceFragment implements private static final String PREF_DEVICE_DOZE = "device_doze"; private static final String PREF_DEVICE_KCAL = "device_kcal"; + private static final String CATEGORY_HALL_WAKEUP = "hall_wakeup"; + public static final String PREF_HALL_WAKEUP = "hall"; + public static final String HALL_WAKEUP_PATH = "/sys/module/hall/parameters/hall_toggle"; + public static final String HALL_WAKEUP_PROP = "persist.service.folio_daemon"; + private static final String DEVICE_DOZE_PACKAGE_NAME = "com.advanced.settings.doze"; private static final String DEVICE_JASON_PACKAGE_NAME = "org.lineageos.settings.devicex"; @@ -166,6 +171,13 @@ public class DeviceSettings extends PreferenceFragment implements mPreset = (SecureSettingListPreference) findPreference(PREF_PRESET); mPreset.setOnPreferenceChangeListener(this); + if (FileUtils.fileWritable(HALL_WAKEUP_PATH)) { + SecureSettingSwitchPreference hall = (SecureSettingSwitchPreference) findPreference(PREF_HALL_WAKEUP); + hall.setChecked(FileUtils.getValue(HALL_WAKEUP_PATH).equals("Y")); + hall.setOnPreferenceChangeListener(this); + } else { + getPreferenceScreen().removePreference(findPreference(CATEGORY_HALL_WAKEUP)); + } } @Override @@ -220,6 +232,11 @@ public class DeviceSettings extends PreferenceFragment implements } break; + case PREF_HALL_WAKEUP: + FileUtils.setValue(HALL_WAKEUP_PATH, (boolean) value ? "Y" : "N"); + FileUtils.setProp(HALL_WAKEUP_PROP, (boolean) value); + break; + case PREF_KEY_FPS_INFO: boolean enabled = (boolean) value; Intent fpsinfo = new Intent(this.getContext(), FPSInfoService.class); diff --git a/folio_daemon/Android.bp b/folio_daemon/Android.bp new file mode 100755 index 00000000..c609cfb1 --- /dev/null +++ b/folio_daemon/Android.bp @@ -0,0 +1,21 @@ +cc_binary { + name: "folio_daemon", + + shared_libs: [ + "libandroid", + "libcutils", + "liblog", + ], + + srcs: ["main.cpp"], + + cflags: [ + "-DLOG_TAG=\"folio_daemon\"", + "-DLOG_NDEBUG=0", + "-Wall", + "-Werror", + ], + + owner: "google", + +} diff --git a/folio_daemon/main.cpp b/folio_daemon/main.cpp new file mode 100644 index 00000000..1cda1ce5 --- /dev/null +++ b/folio_daemon/main.cpp @@ -0,0 +1,182 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Hall-effect sensor type +#define SENSOR_TYPE 33171016 + +#define RETRY_LIMIT 120 +#define RETRY_PERIOD 30 // 30 seconds +#define WARN_PERIOD (time_t)300 // 5 minutes + +/* + * 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; + time_t lastWarn = 0; + int attemptCount = 0; + + 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); + /* + * As long as we are unable to get the sensor handle, periodically retry + * and emit an error message at a low frequency to prevent high CPU usage + * and log spam. If we simply exited with an error here, we would be + * immediately restarted and fail in the same way indefinitely. + */ + while (true) { + time_t now = time(NULL); + hallSensor = ASensorManager_getDefaultSensor(sensorManager, + SENSOR_TYPE); + if (hallSensor != nullptr) { + break; + } + + if (++attemptCount >= RETRY_LIMIT) { + ALOGE("Retries exhausted; exiting"); + goto out; + } else if (now > lastWarn + WARN_PERIOD) { + ALOGE("Unable to get Hall-effect sensor"); + lastWarn = now; + } + + sleep(RETRY_PERIOD); + } + + 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) { + int eventCount = 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"); + eventCount++; + } + + if (eventCount == 0) { + ALOGE("Poll returned with zero events: %s", strerror(errno)); + break; + } + } + +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; +} diff --git a/rootdir/etc/init.target.rc b/rootdir/etc/init.target.rc index 8ee4d26d..12d64d25 100755 --- a/rootdir/etc/init.target.rc +++ b/rootdir/etc/init.target.rc @@ -465,6 +465,18 @@ service dcvs-sh /vendor/bin/init.qti.dcvs.sh on property:vendor.dcvs.prop=1 start dcvs-sh +service folio_daemon /system/bin/folio_daemon + class late_start + user system + group system uhid + disabled + +on property:persist.service.folio_daemon=0 + stop folio_daemon + +on property:persist.service.folio_daemon=1 + start folio_daemon + service ppd /system/vendor/bin/mm-pp-dpps class late_start user system diff --git a/rootdir/etc/init.xiaomi_parts.rc b/rootdir/etc/init.xiaomi_parts.rc index cfb4fa64..47b32c05 100644 --- a/rootdir/etc/init.xiaomi_parts.rc +++ b/rootdir/etc/init.xiaomi_parts.rc @@ -15,9 +15,11 @@ # on boot - # Haptic strength + # XiaomiParts chown system system /sys/devices/virtual/timed_output/vibrator/vtg_level chmod 0660 /sys/devices/virtual/timed_output/vibrator/vtg_level + chown system system /sys/module/hall/parameters/hall_toggle + chmod 0660 /sys/module/hall/parameters/hall_toggle # FPS chown system system /sys/devices/virtual/graphics/fb0/measured_fps diff --git a/sdm660.mk b/sdm660.mk index 2b6e4198..20d1caf7 100644 --- a/sdm660.mk +++ b/sdm660.mk @@ -203,6 +203,10 @@ PRODUCT_PACKAGES += \ android.hardware.drm@1.4-service.clearkey \ android.hardware.drm@1.4.vendor +# Folio +PRODUCT_PACKAGES += \ + folio_daemon + # Freeform Multiwindow PRODUCT_COPY_FILES += \ frameworks/native/data/etc/android.software.freeform_window_management.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.software.freeform_window_management.xml diff --git a/sepolicy/private/file_contexts b/sepolicy/private/file_contexts index e59ed67c..3bc206b5 100644 --- a/sepolicy/private/file_contexts +++ b/sepolicy/private/file_contexts @@ -1,3 +1,3 @@ # Executables /system/bin/chargeonlymode u:object_r:charger_exec:s0 - +/system/bin/folio_daemon u:object_r:folio_daemon_exec:s0 diff --git a/sepolicy/private/folio_daemon.te b/sepolicy/private/folio_daemon.te new file mode 100644 index 00000000..f48a3b2f --- /dev/null +++ b/sepolicy/private/folio_daemon.te @@ -0,0 +1,15 @@ +type folio_daemon, domain, coredomain; +type folio_daemon_exec, system_file_type, exec_type, file_type; + +init_daemon_domain(folio_daemon) + +allow folio_daemon binder_device:chr_file rw_file_perms; +allow folio_daemon uhid_device:chr_file rw_file_perms; + +allow folio_daemon system_server:unix_stream_socket rw_socket_perms_no_ioctl; + +binder_use(folio_daemon) +binder_call(folio_daemon, system_server) + +allow folio_daemon sensorservice_service:service_manager find; +allow folio_daemon permission_service:service_manager find; diff --git a/sepolicy/private/system_server.te b/sepolicy/private/system_server.te index 1e735c29..d8bf45a4 100644 --- a/sepolicy/private/system_server.te +++ b/sepolicy/private/system_server.te @@ -1,3 +1,4 @@ +binder_call(system_server, folio_daemon) # Allow system_server to set persist_camera_prop get_prop(system_server, vendor_persist_camera_prop) diff --git a/sepolicy/vendor/file.te b/sepolicy/vendor/file.te index 6dc994f1..25f44f84 100644 --- a/sepolicy/vendor/file.te +++ b/sepolicy/vendor/file.te @@ -14,6 +14,9 @@ type sysfs_earpiecegain, sysfs_type, fs_type; # HVDCP type vendor_sysfs_hvdcp, fs_type, sysfs_type; +# Hall Switch +type hall_dev, sysfs_type, fs_type; + # Kcal type kcal_dev, sysfs_type, fs_type; diff --git a/sepolicy/vendor/file_contexts b/sepolicy/vendor/file_contexts index 188ec11d..06b4caa5 100644 --- a/sepolicy/vendor/file_contexts +++ b/sepolicy/vendor/file_contexts @@ -29,6 +29,9 @@ /bt_firmware(/.*)? u:object_r:bt_firmware_file:s0 /persist(/.*)? u:object_r:persist_file:s0 +# Hall Switch +/sys/module/hall/parameters(/.*)? u:object_r:hall_dev:s0 + # Hexagon DSP-side executable needed for Halide operation # This is labeled as public_adsprpcd_file as it needs to be read by apps # (e.g. Google Camera App) diff --git a/sepolicy/vendor/property_contexts b/sepolicy/vendor/property_contexts index af6b9436..419a336e 100644 --- a/sepolicy/vendor/property_contexts +++ b/sepolicy/vendor/property_contexts @@ -40,6 +40,9 @@ ro.boot.fp. u:object_r:hal_fingerprint_prop:s0 ro.boot.fpsensor u:object_r:hal_fingerprint_prop:s0 sys.fp. u:object_r:hal_fingerprint_prop:s0 +# Hall wakeup +persist.service.folio_daemon u:object_r:system_prop:s0 + # Media gpu.stats.debug.level u:object_r:vendor_default_prop:s0 diff --git a/sepolicy/vendor/system_app.te b/sepolicy/vendor/system_app.te index 71516fcc..bede6c45 100644 --- a/sepolicy/vendor/system_app.te +++ b/sepolicy/vendor/system_app.te @@ -1,4 +1,6 @@ allow system_app blkio_dev:dir search; +allow system_app hall_dev:file rw_file_perms; +allow system_app hall_dev:dir search; allow system_app kcal_dev:dir search; allow system_app kcal_dev:file rw_file_perms; allow system_app proc_vmallocinfo:file read; diff --git a/sepolicy/vendor/ueventd.te b/sepolicy/vendor/ueventd.te index 985c8ec4..9d1e2181 100644 --- a/sepolicy/vendor/ueventd.te +++ b/sepolicy/vendor/ueventd.te @@ -1 +1,4 @@ +allow ueventd hall_dev:dir r_dir_perms; +allow ueventd hall_dev:file rw_file_perms; +allow ueventd hall_dev:lnk_file r_file_perms; allow ueventd metadata_file:dir search;