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;