pipa: peripheralmanager: Implement a toggle for kb angle detection

This commit is contained in:
Roman Lubij
2025-06-30 23:11:55 +02:00
committed by gensis01
parent 5626759888
commit cb92741ec1
7 changed files with 253 additions and 6 deletions

View File

@@ -43,5 +43,18 @@
android:resource="@string/stylus_summary" />
</activity>
<activity
android:name=".KeyboardSettingsActivity"
android:label="@string/keyboard_title"
android:theme="@style/Theme.SubSettingsBase">
<intent-filter>
<action android:name="com.android.settings.action.IA_SETTINGS" />
</intent-filter>
<meta-data android:name="com.android.settings.category"
android:value="com.android.settings.category.ia.connect" />
<meta-data android:name="com.android.settings.summary"
android:resource="@string/keyboard_summary" />
</activity>
</application>
</manifest>

View File

@@ -14,4 +14,10 @@
<string name="stylus_switch_title">Force recognize stylus</string>
<string name="stylus_switch_summary">Enable this settings to allow using third party styluses</string>
<!-- Xiaomi Stylus -->
<string name="keyboard_title">Keyboard</string>
<string name="keyboard_summary">Keyboard Settings</string>
<string name="keyboard_switch_title">Toggle angle detection</string>
<string name="keyboard_switch_summary">This toggles the angle detection of the keyboard</string>
</resources>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2018 The LineageOS Project
Licensed under the Apache License, Version 2.0 (the "License"
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/stylus_title">
<SwitchPreference
android:key="keyboard_switch_key"
android:defaultValue="true"
android:title="@string/keyboard_switch_title"
android:summary="@string/keyboard_switch_summary"/>
</PreferenceScreen>

View File

@@ -0,0 +1,33 @@
/*
* 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();
}
}

View File

@@ -0,0 +1,125 @@
/*
* 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()) + "] ";
}
}

View File

@@ -93,16 +93,42 @@ 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;
// Add a default config that can be used instead of parsing a file
const bool DEFAULT_WATCHDOG_ENABLED = true;
// Angle detection enable flag
bool angle_detection_enabled = false; // Default value
// Constants
#define POLL_INTERVAL_MS 500 // How often to poll
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;
@@ -135,7 +161,7 @@ void* accelerometer_thread(void* args) {
ASensor_getMinDelay(accelerometer));
while (!terminate) {
ALooper_pollOnce(POLL_INTERVAL_MS, NULL, NULL, NULL);
ALooper_pollOnce(500, NULL, NULL, NULL);
if (terminate) break;
ASensorEvent event;
@@ -572,6 +598,10 @@ void handle_accel_event(char* buffer) {
* 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) {
@@ -585,7 +615,8 @@ void handle_event(char* buffer, ssize_t bytes_read) {
}
} else if (buffer[4] == MSG_TYPE_LOCK || buffer[4] == MSG_TYPE_UNLOCK) {
handle_lock_event(buffer);
} else if (buffer[4] == MSG_TYPE_MOVEMENT) {
} else if (buffer[4] == MSG_TYPE_MOVEMENT && angle_detection_enabled_local) {
LOGI("angle_detection_enabled: %d", angle_detection_enabled_local);
handle_accel_event(buffer);
}
}
@@ -685,6 +716,9 @@ int main() {
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];
@@ -765,6 +799,11 @@ int main() {
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);

View File

@@ -30,3 +30,7 @@ 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