From 8d704d30828f087fc03b21d08a30395d00c4c205 Mon Sep 17 00:00:00 2001 From: CuriousNom Date: Tue, 12 Aug 2025 12:00:00 +0000 Subject: [PATCH] pipa: peripheralmanager: Revert many keyboard/pen changes * will be reimplemented later. --- peripheralmanager/Android.bp | 8 +- peripheralmanager/AndroidManifest.xml | 28 +- peripheralmanager/res/values/strings.xml | 12 - .../res/xml/keyboard_settings.xml | 27 - peripheralmanager/res/xml/lid_settings.xml | 27 - .../BootCompletedReceiver.java | 47 +- .../KeyboardSettingsActivity.java | 33 - .../KeyboardSettingsFragment.java | 125 -- .../KeyboardUtils.java | 327 +---- .../LidSettingsActivity.java | 33 - .../LidSettingsFragment.java | 107 -- .../xiaomiperipheralmanager/PenUtils.java | 166 +-- .../xiaomiperipheralmanager/RefreshUtils.java | 55 + .../StylusSettingsActivity.java | 24 +- .../StylusSettingsFragment.java | 105 +- peripheralmanager/xiaomi-keyboard.cpp | 1076 +++++------------ peripheralmanager/xiaomi-pen.cpp | 40 +- rootdir/etc/init.device.rc | 4 - sepolicy/vendor/file.te | 1 - sepolicy/vendor/file_contexts | 2 - sepolicy/vendor/servicemanager.te | 1 - sepolicy/vendor/system_app.te | 1 - sepolicy/vendor/xiaomi_keyboard.te | 16 +- 23 files changed, 451 insertions(+), 1814 deletions(-) delete mode 100644 peripheralmanager/res/xml/keyboard_settings.xml delete mode 100644 peripheralmanager/res/xml/lid_settings.xml delete mode 100644 peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/KeyboardSettingsActivity.java delete mode 100644 peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/KeyboardSettingsFragment.java delete mode 100644 peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/LidSettingsActivity.java delete mode 100644 peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/LidSettingsFragment.java create mode 100644 peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/RefreshUtils.java delete mode 100644 sepolicy/vendor/file.te delete mode 100644 sepolicy/vendor/servicemanager.te diff --git a/peripheralmanager/Android.bp b/peripheralmanager/Android.bp index a6cdae5..a7bc965 100644 --- a/peripheralmanager/Android.bp +++ b/peripheralmanager/Android.bp @@ -1,5 +1,5 @@ // -// Copyright (C) 2023-2025 The LineageOS Project +// Copyright (C) 2023 The LineageOS Project // // SPDX-License-Identifier: Apache-2.0 // @@ -46,10 +46,4 @@ cc_binary { "liblog", "libsensorndkbridge", ], - - arch: { - arm: { - cflags: ["-mfpu=neon", "-mfloat-abi=softfp"], - }, - }, } diff --git a/peripheralmanager/AndroidManifest.xml b/peripheralmanager/AndroidManifest.xml index e3d4b46..e179d0d 100644 --- a/peripheralmanager/AndroidManifest.xml +++ b/peripheralmanager/AndroidManifest.xml @@ -1,6 +1,6 @@ @@ -43,31 +43,5 @@ android:resource="@string/stylus_summary" /> - - - - - - - - - - - - - - - - diff --git a/peripheralmanager/res/values/strings.xml b/peripheralmanager/res/values/strings.xml index f33b546..eb26843 100644 --- a/peripheralmanager/res/values/strings.xml +++ b/peripheralmanager/res/values/strings.xml @@ -14,16 +14,4 @@ Force recognize stylus Enable this settings to allow using third party styluses - - Keyboard - Keyboard Settings - Toggle angle detection - This toggles the angle detection of the keyboard - - - Smart Cover - Smart Cover Settings - Toggle Smart Cover behaivor - This toggles the behaivor of the smart lid - diff --git a/peripheralmanager/res/xml/keyboard_settings.xml b/peripheralmanager/res/xml/keyboard_settings.xml deleted file mode 100644 index 7d38714..0000000 --- a/peripheralmanager/res/xml/keyboard_settings.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - diff --git a/peripheralmanager/res/xml/lid_settings.xml b/peripheralmanager/res/xml/lid_settings.xml deleted file mode 100644 index e70316b..0000000 --- a/peripheralmanager/res/xml/lid_settings.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - diff --git a/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/BootCompletedReceiver.java b/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/BootCompletedReceiver.java index 5fe1159..94f4831 100644 --- a/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/BootCompletedReceiver.java +++ b/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/BootCompletedReceiver.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023-2025 The LineageOS Project + * Copyright (C) 2023 The LineageOS Project * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,57 +9,20 @@ package org.lineageos.xiaomiperipheralmanager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.os.SystemProperties; import android.util.Log; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; - -/** - * BroadcastReceiver that initializes peripheral managers on boot - */ public class BootCompletedReceiver extends BroadcastReceiver { private static final String TAG = "XiaomiPeripheralManager"; - private static final boolean DEBUG = SystemProperties.getBoolean("persist.xiaomi.peripherals.debug", false); + private static final boolean DEBUG = false; @Override public void onReceive(final Context context, Intent intent) { if (!intent.getAction().equals(Intent.ACTION_LOCKED_BOOT_COMPLETED)) { return; } - - logInfo("Device boot completed, initializing peripheral services"); - - try { - KeyboardUtils.setup(context); - logInfo("Keyboard service initialized"); - } catch (Exception e) { - logError("Failed to initialize keyboard service: " + e.getMessage()); - } - - try { - PenUtils.setup(context); - logInfo("Pen service initialized"); - } catch (Exception e) { - logError("Failed to initialize pen service: " + e.getMessage()); - } - } - - private void logDebug(String message) { - if (DEBUG) Log.d(TAG, getTimestamp() + message); - } - - private void logInfo(String message) { - Log.i(TAG, getTimestamp() + message); - } - - private void logError(String message) { - Log.e(TAG, getTimestamp() + message); - } - - private String getTimestamp() { - return "[" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US).format(new Date()) + "] "; + if (DEBUG) Log.d(TAG, "Received boot completed intent"); + KeyboardUtils.setup(context); + PenUtils.setup(context); } } diff --git a/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/KeyboardSettingsActivity.java b/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/KeyboardSettingsActivity.java deleted file mode 100644 index 049ec68..0000000 --- a/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/KeyboardSettingsActivity.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2023-2025 The LineageOS Project - * - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.lineageos.xiaomiperipheralmanager; - -import android.os.Bundle; -import android.util.Log; - -import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity; - -/** - * Settings activity for stylus/pen configuration - * Hosts the StylusSettingsFragment for user configuration - */ -public class KeyboardSettingsActivity extends CollapsingToolbarBaseActivity { - - private static final String TAG = "XiaomiKeyboardSettings"; - private static final String TAG_KEYBOARD = "keyboard"; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - Log.i(TAG, "Opening keyboard settings"); - - getFragmentManager().beginTransaction().replace( - com.android.settingslib.collapsingtoolbar.R.id.content_frame, - new KeyboardSettingsFragment(), TAG_KEYBOARD).commit(); - } -} diff --git a/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/KeyboardSettingsFragment.java b/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/KeyboardSettingsFragment.java deleted file mode 100644 index a7e256a..0000000 --- a/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/KeyboardSettingsFragment.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2023-2025 The LineageOS Project - * - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.lineageos.xiaomiperipheralmanager; - -import android.content.Context; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.util.Log; - -import android.preference.PreferenceManager; -import androidx.preference.PreferenceFragment; -import androidx.preference.SwitchPreference; - -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; - -import android.content.ComponentName; -import android.content.Intent; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; - -public class KeyboardSettingsFragment extends PreferenceFragment implements - SharedPreferences.OnSharedPreferenceChangeListener { - - private static final String TAG = "XiaomiKeyboardSettings"; - private static final String KEYBOARD_KEY = "keyboard_switch_key"; - private static final boolean DEBUG = true; - private static final String CONF_LOCATION = "/data/misc/xiaomi_keyboard.conf"; - - private SharedPreferences mKeyboardPreference; - - private void saveAngleDetectionPreference(boolean enabled) { - try { - File file = new File(CONF_LOCATION); - FileOutputStream fos = new FileOutputStream(file); - fos.write((enabled ? "1" : "0").getBytes()); - fos.close(); - logInfo("Angle detection preference saved: " + enabled); - } catch (IOException e) { - logError("Failed to save angle detection preference: " + e.getMessage()); - } -} - - @Override - public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { - try { - addPreferencesFromResource(R.xml.keyboard_settings); - - mKeyboardPreference = PreferenceManager.getDefaultSharedPreferences(getContext()); - SwitchPreference switchPreference = (SwitchPreference) findPreference(KEYBOARD_KEY); - - if (switchPreference != null) { - switchPreference.setChecked(mKeyboardPreference.getBoolean(KEYBOARD_KEY, false)); - switchPreference.setEnabled(true); - } else { - logError("Could not find keyboard switch preference"); - } - - logInfo("Keyboard settings fragment created"); - } catch (Exception e) { - logError("Error creating keyboard settings: " + e.getMessage()); - } - } - - @Override - public void onResume() { - super.onResume(); - try { - mKeyboardPreference.registerOnSharedPreferenceChangeListener(this); - logDebug("Registered preference change listener"); - - } catch (Exception e) { - logError("Error in onResume: " + e.getMessage()); - } - } - - @Override - public void onPause() { - super.onPause(); - try { - mKeyboardPreference.unregisterOnSharedPreferenceChangeListener(this); - logDebug("Unregistered preference change listener"); - - } catch (Exception e) { - logError("Error in onPause: " + e.getMessage()); - } - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreference, String key) { - if (KEYBOARD_KEY.equals(key)) { - try { - boolean newStatus = mKeyboardPreference.getBoolean(key, false); - saveAngleDetectionPreference(newStatus); - logInfo("Keyboard status changed: " + newStatus); - } catch (Exception e) { - logError("Error handling preference change: " + e.getMessage()); - } - } - } - - // Enhanced logging helpers to match other classes - private void logDebug(String message) { - if (DEBUG) Log.d(TAG, getTimestamp() + message); - } - - private void logInfo(String message) { - Log.i(TAG, getTimestamp() + message); - } - - private void logError(String message) { - Log.e(TAG, getTimestamp() + message); - } - - private String getTimestamp() { - return "[" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US).format(new Date()) + "] "; - } -} \ No newline at end of file diff --git a/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/KeyboardUtils.java b/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/KeyboardUtils.java index a326cee..8209db5 100644 --- a/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/KeyboardUtils.java +++ b/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/KeyboardUtils.java @@ -1,338 +1,51 @@ /* - * Copyright (C) 2023-2025 The LineageOS Project + * Copyright (C) 2023 The LineageOS Project * * SPDX-License-Identifier: Apache-2.0 */ package org.lineageos.xiaomiperipheralmanager; -import android.content.BroadcastReceiver; import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; import android.hardware.input.InputManager; -import android.os.FileUtils; -import android.os.SystemProperties; import android.util.Log; import android.view.InputDevice; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; - -/** - * Utility class for handling Xiaomi keyboard operations at the framework level. - * Works in conjunction with the native xiaomi-keyboard service. - */ public class KeyboardUtils { - private static final String TAG = "XiaomiKeyboard"; - private static boolean DEBUG = SystemProperties.getBoolean("persist.xiaomi.keyboard.debug", false); + private static final String TAG = "XiaomiPeripheralManagerKeyboardUtils"; + private static final boolean DEBUG = false; - // Xiaomi keyboard identifiers - private static final int KEYBOARD_VENDOR_ID = 5593; - private static final int KEYBOARD_PRODUCT_ID = 163; - - // Communication with native service - private static final String NANODEV_PATH = "/dev/nanodev0"; - private static final byte MSG_TYPE_LOCK = 41; - private static final byte MSG_TYPE_UNLOCK = 42; - private static final byte MSG_HEADER_1 = 0x31; - private static final byte MSG_HEADER_2 = 0x38; + private static final int kbVendorId = 5593; + private static final int kbProductId = 163; private static InputManager mInputManager; - private static boolean mLastEnabledState = false; - private static boolean mIsDeviceLocked = false; - private static Context mContext = null; - private static ScreenStateReceiver mScreenStateReceiver = null; - // Add watchdog monitor and recovery - private static final long WATCHDOG_TIMEOUT_MS = 10000; // 10 seconds - private static Thread mWatchdogThread = null; - private static volatile boolean mWatchdogRunning = false; - private static volatile long mLastWatchdogCheck = 0; - - /** - * Initialize the keyboard utilities and set initial state - * @param context Application context - */ public static void setup(Context context) { - logInfo("Initializing Xiaomi keyboard framework integration"); - mContext = context.getApplicationContext(); - - try { - if (mInputManager == null) { - mInputManager = (InputManager) context.getSystemService(Context.INPUT_SERVICE); - } - - // Force disable keyboard at startup for safety - setKeyboardEnabled(false); - - // Register broadcast receiver for screen state changes - registerScreenStateReceiver(context); - - // Start watchdog thread - startWatchdogThread(); - - } catch (Exception e) { - logError("Error setting up keyboard utils: " + e.getMessage()); + if (mInputManager == null) { + mInputManager = (InputManager) context.getSystemService(Context.INPUT_SERVICE); } - } - - /** - * Register a BroadcastReceiver to handle screen state changes - */ - private static void registerScreenStateReceiver(Context context) { - if (mScreenStateReceiver != null) { - return; // Already registered - } - - logInfo("Registering screen state receiver"); - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_SCREEN_OFF); - filter.addAction(Intent.ACTION_USER_PRESENT); - filter.addAction(Intent.ACTION_SCREEN_ON); - - mScreenStateReceiver = new ScreenStateReceiver(); - context.registerReceiver(mScreenStateReceiver, filter); - } - - /** - * Start watchdog thread to monitor and recover from stuck conditions - */ - private static void startWatchdogThread() { - if (mWatchdogThread != null && mWatchdogThread.isAlive()) { - return; // Thread already running - } - - mWatchdogRunning = true; - mLastWatchdogCheck = System.currentTimeMillis(); - - mWatchdogThread = new Thread(() -> { - logInfo("Keyboard watchdog thread started"); - while (mWatchdogRunning) { - try { - // Update watchdog timestamp - mLastWatchdogCheck = System.currentTimeMillis(); - - // Safety check: ensure keyboard is disabled in lock screen - if (mIsDeviceLocked && mLastEnabledState) { - logError("Watchdog detected keyboard enabled while locked! Forcing disable"); - setKeyboardEnabled(false); - } - - Thread.sleep(5000); // Check every 5 seconds - } catch (InterruptedException e) { - // Thread interrupted, continue loop - } catch (Exception e) { - logError("Watchdog thread error: " + e.getMessage()); - } - } - logInfo("Keyboard watchdog thread stopped"); - }); - - mWatchdogThread.setDaemon(true); - mWatchdogThread.setName("KeyboardWatchdog"); - mWatchdogThread.start(); - } - - /** - * Stop the watchdog thread during cleanup - */ - private static void stopWatchdogThread() { - mWatchdogRunning = false; - if (mWatchdogThread != null) { - mWatchdogThread.interrupt(); - mWatchdogThread = null; - } - } - - /** - * Unregister the screen state receiver when service is destroyed - */ - public static void cleanup(Context context) { - if (mScreenStateReceiver != null) { - try { - context.unregisterReceiver(mScreenStateReceiver); - mScreenStateReceiver = null; - } catch (Exception e) { - logError("Error unregistering receiver: " + e.getMessage()); - } - } - - // Stop watchdog thread - stopWatchdogThread(); - - // Force disable keyboard on cleanup setKeyboardEnabled(false); } - /** - * Enable or disable the Xiaomi keyboard input device - * @param enabled Whether the keyboard should be enabled - * @return true if operation was successful, false otherwise - */ - public static boolean setKeyboardEnabled(boolean enabled) { - // If the device is locked, never enable the keyboard - if (enabled && mIsDeviceLocked) { - logDebug("Not enabling keyboard because device is locked"); - return false; - } - - // Update watchdog timestamp to show activity - mLastWatchdogCheck = System.currentTimeMillis(); - - if (enabled == mLastEnabledState) { - logDebug("Keyboard already in requested state: " + enabled); - return true; - } - - logInfo("Setting keyboard enabled: " + enabled); - boolean success = false; - boolean deviceFound = false; - - try { - if (mInputManager == null) { - logError("InputManager not initialized"); - return false; - } - - for (int id : mInputManager.getInputDeviceIds()) { - if (isDeviceXiaomiKeyboard(id)) { - deviceFound = true; - logDebug("Found Xiaomi Keyboard with id: " + id); - - // Apply enable/disable with timeout protection - try { - if (enabled) { - mInputManager.enableInputDevice(id); - } else { - mInputManager.disableInputDevice(id); - } - mLastEnabledState = enabled; - success = true; - } catch (Exception e) { - logError("Failed to change keyboard state: " + e.getMessage()); - } + public static void setKeyboardEnabled(boolean enabled) { + if (DEBUG) Log.d(TAG, "setKeyboardEnabled: " + enabled); + for (int id : mInputManager.getInputDeviceIds()) { + if (isDeviceXiaomiKeyboard(id)) { + if (DEBUG) Log.d(TAG, "setKeyboardEnabled: Found Xiaomi Keyboard with id: " + id); + if (enabled) { + if (DEBUG) Log.d(TAG, "setKeyboardEnabled: Enabling Xiaomi Keyboard"); + mInputManager.enableInputDevice(id); + } else { + if (DEBUG) Log.d(TAG, "setKeyboardEnabled: Disabling Xiaomi Keyboard"); + mInputManager.disableInputDevice(id); } } - - if (!deviceFound) { - logInfo("Xiaomi keyboard not found in input devices"); - } - } catch (Exception e) { - logError("Error changing keyboard state: " + e.getMessage()); - } - - return success; - } - - /** - * Set device lock state and notify native service - * @param isLocked Whether the device is locked - */ - public static void setDeviceLockState(boolean isLocked) { - mIsDeviceLocked = isLocked; - logInfo("Device lock state changed: " + (isLocked ? "LOCKED" : "UNLOCKED")); - - // If locked, force disable the keyboard with higher priority - if (isLocked) { - setKeyboardEnabled(false); - } else if (!mLastEnabledState) { - // Re-enable keyboard if unlocked and currently disabled - setKeyboardEnabled(true); - } - - // Notify native service about lock state change - sendLockStateToNativeService(isLocked); - } - - /** - * Send lock state message to native service - * @param isLocked Whether device is locked - */ - private static void sendLockStateToNativeService(boolean isLocked) { - try { - byte messageType = isLocked ? MSG_TYPE_LOCK : MSG_TYPE_UNLOCK; - - // Protocol: [0x??][Header1][Header2][0][MessageType][1][1] - byte[] message = new byte[7]; - message[0] = 0; // First byte can be anything - message[1] = MSG_HEADER_1; - message[2] = MSG_HEADER_2; - message[3] = 0; - message[4] = messageType; - message[5] = 1; - message[6] = 1; - - // Write to nanodev device - File nanodev = new File(NANODEV_PATH); - if (!nanodev.exists() || !nanodev.canWrite()) { - logError("Cannot write to nanodev: " + NANODEV_PATH); - return; - } - - FileOutputStream fos = new FileOutputStream(NANODEV_PATH); - fos.write(message); - fos.close(); - - logDebug("Sent lock state " + (isLocked ? "LOCK" : "UNLOCK") + " to native service"); - } catch (IOException e) { - logError("Failed to send lock state to native service: " + e.getMessage()); } } - /** - * Check if an input device is the Xiaomi keyboard - * @param id Device ID to check - * @return true if the device is the Xiaomi keyboard - */ private static boolean isDeviceXiaomiKeyboard(int id) { - try { - InputDevice inputDevice = mInputManager.getInputDevice(id); - if (inputDevice == null) return false; - - return inputDevice.getVendorId() == KEYBOARD_VENDOR_ID && - inputDevice.getProductId() == KEYBOARD_PRODUCT_ID; - } catch (Exception e) { - logError("Error checking device: " + e.getMessage()); - return false; - } - } - - /** - * BroadcastReceiver to detect screen state changes - */ - private static class ScreenStateReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - - if (Intent.ACTION_SCREEN_OFF.equals(action)) { - setDeviceLockState(true); - } else if (Intent.ACTION_USER_PRESENT.equals(action)) { - setDeviceLockState(false); - } - } - } - - // Enhanced logging helpers to match C++ style - private static void logDebug(String message) { - if (DEBUG) Log.d(TAG, getTimestamp() + message); - } - - private static void logInfo(String message) { - Log.i(TAG, getTimestamp() + message); - } - - private static void logError(String message) { - Log.e(TAG, getTimestamp() + message); - } - - private static String getTimestamp() { - return "[" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US).format(new Date()) + "] "; + InputDevice inputDevice = mInputManager.getInputDevice(id); + return inputDevice.getVendorId() == kbVendorId && inputDevice.getProductId() == kbProductId; } } diff --git a/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/LidSettingsActivity.java b/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/LidSettingsActivity.java deleted file mode 100644 index 9b20059..0000000 --- a/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/LidSettingsActivity.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2023-2025 The LineageOS Project - * - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.lineageos.xiaomiperipheralmanager; - -import android.os.Bundle; -import android.util.Log; - -import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity; - -/** - * Settings activity for stylus/pen configuration - * Hosts the StylusSettingsFragment for user configuration - */ -public class LidSettingsActivity extends CollapsingToolbarBaseActivity { - - private static final String TAG = "XiaomiLidSettings"; - private static final String TAG_LID = "lid"; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - Log.i(TAG, "Opening lid settings"); - - getFragmentManager().beginTransaction().replace( - com.android.settingslib.collapsingtoolbar.R.id.content_frame, - new LidSettingsFragment(), TAG_LID).commit(); - } -} diff --git a/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/LidSettingsFragment.java b/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/LidSettingsFragment.java deleted file mode 100644 index 202d480..0000000 --- a/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/LidSettingsFragment.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2023-2025 The LineageOS Project - * - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.lineageos.xiaomiperipheralmanager; - -import android.content.Context; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.os.SystemProperties; -import android.util.Log; - -import android.preference.PreferenceManager; -import androidx.preference.ListPreference; -import androidx.preference.Preference; -import androidx.preference.Preference.OnPreferenceChangeListener; -import androidx.preference.PreferenceFragment; -import androidx.preference.SwitchPreference; -import com.android.settingslib.widget.MainSwitchPreference; - -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; - -import android.provider.Settings; - -/** - * Settings fragment for lid configuration - * Allows users to manually enable/disable the smart cover - */ -public class LidSettingsFragment extends PreferenceFragment implements - SharedPreferences.OnSharedPreferenceChangeListener { - - private static final String TAG = "XiaomiLidSettings"; - private static final String LID_KEY = "lid_switch_key"; - - private SharedPreferences mLidPreference; - - @Override - public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { - try { - addPreferencesFromResource(R.xml.lid_settings); - - mLidPreference = PreferenceManager.getDefaultSharedPreferences(getContext()); - SwitchPreference switchPreference = (SwitchPreference) findPreference(LID_KEY); - - if (switchPreference != null) { - switchPreference.setChecked(mLidPreference.getBoolean(LID_KEY, false)); - switchPreference.setEnabled(true); - } else { - logError("Could not find lid switch preference"); - } - - logInfo("Lid settings fragment created"); - } catch (Exception e) { - logError("Error creating lid settings: " + e.getMessage()); - } - } - - @Override - public void onResume() { - super.onResume(); - try { - mLidPreference.registerOnSharedPreferenceChangeListener(this); - } catch (Exception e) { - logError("Error in onResume: " + e.getMessage()); - } - } - - @Override - public void onPause() { - super.onPause(); - try { - mLidPreference.unregisterOnSharedPreferenceChangeListener(this); - } catch (Exception e) { - logError("Error in onPause: " + e.getMessage()); - } - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreference, String key) { - if (LID_KEY.equals(key)) { - try { - boolean newStatus = mLidPreference.getBoolean(key, false); - logInfo("Lid preference changed to: " + newStatus); - Settings.Global.putInt(getActivity().getContentResolver(), - "lid_behavior", newStatus ? 1 : 0); - } catch (Exception e) { - logError("Error handling preference change: " + e.getMessage()); - } - } - } - - private void logInfo(String message) { - Log.i(TAG, getTimestamp() + message); - } - - private void logError(String message) { - Log.e(TAG, getTimestamp() + message); - } - - private String getTimestamp() { - return "[" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US).format(new Date()) + "] "; - } -} diff --git a/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/PenUtils.java b/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/PenUtils.java index 38a56bb..675bbcb 100644 --- a/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/PenUtils.java +++ b/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/PenUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023-2025 The LineageOS Project + * Copyright (C) 2023 The LineageOS Project * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,151 +16,73 @@ import android.view.InputDevice; import android.preference.PreferenceManager; import android.content.SharedPreferences; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; - -/** - * Utility class for handling Xiaomi pen operations and mode switching - */ public class PenUtils { - private static final String TAG = "XiaomiPen"; - private static boolean DEBUG = SystemProperties.getBoolean("persist.xiaomi.pen.debug", false); + private static final String TAG = "XiaomiPeripheralManagerPenUtils"; + private static final boolean DEBUG = false; - // Xiaomi pen identifiers - private static final int PEN_VENDOR_ID = 6421; - private static final int PEN_PRODUCT_ID = 19841; + private static final int penVendorId = 6421; + private static final int penProductId = 19841; private static InputManager mInputManager; - private static SharedPreferences mPreferences; + private static final String STYLUS_KEY = "stylus_switch_key"; - /** - * Initialize the pen utilities and register for input device events - * @param context Application context - */ + private static SharedPreferences preferences; + private static RefreshUtils mRefreshUtils; + public static void setup(Context context) { - logInfo("Initializing Xiaomi pen framework integration"); - try { - mInputManager = (InputManager) context.getSystemService(Context.INPUT_SERVICE); - mInputManager.registerInputDeviceListener(mInputDeviceListener, null); - mPreferences = PreferenceManager.getDefaultSharedPreferences(context); - refreshPenMode(); - } catch (Exception e) { - logError("Error setting up pen utils: " + e.getMessage()); - } + mInputManager = (InputManager) context.getSystemService(Context.INPUT_SERVICE); + mInputManager.registerInputDeviceListener(mInputDeviceListener, null); + preferences = PreferenceManager.getDefaultSharedPreferences(context); + mRefreshUtils = new RefreshUtils(context); + refreshPenMode(); } - /** - * Enable pen mode by setting system property - */ public static void enablePenMode() { - logInfo("Enabling pen mode"); - try { - SystemProperties.set("persist.vendor.parts.pen", "18"); - } catch (Exception e) { - logError("Failed to enable pen mode: " + e.getMessage()); - } + Log.d(TAG, "enablePenMode: Enable Pen Mode"); + SystemProperties.set("persist.vendor.parts.pen", "18"); + Log.d(TAG, "enablePenMode: Setting Refresh Rates for Pen"); + mRefreshUtils.setPenRefreshRate(); } - /** - * Disable pen mode by setting system property - */ public static void disablePenMode() { - logInfo("Disabling pen mode"); - try { - SystemProperties.set("persist.vendor.parts.pen", "2"); - } catch (Exception e) { - logError("Failed to disable pen mode: " + e.getMessage()); - } + Log.d(TAG, "disablePenMode: Disable Pen Mode"); + SystemProperties.set("persist.vendor.parts.pen", "2"); + Log.d(TAG, "disablePenMode: Resetting Refresh Rate Values"); + mRefreshUtils.setDefaultRefreshRate(); } - /** - * Check for pen presence and update mode accordingly - */ private static void refreshPenMode() { - try { - boolean penFound = false; - - for (int id : mInputManager.getInputDeviceIds()) { - if (isDeviceXiaomiPen(id)) { - logDebug("Found Xiaomi Pen with id: " + id); - penFound = true; - break; - } - } - - // Also check preference override - boolean preferenceEnabled = mPreferences.getBoolean(STYLUS_KEY, false); - - if (penFound || preferenceEnabled) { - logInfo("Pen detected or enabled in preferences"); + for (int id : mInputManager.getInputDeviceIds()) { + if (isDeviceXiaomiPen(id) || preferences.getBoolean(STYLUS_KEY, false)) { + if (DEBUG) Log.d(TAG, "refreshPenMode: Found Xiaomi Pen"); enablePenMode(); - } else { - logInfo("No pen detected and not enabled in preferences"); - disablePenMode(); + return; } - } catch (Exception e) { - logError("Error refreshing pen mode: " + e.getMessage()); } + if (DEBUG) Log.d(TAG, "refreshPenMode: No Xiaomi Pen found"); + disablePenMode(); } - /** - * Check if an input device is the Xiaomi pen - * @param id Device ID to check - * @return true if the device is the Xiaomi pen - */ private static boolean isDeviceXiaomiPen(int id) { - try { - InputDevice inputDevice = mInputManager.getInputDevice(id); - if (inputDevice == null) return false; - - return inputDevice.getVendorId() == PEN_VENDOR_ID && - inputDevice.getProductId() == PEN_PRODUCT_ID; - } catch (Exception e) { - logError("Error checking pen device: " + e.getMessage()); - return false; - } + InputDevice inputDevice = mInputManager.getInputDevice(id); + return inputDevice.getVendorId() == penVendorId && + inputDevice.getProductId() == penProductId; } - /** - * Input device listener for pen connection/disconnection events - */ private static InputDeviceListener mInputDeviceListener = new InputDeviceListener() { - @Override - public void onInputDeviceAdded(int id) { - logDebug("Input device added: " + id); - refreshPenMode(); - } - - @Override - public void onInputDeviceRemoved(int id) { - logDebug("Input device removed: " + id); - refreshPenMode(); - } - - @Override - public void onInputDeviceChanged(int id) { - logDebug("Input device changed: " + id); - refreshPenMode(); - } - }; - - // Enhanced logging helpers to match other classes - private static void logDebug(String message) { - if (DEBUG) Log.d(TAG, getTimestamp() + message); - } - - private static void logInfo(String message) { - Log.i(TAG, getTimestamp() + message); - } - - private static void logError(String message) { - Log.e(TAG, getTimestamp() + message); - } - - private static String getTimestamp() { - return "[" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US).format(new Date()) + "] "; - } + @Override + public void onInputDeviceAdded(int id) { + refreshPenMode(); + } + @Override + public void onInputDeviceRemoved(int id) { + refreshPenMode(); + } + @Override + public void onInputDeviceChanged(int id) { + refreshPenMode(); + } + }; } diff --git a/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/RefreshUtils.java b/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/RefreshUtils.java new file mode 100644 index 0000000..790c5d2 --- /dev/null +++ b/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/RefreshUtils.java @@ -0,0 +1,55 @@ +package org.lineageos.xiaomiperipheralmanager; + +import android.content.Context; +import android.content.SharedPreferences; +import android.provider.Settings; + +public final class RefreshUtils { + private static final String KEY_PEAK_REFRESH_RATE = "peak_refresh_rate"; + private static final String KEY_MIN_REFRESH_RATE = "min_refresh_rate"; + private static final String KEY_PEN_MODE = "pen_mode"; + private static final String PREF_FILE_NAME = "pen_refresh_prefs"; + + private Context mContext; + private SharedPreferences mSharedPrefs; + + protected RefreshUtils(Context context) { + mContext = context; + mSharedPrefs = context.getSharedPreferences(PREF_FILE_NAME, Context.MODE_PRIVATE); + } + + protected void setPenRefreshRate() { + boolean penMode = mSharedPrefs.getBoolean(KEY_PEN_MODE, false); + + if (!penMode) { + float maxRate = Settings.System.getFloat(mContext.getContentResolver(), KEY_PEAK_REFRESH_RATE, 144f); + float minRate = Settings.System.getFloat(mContext.getContentResolver(), KEY_MIN_REFRESH_RATE, 144f); + + // Update default values in SharedPreferences + mSharedPrefs.edit() + .putFloat(KEY_MIN_REFRESH_RATE, minRate) + .putFloat(KEY_PEAK_REFRESH_RATE, maxRate) + .putBoolean(KEY_PEN_MODE, true) + .apply(); + + // Ensure valid values for maxRate and minRate + maxRate = (maxRate != 60) ? 120 : maxRate; + minRate = (minRate <= 60) ? 60 : 120; + + // Set the values in the Settings.System + Settings.System.putFloat(mContext.getContentResolver(), KEY_MIN_REFRESH_RATE, minRate); + Settings.System.putFloat(mContext.getContentResolver(), KEY_PEAK_REFRESH_RATE, maxRate); + } + } + + protected void setDefaultRefreshRate() { + float defaultMinRate = mSharedPrefs.getFloat(KEY_MIN_REFRESH_RATE, 144f); + float defaultMaxRate = mSharedPrefs.getFloat(KEY_PEAK_REFRESH_RATE, 144f); + + mSharedPrefs.edit().putBoolean(KEY_PEN_MODE, false).apply(); + + // Set the values in the Settings.System directly + Settings.System.putFloat(mContext.getContentResolver(), KEY_MIN_REFRESH_RATE, defaultMinRate); + Settings.System.putFloat(mContext.getContentResolver(), KEY_PEAK_REFRESH_RATE, defaultMaxRate); + } +} diff --git a/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/StylusSettingsActivity.java b/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/StylusSettingsActivity.java index d4317f4..2012e9a 100644 --- a/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/StylusSettingsActivity.java +++ b/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/StylusSettingsActivity.java @@ -1,31 +1,33 @@ /* - * Copyright (C) 2023-2025 The LineageOS Project + * Copyright (C) 2023 The LineageOS Project * - * SPDX-License-Identifier: Apache-2.0 + * 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 org.lineageos.xiaomiperipheralmanager; import android.os.Bundle; -import android.util.Log; import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity; -/** - * Settings activity for stylus/pen configuration - * Hosts the StylusSettingsFragment for user configuration - */ public class StylusSettingsActivity extends CollapsingToolbarBaseActivity { - private static final String TAG = "XiaomiPenSettings"; private static final String TAG_STYLUS = "stylus"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - - Log.i(TAG, "Opening stylus settings"); - + getFragmentManager().beginTransaction().replace( com.android.settingslib.collapsingtoolbar.R.id.content_frame, new StylusSettingsFragment(), TAG_STYLUS).commit(); diff --git a/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/StylusSettingsFragment.java b/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/StylusSettingsFragment.java index 6801f62..5ad93ab 100644 --- a/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/StylusSettingsFragment.java +++ b/peripheralmanager/src/org/lineageos/xiaomiperipheralmanager/StylusSettingsFragment.java @@ -1,7 +1,17 @@ /* - * Copyright (C) 2023-2025 The LineageOS Project + * Copyright (C) 2023 The LineageOS Project * - * SPDX-License-Identifier: Apache-2.0 + * 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 org.lineageos.xiaomiperipheralmanager; @@ -9,7 +19,7 @@ package org.lineageos.xiaomiperipheralmanager; import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; -import android.os.SystemProperties; +import android.widget.Switch; import android.util.Log; import android.preference.PreferenceManager; @@ -20,108 +30,53 @@ import androidx.preference.PreferenceFragment; import androidx.preference.SwitchPreference; import com.android.settingslib.widget.MainSwitchPreference; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; +import org.lineageos.xiaomiperipheralmanager.PenUtils; +import org.lineageos.xiaomiperipheralmanager.R; -/** - * Settings fragment for stylus/pen configuration - * Allows users to manually enable/disable the pen mode - */ public class StylusSettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener { - private static final String TAG = "XiaomiPenSettings"; - private static boolean DEBUG = SystemProperties.getBoolean("persist.xiaomi.pen.debug", false); + private static final String TAG = "XiaomiPeripheralManagerPenUtils"; private static final String STYLUS_KEY = "stylus_switch_key"; private SharedPreferences mStylusPreference; @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { - try { - addPreferencesFromResource(R.xml.stylus_settings); + addPreferencesFromResource(R.xml.stylus_settings); - mStylusPreference = PreferenceManager.getDefaultSharedPreferences(getContext()); - SwitchPreference switchPreference = (SwitchPreference) findPreference(STYLUS_KEY); + mStylusPreference = PreferenceManager.getDefaultSharedPreferences(getContext()); + SwitchPreference switchPreference = (SwitchPreference) findPreference(STYLUS_KEY); - if (switchPreference != null) { - switchPreference.setChecked(mStylusPreference.getBoolean(STYLUS_KEY, false)); - switchPreference.setEnabled(true); - } else { - logError("Could not find stylus switch preference"); - } - - logInfo("Stylus settings fragment created"); - } catch (Exception e) { - logError("Error creating stylus settings: " + e.getMessage()); - } + switchPreference.setChecked(mStylusPreference.getBoolean(STYLUS_KEY, false)); + switchPreference.setEnabled(true); } @Override public void onResume() { super.onResume(); - try { - mStylusPreference.registerOnSharedPreferenceChangeListener(this); - logDebug("Registered preference change listener"); - } catch (Exception e) { - logError("Error in onResume: " + e.getMessage()); - } + mStylusPreference.registerOnSharedPreferenceChangeListener(this); } @Override public void onPause() { super.onPause(); - try { - mStylusPreference.unregisterOnSharedPreferenceChangeListener(this); - logDebug("Unregistered preference change listener"); - } catch (Exception e) { - logError("Error in onPause: " + e.getMessage()); - } + mStylusPreference.unregisterOnSharedPreferenceChangeListener(this); } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreference, String key) { if (STYLUS_KEY.equals(key)) { - try { - boolean newStatus = mStylusPreference.getBoolean(key, false); - logInfo("Stylus preference changed to: " + newStatus); - forceStylus(newStatus); - } catch (Exception e) { - logError("Error handling preference change: " + e.getMessage()); - } + forceStylus(mStylusPreference.getBoolean(key, false)); } } private void forceStylus(boolean status) { - try { - mStylusPreference.edit().putBoolean(STYLUS_KEY, status).apply(); - logInfo("Setting stylus mode: " + (status ? "enabled" : "disabled")); - - if (status) { - PenUtils.enablePenMode(); - } else { - PenUtils.disablePenMode(); - } - } catch (Exception e) { - logError("Error setting stylus mode: " + e.getMessage()); - } - } - - // Enhanced logging helpers to match other classes - private void logDebug(String message) { - if (DEBUG) Log.d(TAG, getTimestamp() + message); - } - - private void logInfo(String message) { - Log.i(TAG, getTimestamp() + message); - } - - private void logError(String message) { - Log.e(TAG, getTimestamp() + message); - } - - private String getTimestamp() { - return "[" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US).format(new Date()) + "] "; + mStylusPreference.edit().putBoolean(STYLUS_KEY, status).apply(); + + if (status) + PenUtils.enablePenMode(); + else + PenUtils.disablePenMode(); } } diff --git a/peripheralmanager/xiaomi-keyboard.cpp b/peripheralmanager/xiaomi-keyboard.cpp index b6fe01d..91282b7 100644 --- a/peripheralmanager/xiaomi-keyboard.cpp +++ b/peripheralmanager/xiaomi-keyboard.cpp @@ -1,862 +1,340 @@ -/* - * Copyright (C) 2023-2025 The LineageOS Project - * - * SPDX-License-Identifier: Apache-2.0 - */ - #include -#include #include -#include // for fast square root + vector math -#include // Add for isspace() function -#include #include #include #include -#include // Add for signal handling #include #include -#include #include #include -#include // Add for time functions #include + const char kPackageName[] = "xiaomi-keyboard"; -/******************************************** - * Configuration Constants - ********************************************/ -#define BUFFER_SIZE 256 -#define NANODEV_PATH "/dev/nanodev0" -#define DEBOUNCE_COUNT 3 - -/******************************************** - * Message Protocol Definitions - ********************************************/ -#define MSG_TYPE_SLEEP 37 -#define MSG_TYPE_WAKE 40 -#define MSG_HEADER_1 0x31 -#define MSG_HEADER_2 0x38 -#define MSG_TYPE_MOVEMENT 0x64 - -// Lock state message types -#define MSG_TYPE_LOCK 41 -#define MSG_TYPE_UNLOCK 42 +#define BUFFER_SIZE 1024 // Device path -// We'll find this dynamically -char* EVENT_PATH = NULL; +#define NANODEV_PATH "/dev/nanodev0" +#define EVENT_PATH "/dev/input/event12" -// Simplify by keeping only essential logging macros +// logging #define TAG "xiaomi-keyboard" #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__) #define LOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__) #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) -// Keep just one enhanced logging macro for important events -#define LOG_IMPORTANT(fmt, ...) \ - do { \ - time_t now = time(NULL); \ - struct tm* tm_info = localtime(&now); \ - char time_str[20]; \ - strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", tm_info); \ - __android_log_print(ANDROID_LOG_INFO, TAG, "[%s] " fmt, time_str, \ - ##__VA_ARGS__); \ - } while (0) +// Pre-calculated sin and cos tables to optimize code +static const float angle_cos[] = { + 1.0f, 0.999848f, 0.999391f, 0.99863f, 0.997564f, 0.996195f, 0.994522f, + 0.992546f, 0.990268f, 0.987688f, 0.984808f, 0.981627f, 0.978148f, 0.97437f, + 0.970296f, 0.965926f, 0.961262f, 0.956305f, 0.951057f, 0.945519f, 0.939693f, + 0.93358f, 0.927184f, 0.920505f, 0.913545f, 0.906308f, 0.898794f, 0.891007f, + 0.882948f, 0.87462f, 0.866025f, 0.857167f, 0.848048f, 0.838671f, 0.829038f, + 0.819152f, 0.809017f, 0.798635f, 0.788011f, 0.777146f, 0.766044f, 0.75471f, + 0.743145f, 0.731354f, 0.71934f, 0.707107f, 0.694658f, 0.681998f, 0.669131f, + 0.656059f, 0.642788f, 0.62932f, 0.615661f, 0.601815f, 0.587785f, 0.573576f, + 0.559193f, 0.544639f, 0.529919f, 0.515038f, 0.5f, 0.48481f, 0.469472f, + 0.453991f, 0.438371f, 0.422618f, 0.406737f, 0.390731f, 0.374607f, 0.358368f, + 0.34202f, 0.325568f, 0.309017f, 0.292372f, 0.275637f, 0.258819f, 0.241922f, + 0.224951f, 0.207912f, 0.190809f, 0.173648f, 0.156434f, 0.139173f, 0.121869f, + 0.104528f, 0.087156f, 0.069756f, 0.052336f, 0.034899f, 0.017452f, -0.0f}; + +static const float angle_sin[] = { + 0.0f, 0.017452f, 0.034899f, 0.052336f, 0.069756f, 0.087156f, 0.104528f, + 0.121869f, 0.139173f, 0.156434f, 0.173648f, 0.190809f, 0.207912f, 0.224951f, + 0.241922f, 0.258819f, 0.275637f, 0.292372f, 0.309017f, 0.325568f, 0.34202f, + 0.358368f, 0.374607f, 0.390731f, 0.406737f, 0.422618f, 0.438371f, 0.453991f, + 0.469472f, 0.48481f, 0.5f, 0.515038f, 0.529919f, 0.544639f, 0.559193f, + 0.573576f, 0.587785f, 0.601815f, 0.615662f, 0.62932f, 0.642788f, 0.656059f, + 0.669131f, 0.681998f, 0.694658f, 0.707107f, 0.71934f, 0.731354f, 0.743145f, + 0.75471f, 0.766044f, 0.777146f, 0.788011f, 0.798636f, 0.809017f, 0.819152f, + 0.829038f, 0.838671f, 0.848048f, 0.857167f, 0.866025f, 0.87462f, 0.882948f, + 0.891007f, 0.898794f, 0.906308f, 0.913545f, 0.920505f, 0.927184f, 0.93358f, + 0.939693f, 0.945519f, 0.951057f, 0.956305f, 0.961262f, 0.965926f, 0.970296f, + 0.97437f, 0.978148f, 0.981627f, 0.984808f, 0.987688f, 0.990268f, 0.992546f, + 0.994522f, 0.996195f, 0.997564f, 0.99863f, 0.999391f, 0.999848f, 1.0f}; // Nanodev file int fd; +// Global variables to hold pad the accelerometer data +float padX = 0.0f; +float padY = 0.0f; +float padZ = 0.0f; + +// Global variables to hold kb the accelerometer data +float kbX = 0.0f; +float kbY = 0.0f; +float kbZ = 0.0f; + // Current kb enabled/disabled state bool kb_status = true; +// Condition variable for pausing and resuming the thread +pthread_mutex_t acc_mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t acc_cond = PTHREAD_COND_INITIALIZER; +bool acc_paused = false; + // Sensor variables -const ASensor* sensor; -ASensorEventQueue* queue; +const ASensor *sensor; +ASensorEventQueue *queue; -float padX = 0; -float padY = 0; -float padZ = 0; -float kbX = 0; -float kbY = 0; -float kbZ = 0; - -// Add signal handler for graceful termination - MOVED HERE -volatile sig_atomic_t terminate = 0; - -// Condition variable for pausing and resuming the kb, sensor threads -pthread_mutex_t kb_mutex = PTHREAD_MUTEX_INITIALIZER; -pthread_cond_t kb_cond = PTHREAD_COND_INITIALIZER; -bool kb_thread_paused = false; - -// Condition variable for the sensor thread -pthread_mutex_t sensor_mutex = PTHREAD_MUTEX_INITIALIZER; - -// For the preference thread -pthread_mutex_t angle_detection_mutex = PTHREAD_MUTEX_INITIALIZER; - -// Add these global variables -time_t last_monitor_activity = time(NULL); -pthread_t watchdog_thread; -bool watchdog_enabled = true; - -// Angle detection enable flag -bool angle_detection_enabled = false; // Default value - -void load_angle_detection_preference() { - FILE* f = fopen("/data/misc/xiaomi_keyboard.conf", "r"); - if (f) { - int c = fgetc(f); - pthread_mutex_lock(&angle_detection_mutex); - angle_detection_enabled = (c == '1'); - pthread_mutex_lock(&angle_detection_mutex); - fclose(f); - LOGI("Angle detection preference loaded: %s", - angle_detection_enabled ? "enabled" : "disabled"); - } else { - LOGW( - "Could not open /data/misc/xiaomi_keyboard.conf, using default " - "(enabled)"); - // angle_detection_enabled = true; - } -} - -void* preference_watcher_thread(void*) { - while (!terminate) { - load_angle_detection_preference(); - sleep(10); // Reload every 10 seconds - } - return NULL; -} - -// Globals -static ASensorManager* sensorManager = NULL; -static const ASensor* accelerometer = NULL; -static ASensorEventQueue* sensorQueue = NULL; -static ALooper* looper = NULL; - -void* accelerometer_thread(void* args) { - pthread_mutex_lock(&kb_mutex); - while (kb_thread_paused && !terminate) { - pthread_cond_wait(&kb_cond, &kb_mutex); - } - pthread_mutex_unlock(&kb_mutex); - - sensorManager = ASensorManager_getInstanceForPackage( - "org.lineageos.xiaomiperipheralmanager"); - accelerometer = ASensorManager_getDefaultSensor(sensorManager, - ASENSOR_TYPE_ACCELEROMETER); - - if (!accelerometer) { - LOGI("Accelerometer not available"); - return NULL; - } - - looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); - sensorQueue = - ASensorManager_createEventQueue(sensorManager, looper, 0, NULL, NULL); - ASensorEventQueue_enableSensor(sensorQueue, accelerometer); - ASensorEventQueue_setEventRate(sensorQueue, accelerometer, - ASensor_getMinDelay(accelerometer)); - - while (!terminate) { - ALooper_pollOnce(500, NULL, NULL, NULL); - if (terminate) break; - - ASensorEvent event; - while (ASensorEventQueue_getEvents(sensorQueue, &event, 1) > 0) { - if (event.type == ASENSOR_TYPE_ACCELEROMETER) { - pthread_mutex_lock(&sensor_mutex); - padX = event.acceleration.x; - padY = event.acceleration.y; - padZ = event.acceleration.z; - pthread_mutex_unlock(&sensor_mutex); - } +// Initialize the sensors module +int init_sensors() { + ASensorManager *sensor_manager = + ASensorManager_getInstanceForPackage(kPackageName); + if (!sensor_manager) { + LOGE("Failed to get a sensor manager"); + return 1; } - } - // Unreachable, but good practice - ASensorEventQueue_disableSensor(sensorQueue, accelerometer); - ASensorManager_destroyEventQueue(sensorManager, sensorQueue); - return NULL; + queue = ASensorManager_createEventQueue( + sensor_manager, ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS), 1, + NULL /* no callback */, NULL /* no data */); + if (!queue) { + LOGE("Failed to create a sensor event queue"); + return 1; + } + + sensor = ASensorManager_getDefaultSensor(sensor_manager, + ASENSOR_TYPE_ACCELEROMETER); + + return 0; } -static inline float neon_sqrtf(float x) { - float32x2_t val = vdup_n_f32(x); - float32x2_t res = vsqrt_f32(val); - return vget_lane_f32(res, 0); -} +// Read acc data +int read_acc() { + if (sensor && !ASensorEventQueue_enableSensor(queue, sensor)) { + ASensorEvent data; + usleep(150000); + if (ASensorEventQueue_getEvents(queue, &data, 1)) { + padX = data.acceleration.x; + padY = data.acceleration.y; + padZ = data.acceleration.z; + } else + return -1; -static inline float fast_acosf(float x) { - if (x < -1.0f) x = -1.0f; - if (x > 1.0f) x = 1.0f; - - float negate = (x < 0.0f); - x = fabsf(x); - - float ret = -0.0187293f; - ret = ret * x + 0.0742610f; - ret = ret * x - 0.2121144f; - ret = ret * x + 1.5707288f; - ret = ret * neon_sqrtf(1.0f - x); - - return negate ? (M_PI - ret) : ret; -} - -/** - * Find the keyboard event input device path - * This replaces the hardcoded path with dynamic detection - */ -char* find_keyboard_input_path() { - static char path_buffer[128] = "/dev/input/event12"; - const char* input_dir = "/dev/input"; - DIR* dir = opendir(input_dir); - - if (!dir) { - LOGE("Failed to open input directory"); - return path_buffer; - } - - FILE* device_file; - char name_path[128]; - char device_name[256]; - struct dirent* entry; - - // Simplified detection criteria with key terms - const char* keyboard_identifiers[] = {"xiaomi", "keyboard", "pipa", "XKBD"}; - const int num_identifiers = 4; - - while ((entry = readdir(dir)) != NULL) { - if (strncmp(entry->d_name, "event", 5) == 0) { - snprintf(name_path, sizeof(name_path), "/sys/class/input/%s/device/name", - entry->d_name); - - device_file = fopen(name_path, "r"); - if (device_file && fgets(device_name, sizeof(device_name), device_file)) { - // Convert to lowercase for case-insensitive matching - for (char* p = device_name; *p; p++) { - *p = tolower(*p); + int ret = ASensorEventQueue_disableSensor(queue, sensor); + if (ret) { + LOGW("Failed to disable acc: %d", ret); + return ret; } - - for (int i = 0; i < num_identifiers; i++) { - if (strstr(device_name, keyboard_identifiers[i])) { - snprintf(path_buffer, sizeof(path_buffer), "/dev/input/%s", - entry->d_name); - LOGI("Found keyboard at: %s", path_buffer); - fclose(device_file); - closedir(dir); - return path_buffer; - } - } - fclose(device_file); - } - } - } - - closedir(dir); - LOGW("Could not find keyboard device, using default path"); - return path_buffer; + } else + return -1; + return 0; } -/** - * Set keyboard state directly - */ -void set_kb_state(bool value, bool force) { - if (kb_status != value || force) { - kb_status = value; - LOGI("Setting keyboard state to: %d", value); - - // Add fd validation before attempting write - if (fd < 0) { - LOGE("Invalid file descriptor (fd=%d) when setting keyboard state", fd); - return; - } - - unsigned char buf[3] = {0x32, 0xFF, (unsigned char)value}; - ssize_t bytes_written = write(fd, &buf, 3); - - if (bytes_written != 3) { - // Enhanced error logging with errno details - LOGE("Failed to write keyboard state: %s (errno=%d, written=%zd/3)", - strerror(errno), errno, bytes_written); - - // Log device status - struct stat st; - if (fstat(fd, &st) == 0) { - LOGI("Device status: mode=%o, size=%lld, uid=%d, gid=%d", st.st_mode, - (long long)st.st_size, st.st_uid, st.st_gid); - } else { - LOGE("Unable to stat device: %s", strerror(errno)); - } - } else { - LOGI("Successfully wrote keyboard state: %d", value); - } - } +float invSqrt(float num) { + float xHalf = 0.5f * num; + int i = *(int *)# + i = 0x5f3759df - (i >> 1); + float y = *(float *)&i; + y = y * (1.5f - (xHalf * y * y)); // Newton's method step + return y; } -// Improved keyboard status monitoring with debouncing - -// Add this global variable to track device lock state -bool device_is_locked = false; - -void* keyboard_monitor_thread(void* arg) { - (void)arg; - - int connection_state_count = 0; - bool last_state = access(EVENT_PATH, F_OK) != -1; - - struct timespec timeout; - - while (!terminate) { - // Check whether the watchdog thread should be paused - pthread_mutex_lock(&kb_mutex); - while (kb_thread_paused && !terminate) { - pthread_cond_wait(&kb_cond, &kb_mutex); - } - pthread_mutex_unlock(&kb_mutex); - - if (terminate) break; - - // Check keyboard connection state - bool current_state = (access(EVENT_PATH, F_OK) != -1); - - if (current_state != last_state) { - connection_state_count++; - LOGD("Potential keyboard connection change detected (%d/%d)", - connection_state_count, DEBOUNCE_COUNT); - } else { - connection_state_count = 0; - } - - if (connection_state_count >= DEBOUNCE_COUNT) { - last_state = current_state; - connection_state_count = 0; - - pthread_mutex_lock(&kb_mutex); - if (!kb_thread_paused) { - if (current_state && !device_is_locked && !kb_status) { - LOGI("Keyboard connected and device unlocked - enabling"); - set_kb_state(true, false); - } else if ((!current_state || device_is_locked) && kb_status) { - LOGI("Keyboard %s - disabling", - !current_state ? "disconnected" : "disabled due to device lock"); - set_kb_state(false, false); - } - } - pthread_mutex_unlock(&kb_mutex); - } - - // Always update watchdog activity if not paused - pthread_mutex_lock(&kb_mutex); - if (!kb_thread_paused) last_monitor_activity = time(NULL); - pthread_mutex_unlock(&kb_mutex); - - // Sleep in a responsive pattern (1s total) - for (int i = 0; i < 5 && !terminate; i++) { - usleep(200000); - } - } - LOGI("Keyboard monitor thread exiting"); - return NULL; -} - -// Add this watchdog thread function -void* watchdog_thread_func(void* arg) { - (void)arg; // Suppress unused parameter warning - - const int WATCHDOG_INTERVAL = 30; // 30 seconds - - LOGI("Watchdog thread started"); - - while (!terminate) { - sleep(10); // Check every 10 seconds - - time_t now = time(NULL); - pthread_mutex_lock(&kb_mutex); - bool is_paused = kb_thread_paused; - time_t last_activity = last_monitor_activity; - pthread_mutex_unlock(&kb_mutex); - - // If monitor thread hasn't updated in WATCHDOG_INTERVAL, it might be stuck - if (!is_paused && watchdog_enabled && - now - last_activity > WATCHDOG_INTERVAL) { - LOGW("Watchdog: Monitor thread appears stuck for %d seconds", - (int)(now - last_activity)); - - // Signal the condition to try to wake up the thread - pthread_mutex_lock(&kb_mutex); - pthread_cond_signal(&kb_cond); - pthread_mutex_unlock(&kb_mutex); - } - } - - LOGI("Watchdog thread exiting"); - return NULL; -} - -// Define message types for better readability - -/** - * Event handler for wake/sleep messages - */ -// Consider using a simpler mutex lock/unlock pattern -void handle_power_event(char* buffer) { - bool is_wake = (buffer[6] == 1); - - pthread_mutex_lock(&kb_mutex); - if (is_wake) { - kb_thread_paused = false; - last_monitor_activity = time(NULL); - pthread_cond_signal(&kb_cond); - } else { - kb_thread_paused = true; - } - pthread_mutex_unlock(&kb_mutex); - - // Log and handle status after mutex is released - if (is_wake) { - LOGI("Received wake event - enabling keyboard monitoring"); - bool keyboard_connected = (access(EVENT_PATH, F_OK) != -1); - LOGI("Wake: Keyboard %s", - keyboard_connected ? "connected" : "disconnected"); - - // Only enable if the device is not locked and keyboard is connected - if (keyboard_connected && !device_is_locked) { - set_kb_state(true, true); - } else { - kb_status = false; - LOGI("Not enabling keyboard on wake: %s", - device_is_locked ? "device is locked" : "keyboard not connected"); - } - } else { - LOGI("Received sleep event - pausing keyboard monitoring"); - } -} - -void handle_lock_event(char* buffer) { - bool is_locked = (buffer[4] == MSG_TYPE_LOCK); - - // Add message validation logging - LOGI("Received lock event: %s (msg_type=%d)", is_locked ? "LOCK" : "UNLOCK", - buffer[4]); - - // Log buffer contents for debugging - char hex_buffer[64] = {0}; - for (int i = 0; i < 7 && i < 20; i++) { - sprintf(hex_buffer + (i * 3), "%02X ", (unsigned char)buffer[i]); - } - LOGD("Lock message buffer: %s", hex_buffer); - - pthread_mutex_lock(&kb_mutex); - // Update global lock state - device_is_locked = is_locked; - - if (is_locked) { - LOGI("Lock event with current kb_status=%d", kb_status); - - if (kb_status) { - // Check device status before attempting to change state - if (fd >= 0) { - // Check if device is writable - int flags = fcntl(fd, F_GETFL); - if (flags != -1 && (flags & O_RDWR)) { - LOGI( - "Device is opened with read-write access, attempting to disable " - "keyboard"); - set_kb_state(false, true); +int calculateAngle(float kX, float kY, float kZ, float pX, float pY, float pZ) { + float deviation2; + float deviation1; + float recipNorm = invSqrt((kX * kX) + (kY * kY) + (kZ * kZ)); + float kX2 = kX * recipNorm; + float kY2 = kY * recipNorm; + float kZ2 = kZ * recipNorm; + float recipNorm2 = invSqrt((pX * pX) + (pY * pY) + (pZ * pZ)); + float pX2 = pX * recipNorm2; + float pY2 = pY * recipNorm2; + float pZ2 = pZ * recipNorm2; + float min_deviation = 100.0f; + int min_deviation_angle = 0; + for (int i = 0; i <= 360; i++) { + if (i > 90) { + if (i > 90 && i <= 180) { + float deviation12 = (((-angle_cos[180 - i]) * kX2) - + (angle_sin[180 - i] * kZ2)) + + pX2; + deviation2 = ((-angle_cos[180 - i]) * kZ2) + + (angle_sin[180 - i] * kX2) + pZ2; + deviation1 = deviation12; + } else if (i > 180 && i <= 270) { + float deviation13 = (((-angle_cos[i - 180]) * kX2) - + ((-angle_sin[i - 180]) * kZ2)) + + pX2; + deviation2 = ((-angle_cos[i - 180]) * kZ2) + + ((-angle_sin[i - 180]) * kX2) + pZ2; + deviation1 = deviation13; + } else { + float deviation14 = ((angle_cos[360 - i] * kX2) - + ((-angle_sin[360 - i]) * kZ2)) + + pX2; + deviation2 = (angle_cos[360 - i] * kZ2) + + ((-angle_sin[360 - i]) * kX2) + pZ2; + deviation1 = deviation14; + } } else { - LOGW("Device may not have write permissions (flags=%d)", flags); - set_kb_state(false, true); // Try anyway + float f = angle_cos[i]; + float f2 = angle_sin[i]; + float deviation15 = ((f * kX2) - (f2 * kZ2)) + pX2; + deviation2 = (f * kZ2) + (f2 * kX2) + pZ2; + deviation1 = deviation15; } - } else { - LOGE("Invalid file descriptor when handling lock event (fd=%d)", fd); - } - - LOGI("Device locked - disabling keyboard"); - } else { - LOGI("Device locked but keyboard already disabled"); - } - } else { - // Restore previous state if keyboard is connected - LOGI("Unlock event, checking keyboard presence"); - bool keyboard_present = (access(EVENT_PATH, F_OK) != -1); - LOGI("Keyboard %s on unlock", keyboard_present ? "present" : "not present"); - - if (keyboard_present) { - // Same device check as above - if (fd >= 0) { - LOGI("Attempting to enable keyboard on unlock"); - set_kb_state(true, true); - } else { - LOGE("Invalid file descriptor when handling unlock event (fd=%d)", fd); - - // Try to recover the file descriptor - fd = open(NANODEV_PATH, O_RDWR); - if (fd != -1) { - LOGI("Reopened device file on unlock, attempting to enable keyboard"); - set_kb_state(true, true); + if (abs(deviation1) + abs(deviation2) < min_deviation) { + float min_deviation2 = abs(deviation1) + abs(deviation2); + min_deviation_angle = i; + min_deviation = min_deviation2; } - } - - LOGI("Device unlocked - re-enabling keyboard"); - } else { - LOGW("Not enabling keyboard on unlock - device not present"); } - } - pthread_mutex_unlock(&kb_mutex); -} - -float calculateAngle(float kX, float kY, float kZ, float padX, float padY, - float padZ) { - float32x4_t a = {kX, kY, kZ, 0.0f}; - float32x4_t b = {padX, padY, padZ, 0.0f}; - - // Dot product - float32x4_t prod = vmulq_f32(a, b); - float dot = vgetq_lane_f32(prod, 0) + vgetq_lane_f32(prod, 1) + - vgetq_lane_f32(prod, 2); - - // Norm of a - float32x4_t a2 = vmulq_f32(a, a); - float norm_a_sq = - vgetq_lane_f32(a2, 0) + vgetq_lane_f32(a2, 1) + vgetq_lane_f32(a2, 2); - float norm_a = neon_sqrtf(norm_a_sq); - - // Norm of b - float32x4_t b2 = vmulq_f32(b, b); - float norm_b_sq = - vgetq_lane_f32(b2, 0) + vgetq_lane_f32(b2, 1) + vgetq_lane_f32(b2, 2); - float norm_b = neon_sqrtf(norm_b_sq); - - if (norm_a == 0.0f || norm_b == 0.0f) return 0.0f; - - float cos_theta = dot / (norm_a * norm_b); - float angle = fast_acosf(cos_theta) * (180.0f / M_PI); - - return angle; -} - -void get_kb_accel(char* buffer) { - int x = ((buffer[7] << 4) & 4080) | ((buffer[6] >> 4) & 15); - int y = ((buffer[9] << 4) & 4080) | ((buffer[8] >> 4) & 15); - int z = ((buffer[11] << 4) & 4080) | ((buffer[10] >> 4) & 15); - - if ((x & 2048) == 2048) x = -(4096 - x); - if ((y & 2048) == 2048) y = -(4096 - y); - if ((z & 2048) == 2048) z = -(4096 - z); - - float x_normal = (x * 9.8f) / 256.0f; - float y_normal = ((-y) * 9.8f) / 256.0f; - float z_normal = ((-z) * 9.8f) / 256.0f; - - float scale = 9.8f / neon_sqrtf(x_normal * x_normal + y_normal * y_normal + - z_normal * z_normal); - - pthread_mutex_lock(&sensor_mutex); - kbX = x_normal * scale; - kbY = y_normal * scale; - kbZ = z_normal * scale; - pthread_mutex_unlock(&sensor_mutex); -} - -void handle_accel_event(char* buffer) { - float local_padX, local_padY, local_padZ; - float local_kbX, local_kbY, local_kbZ; - float last_kbX = 0.0f, last_kbY = 0.0f, last_kbZ = 0.0f; - const float vector_threshold = 0.04f; - - get_kb_accel(buffer); - - pthread_mutex_lock(&sensor_mutex); - local_padX = padX; - local_padY = padY; - local_padZ = padZ; - local_kbX = kbX; - local_kbY = kbY; - local_kbZ = kbZ; - pthread_mutex_unlock(&sensor_mutex); - - float dx = local_kbX - last_kbX; - float dy = local_kbY - last_kbY; - float dz = local_kbZ - last_kbZ; - - float delta = dx * dx + dy * dy + dz * dz; - - if (delta > vector_threshold) { - float angle = calculateAngle(local_kbX, local_kbY, local_kbZ, local_padX, - local_padY, local_padZ); - set_kb_state(!(angle >= 120), false); - - last_kbX = local_kbX; - last_kbY = local_kbY; - last_kbZ = local_kbZ; - } -} - -/** - * Main event handler - dispatches to appropriate handler based on message type - */ -void handle_event(char* buffer, ssize_t bytes_read) { - pthread_mutex_lock(&angle_detection_mutex); - bool angle_detection_enabled_local = angle_detection_enabled; - pthread_mutex_unlock(&angle_detection_mutex); - - // Basic validation - if (bytes_read < 7 || buffer[1] != MSG_HEADER_1 || - buffer[2] != MSG_HEADER_2) { - return; - } - - // Handle message based on type - if (buffer[4] == MSG_TYPE_SLEEP || buffer[4] == MSG_TYPE_WAKE) { - if (buffer[5] == 1) { - handle_power_event(buffer); + float accel_angle_error = abs(pY2) > abs(kY2) ? abs(pY2) : abs(kY2); + if (accel_angle_error > 0.98f) { + return -1; } - } else if (buffer[4] == MSG_TYPE_LOCK || buffer[4] == MSG_TYPE_UNLOCK) { - handle_lock_event(buffer); - } else if (buffer[4] == MSG_TYPE_MOVEMENT && angle_detection_enabled_local) { - LOGI("angle_detection_enabled: %d", angle_detection_enabled_local); - handle_accel_event(buffer); - } + printf("Angle: %d, status: %d\n", min_deviation_angle, kb_status); + return min_deviation_angle; } -/** - * Attempt to reconnect to the device with exponential backoff - * Returns: file descriptor on success, -1 on failure - */ -int reconnect_device() { - int attempts = 0; - const int max_attempts = 5; // Reduced from 10 - int new_fd = -1; +void set_kb_state(bool value, bool force) { + printf("set_kb called, new value: %d\n", value); + if (kb_status == value && !force) + return; + kb_status = value; + printf("set_kb called, setting new value: %d\n", value); + unsigned char buf[3] = {0x32, 0xFF, value}; + write(fd, &buf, 3); +} - LOGI("Starting device reconnection procedure to %s", NANODEV_PATH); +void acc_handle(char *buffer) { + int x = ((buffer[7] << 4) & 4080) | ((buffer[6] >> 4) & 15); + int y = ((buffer[9] << 4) & 4080) | ((buffer[8] >> 4) & 15); + int z = ((buffer[11] << 4) & 4080) | ((buffer[10] >> 4) & 15); - // Check if device exists - if (access(NANODEV_PATH, F_OK) != 0) { - LOGE("Device file %s does not exist: %s", NANODEV_PATH, strerror(errno)); - } else { - LOGI("Device file exists, checking permissions"); - // Check permissions - if (access(NANODEV_PATH, R_OK | W_OK) != 0) { - LOGE("Insufficient permissions for device: %s", strerror(errno)); - } else { - LOGI("Device has read/write permissions"); - } - } - - while (attempts < max_attempts && new_fd == -1 && !terminate) { - LOGI("Reconnect attempt %d/%d", attempts + 1, max_attempts); - - // Log current process permissions - uid_t uid = getuid(); - gid_t gid = getgid(); - LOGI("Current process: uid=%d, gid=%d, euid=%d, egid=%d", uid, gid, - geteuid(), getegid()); - - new_fd = open(NANODEV_PATH, O_RDWR); - - if (new_fd != -1) { - LOGI("Successfully reconnected to device (fd=%d)", new_fd); - return new_fd; - } else { - LOGE("Failed to open device: %s (errno=%d)", strerror(errno), errno); + if ((x & 2048) == 2048) { + x = -(4096 - x); } - // Simplified backoff: 1s, 2s, 4s, 4s, 4s - int sleep_time = (attempts < 3) ? (1 << attempts) : 4; - LOGI("Sleeping for %d seconds before next attempt", sleep_time); - sleep(sleep_time); - attempts++; - } + if ((y & 2048) == 2048) { + y = -(4096 - y); + } - LOGE("Failed to reconnect after %d attempts", attempts); - return -1; + if ((z & 2048) == 2048) { + z = -(4096 - z); + } + + float x_normal = (x * 9.8f) / 256.0f; + float y_normal = ((-y) * 9.8f) / 256.0f; + float z_normal = ((-z) * 9.8f) / 256.0f; + + // Read tablet acc + if (read_acc()) { + LOGE("Failed to read acc"); + return; + } + + kbX = x_normal; + kbY = y_normal; + kbZ = z_normal; + + int angle = calculateAngle(x_normal, y_normal, z_normal, padX, padY, padZ); + set_kb_state(!(angle > 230 || angle < 40), false); } -// Add signal handler for graceful termination -void signal_handler(int signum) { - LOGI("Caught signal %d, terminating...", signum); - terminate = 1; +void *acc_thread_func(void *arg) { + while (1) { + // Check if the event file exists + if (access(EVENT_PATH, F_OK) != -1 || !kb_status) { + pthread_mutex_lock(&acc_mutex); + while (acc_paused) { + // Wait for the condition signal to resume + pthread_cond_wait(&acc_cond, &acc_mutex); + } + pthread_mutex_unlock(&acc_mutex); + // Read accelerometer data + if (read_acc() == 0) { + // Calculate the angle + int angle = calculateAngle(kbX, kbY, kbZ, padX, padY, padZ); + set_kb_state(!(angle > 230 || angle < 40), false); + } + } else { + usleep(3000000); + } + } + return NULL; } -// Use a cleanup function for consistent resource release -void cleanup_resources(pthread_t monitor_thread, pthread_t watchdog_thread_id /*, pthread_t tab_sensor_thread, pthread_t kb_sensor_thread*/) { - LOGI("Performing cleanup..."); - - pthread_mutex_lock(&kb_mutex); - terminate = 1; - pthread_cond_signal(&kb_cond); - pthread_mutex_unlock(&kb_mutex); - - pthread_join(monitor_thread, NULL); - if (watchdog_enabled && watchdog_thread_id != 0) { - pthread_join(watchdog_thread_id, NULL); - } - - if (fd != -1) { - close(fd); - fd = -1; - } - ASensorEventQueue_disableSensor(sensorQueue, accelerometer); - ASensorManager_destroyEventQueue(sensorManager, sensorQueue); -} - -#define VERSION_STRING "1.1.0" - -/** - * Main function - */ int main() { - // Add program start timestamp - time_t start_time = time(NULL); - struct tm* tm_info = localtime(&start_time); - char time_str[64]; - strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", tm_info); + ssize_t bytes_read; + char buffer[BUFFER_SIZE]; - LOGI("Xiaomi keyboard service v%s starting at %s", VERSION_STRING, time_str); - - // Load angle detection preference - load_angle_detection_preference(); - - ssize_t bytes_read; - char buffer[BUFFER_SIZE]; - - // Initialize log - LOG_IMPORTANT("Xiaomi keyboard service starting..."); - - // Dynamic path detection - EVENT_PATH = find_keyboard_input_path(); - LOGI("Using keyboard input path: %s", EVENT_PATH); - - // Open the nanodev device file - fd = open(NANODEV_PATH, O_RDWR); - if (fd == -1) { - LOGE("Error opening nanodev device: %s (errno=%d)", strerror(errno), errno); - - // Add more diagnostic information - if (access(NANODEV_PATH, F_OK) != 0) { - LOGE("Device file %s does not exist!", NANODEV_PATH); - } else { - LOGE("Device exists but cannot be opened. Checking permissions..."); - if (access(NANODEV_PATH, R_OK | W_OK) != 0) { - LOGE("Insufficient permissions for device %s", NANODEV_PATH); - } + if (init_sensors() != 0) { + LOGE("Failed to initialize sensors"); + return EXIT_FAILURE; } - return errno; - } - - LOGI("Successfully opened device file (fd=%d)", fd); - - // Get and log file status - struct stat st; - if (fstat(fd, &st) == 0) { - LOGI("Device file info: mode=%o, size=%lld, uid=%d, gid=%d", st.st_mode, - (long long)st.st_size, st.st_uid, st.st_gid); - } - - // Check current keyboard status - if (access(EVENT_PATH, F_OK) == -1) { - kb_status = false; - LOGW("Keyboard input device not found, starting disabled"); - } else { - // Only enable if the device is not locked - if (!device_is_locked) { - LOGI("Keyboard input device found and device unlocked, starting enabled"); - set_kb_state(true, true); - } else { - LOGI("Keyboard input device found but device locked, starting disabled"); - kb_status = false; + // Open the device file for reading + fd = open(NANODEV_PATH, O_RDWR); + if (fd == -1) { + LOGE("Error opening device"); + return errno; } - } - // Create the keyboard monitor thread - pthread_t monitor_thread; - if (pthread_create(&monitor_thread, NULL, keyboard_monitor_thread, NULL) != - 0) { - LOGE("Failed to create keyboard monitor thread"); + // Check current kb status + if (access(EVENT_PATH, F_OK) == -1) + kb_status = false; + + // Create the accelerometer thread + pthread_t acc_thread; + if (pthread_create(&acc_thread, NULL, acc_thread_func, NULL) != 0) { + LOGE("Failed to create accelerometer thread"); + return EXIT_FAILURE; + } + + // Main loop + while (1) { + // Read data from the device + bytes_read = read(fd, buffer, BUFFER_SIZE); + if (bytes_read > 0) { + if (buffer[0] != 34 && buffer[0] != 35 && buffer[0] != 36 && + buffer[0] != 38) + continue; + + if (buffer[1] == 0x31 && buffer[2] == 0x38) { + if (buffer[4] == 100) { + acc_handle(buffer); + } else if (buffer[4] == 37 || buffer[4] == 40) { + if (buffer[5] != 1) + continue; + if (buffer[6] == 1) { + LOGI("Got sleap event: unsleap"); + pthread_mutex_lock(&acc_mutex); + acc_paused = false; + pthread_cond_signal( + &acc_cond); // Signal the condition variable to wake + // up the thread + pthread_mutex_unlock(&acc_mutex); + + // Restor input device state + set_kb_state(kb_status, true); + } else { + LOGI("Got sleap event: sleap"); + pthread_mutex_lock(&acc_mutex); + acc_paused = true; + pthread_mutex_unlock(&acc_mutex); + } + } + } + } else if (bytes_read == 0) { + // No data, you might want to sleep for a bit + sleep(1); + } else { + // An error occurred + LOGE("Error reading device"); + break; + } + } + + // Join the thread when done + pthread_join(acc_thread, NULL); + + // Close the device file close(fd); - return EXIT_FAILURE; - } - - // At the top of main(): - pthread_t watchdog_thread_id = 0; - - // Replace watchdog thread creation with: - if (watchdog_enabled) { - if (pthread_create(&watchdog_thread_id, NULL, watchdog_thread_func, NULL) != - 0) { - LOGW("Failed to create watchdog thread - continuing without watchdog"); - watchdog_enabled = false; - } - } else { - LOGI("Watchdog disabled by configuration"); - } - - // Create sensor thread - pthread_t sensor_thread; - pthread_create(&sensor_thread, NULL, accelerometer_thread, NULL); - pthread_detach(sensor_thread); - - // Create the preference watching thread - pthread_t preference_thread; - pthread_create(&preference_thread, NULL, preference_watcher_thread, NULL); - pthread_detach(preference_thread); - - // Set up signal handling - signal(SIGINT, signal_handler); - signal(SIGTERM, signal_handler); - - // Consider adding a maximum number of recoveries - int recoveries = 0; - const int MAX_RECOVERIES = 3; - - // Main loop for keyboard events - LOGI("Main loop starting, ready to receive keyboard events"); - while (!terminate) { - // Read data from the device - bytes_read = read(fd, buffer, BUFFER_SIZE); - - if (bytes_read > 0) { - // Reset recovery counter after successful read - recoveries = 0; - // Process the message - handle_event(buffer, bytes_read); - } else if (bytes_read == 0) { - // No data available, sleep before trying again - usleep(500000); // 500ms - } else { - // Read error occurred - LOGE("Error reading device: %s", strerror(errno)); - - // Check if we've exceeded recovery limit - if (++recoveries > MAX_RECOVERIES) { - LOGE("Exceeded maximum recovery attempts, exiting"); - break; - } - - // Close the current file descriptor - close(fd); - - // Try to reconnect with backoff - fd = reconnect_device(); - - // If reconnection failed, exit the loop - if (fd == -1) { - LOGE("Could not recover device connection, exiting"); - break; - } - } - } - - // Final status report before exit - time_t end_time = time(NULL); - double runtime = difftime(end_time, start_time); - LOGI("Service exiting after running for %.1f seconds", runtime); - - // Cleanup - cleanup_resources(monitor_thread, watchdog_thread_id); - - return 0; -} \ No newline at end of file + return 0; +} diff --git a/peripheralmanager/xiaomi-pen.cpp b/peripheralmanager/xiaomi-pen.cpp index f9d55f7..be99845 100644 --- a/peripheralmanager/xiaomi-pen.cpp +++ b/peripheralmanager/xiaomi-pen.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023-2025 The LineageOS Project + * Copyright (C) 2023 The LineageOS Project * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,12 +8,7 @@ #include #include #include -#include -#include -#define VERSION_STRING "1.0.0" - -// Device control definitions #define SET_CUR_VALUE 0 #define TOUCH_PEN_MODE 20 #define TOUCH_MAGIC 't' @@ -21,41 +16,12 @@ #define TOUCH_DEV_PATH "/dev/xiaomi-touch" int main(int argc, char **argv) { - // Validate arguments if(argc != 2) { - fprintf(stderr, "Xiaomi pen utility v%s\n", VERSION_STRING); fprintf(stderr, "Usage: %s \n", argv[0]); return -1; } - - // Open the touch device int fd = open(TOUCH_DEV_PATH, O_RDWR); - if (fd < 0) { - fprintf(stderr, "Error opening device %s: %s\n", - TOUCH_DEV_PATH, strerror(errno)); - return -1; - } - - // Parse the input value - int value = atoi(argv[1]); - if (value < 0 || value > 20) { - fprintf(stderr, "Warning: Value %d outside normal range (0-20)\n", value); - } - fprintf(stdout, "Setting pen mode to: %d\n", value); - - // Prepare and send the command - int arg[2] = {TOUCH_PEN_MODE, value}; - int result = ioctl(fd, TOUCH_IOC_SETMODE, &arg); - - // Check for errors - if (result < 0) { - fprintf(stderr, "Error setting pen mode: %s\n", strerror(errno)); - close(fd); - return -1; - } - - // Clean up + int arg[2] = {TOUCH_PEN_MODE, atoi(argv[1])}; + ioctl(fd, TOUCH_IOC_SETMODE, &arg); close(fd); - fprintf(stdout, "Pen mode set successfully\n"); - return 0; } diff --git a/rootdir/etc/init.device.rc b/rootdir/etc/init.device.rc index c27e96d..b30f0ed 100644 --- a/rootdir/etc/init.device.rc +++ b/rootdir/etc/init.device.rc @@ -30,7 +30,3 @@ service xiaomi-keyboard /vendor/bin/xiaomi-keyboard on property:persist.vendor.parts.pen=* start xiaomi-pen - -on post-data-fs - exec - system system -- /system/bin/touch /data/misc/xiaomi_keyboard.conf - exec - system system -- /system/bin/restorecon /data/misc/xiaomi_keyboard.conf diff --git a/sepolicy/vendor/file.te b/sepolicy/vendor/file.te deleted file mode 100644 index 46c09ae..0000000 --- a/sepolicy/vendor/file.te +++ /dev/null @@ -1 +0,0 @@ -type xiaomi_keyboard_conf_file, file_type; \ No newline at end of file diff --git a/sepolicy/vendor/file_contexts b/sepolicy/vendor/file_contexts index 29a65d1..fd2e0ea 100644 --- a/sepolicy/vendor/file_contexts +++ b/sepolicy/vendor/file_contexts @@ -9,5 +9,3 @@ # Xiaomi Keyboard /dev/nanodev0 u:object_r:xiaomi_keyboard_device:s0 - -/data/vendor/xiaomi_keyboard.conf u:object_r:xiaomi_keyboard_conf_file:s0 diff --git a/sepolicy/vendor/servicemanager.te b/sepolicy/vendor/servicemanager.te deleted file mode 100644 index b6ced0a..0000000 --- a/sepolicy/vendor/servicemanager.te +++ /dev/null @@ -1 +0,0 @@ -allow servicemanager xiaomi_keyboard:binder call; diff --git a/sepolicy/vendor/system_app.te b/sepolicy/vendor/system_app.te index 89a7d36..cc5ce3e 100644 --- a/sepolicy/vendor/system_app.te +++ b/sepolicy/vendor/system_app.te @@ -1,2 +1 @@ set_prop(system_app, vendor_pen_prop) -allow system_app xiaomi_keyboard_conf_file:file { read write open getattr }; \ No newline at end of file diff --git a/sepolicy/vendor/xiaomi_keyboard.te b/sepolicy/vendor/xiaomi_keyboard.te index e592c8e..332025e 100644 --- a/sepolicy/vendor/xiaomi_keyboard.te +++ b/sepolicy/vendor/xiaomi_keyboard.te @@ -9,20 +9,8 @@ get_prop(xiaomi_keyboard, hwservicemanager_prop) binder_call(xiaomi_keyboard, hwservicemanager) binder_call(xiaomi_keyboard, system_server) -# Enhanced permissions for keyboard device -allow xiaomi_keyboard xiaomi_keyboard_device:chr_file { getattr open read write ioctl }; +allow xiaomi_keyboard xiaomi_keyboard_device:chr_file { open read write }; allow xiaomi_keyboard fwk_sensor_hwservice:hwservice_manager find; allow xiaomi_keyboard fwk_sensor_service:service_manager find; - -# Enhanced input device permissions -allow xiaomi_keyboard input_device:dir { read search open }; -allow xiaomi_keyboard input_device:file { read open getattr }; +allow xiaomi_keyboard input_device:dir search; allow xiaomi_keyboard servicemanager:binder { call transfer }; - -# Additional diagnostic permissions -allow xiaomi_keyboard sysfs:dir { read open }; -allow xiaomi_keyboard sysfs_devices_system_cpu:file { read open }; - -allow xiaomi_keyboard xiaomi_keyboard_conf_file:file { read open }; - -typeattribute xiaomi_keyboard_conf_file data_file_type;