|
|||||||
![]() |
|
|
Thread Tools | Search this Thread |
|
|
#1 |
|
Junior Member
![]() Posts: 3
Karma: 10
Join Date: Feb 2024
Device: none
|
[Guide] Add a physical-button dark mode toggle to the Nook GlowLight 4 (stock reader,
I cross-posted this on Nook's subreddit as well if you prefer formatting over there - https://www.reddit.com/r/nook/commen...ode_toggle_to/
I wanted a quick way to switch between normal reading and dark mode on my Nook GlowLight 4 without installing a different reading app. With ChatGPT's help I ended up building a small Android APK that lets me **hold the upper-left page-turn button for 1.5 seconds to toggle system-wide color inversion**. I've tested the APK on GlowLight 4 and GlowLight 4+ devices (BNRV1100, BNRV1300), and it works with the **stock Barnes & Noble reading app**. No root required. ## What it does - Short press of the upper-left button: normal page turn. - Long press (1.5 seconds): toggles dark mode. - Long press again: returns to normal mode. - Works in the stock Nook reader, not just KOReader. - Works system-wide, including menus and other apps. **Important limitations:** This uses Android's accessibility color inversion rather than a true dark theme. Images, covers, and illustrations are inverted too. Also, holding the button still turns a page. The app deliberately doesn't block the stock reader from receiving the button press. ## Requirements - Nook GlowLight 4 (tested on BNRV1100) - A computer with Android Studio - Android SDK Platform Tools (ADB) - USB cable - USB debugging enabled on the Nook - Basic familiarity with Android Studio The project below uses Java and an Android AccessibilityService. ## Step 1: Create the Android Studio project Open Android Studio and create a new project. Choose **Empty Views Activity** (Java), or a basic Java Android project. Use: - Name: Nook Dark Mode - Package: `com.nook.darkmode` - Language: Java - Minimum SDK: API 27 (Android 8.1) For the project we tested, we used Android Gradle Plugin 8.1.4 and Gradle 8.5. The following files make up the application. ## Step 2: AndroidManifest.xml Replace the contents of: `app/src/main/AndroidManifest.xml` with: ```xml <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"> <uses-permission android:name="android.permission.WRITE_SECURE_SETT INGS" /> <application android:allowBackup="false" android:label="Nook Dark Mode" android:theme="@android:style/Theme.Material.Light.NoActionBar"> <activity android:name=".ToggleActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".ButtonAccessibilityService" android:label="Nook Dark Mode Buttons" android ermission="android.permission.BIND_ACCESS IBILITY_SERVICE"android:exported="true"> <intent-filter> <action android:name="android.accessibilityservice.Accessi bilityService" /> </intent-filter> <meta-data android:name="android.accessibilityservice" android:resource="@xml/button_accessibility" /> </service> </application> </manifest> ``` ## Step 3: Create the accessibility service configuration Create the folder if necessary: `app/src/main/res/xml/` Inside it, create: `button_accessibility.xml` Paste: ```xml <?xml version="1.0" encoding="utf-8"?> <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:accessibilityEventTypes="typeAllMask" android:accessibilityFeedbackType="feedbackGeneric " android:accessibilityFlags="flagRequestFilterKeyEv ents" android:canRequestFilterKeyEvents="true" android:notificationTimeout="100" /> ``` This allows the accessibility service to receive physical key events. ## Step 4: Create ButtonAccessibilityService.java Create: `app/src/main/java/com/nook/darkmode/ButtonAccessibilityService.java` Paste: ```java package com.nook.darkmode; import android.accessibilityservice.AccessibilityService; import android.provider.Settings; import android.os.Handler; import android.os.Looper; import android.util.Log; import android.view.KeyEvent; import android.view.accessibility.AccessibilityEvent; public class ButtonAccessibilityService extends AccessibilityService { private static final String TAG = "NookDarkModeButtons"; // Upper-left physical page-turn button private static final int TARGET_KEY = 140; // Long press duration private static final long LONG_PRESS_MS = 1500; private final Handler handler = new Handler(Looper.getMainLooper()); private boolean pressed = false; private boolean triggered = false; private final Runnable longPressAction = new Runnable() { @Override public void run() { if (pressed && !triggered) { triggered = true; toggleDarkMode(); } } }; @Override protected boolean onKeyEvent(KeyEvent event) { if (event.getKeyCode() != TARGET_KEY) { return false; } if (event.getAction() == KeyEvent.ACTION_DOWN) { if (!pressed) { pressed = true; triggered = false; handler.postDelayed( longPressAction, LONG_PRESS_MS ); } } else if (event.getAction() == KeyEvent.ACTION_UP) { pressed = false; handler.removeCallbacks(longPressAction); } // Let the stock Nook reader handle page turns return false; } private void toggleDarkMode() { try { int current = Settings.Secure.getInt( getContentResolver(), "accessibility_display_inversion_enabled", 0 ); int next = current == 0 ? 1 : 0; Settings.Secure.putInt( getContentResolver(), "accessibility_display_inversion_enabled", next ); Log.i(TAG, "Dark mode toggled: " + next); } catch (Exception e) { Log.e(TAG, "Failed to toggle dark mode", e); } } @Override public void onAccessibilityEvent( AccessibilityEvent event) { } @Override public void onInterrupt() { } @Override public void onDestroy() { handler.removeCallbacks(longPressAction); super.onDestroy(); } } ``` **Note:** The Android key code `140` was confirmed during testing on our devices. Other Nook models or firmware versions may use different key mappings. You can also change `LONG_PRESS_MS` to something shorter or longer. ## Step 5: Create ToggleActivity.java This is a simple launcher activity that toggles inversion when opened. It also provides a fallback if the physical-button shortcut isn't working. Create: `app/src/main/java/com/nook/darkmode/ToggleActivity.java` ```java package com.nook.darkmode; import android.app.Activity; import android.os.Bundle; import android.provider.Settings; import android.widget.Toast; public class ToggleActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); try { int current = Settings.Secure.getInt( getContentResolver(), "accessibility_display_inversion_enabled", 0 ); int next = current == 0 ? 1 : 0; boolean success = Settings.Secure.putInt( getContentResolver(), "accessibility_display_inversion_enabled", next ); Toast.makeText( this, success ? (next == 1 ? "Dark mode enabled" : "Dark mode disabled") : "Unable to change dark mode", Toast.LENGTH_SHORT ).show(); } catch (Exception e) { Toast.makeText( this, "Permission not granted", Toast.LENGTH_LONG ).show(); } finish(); } } ``` This activity is a minimal implementation of the same launcher-toggle behavior; the physical-button service is the part we tested directly. ## Step 6: Build the APK In Android Studio, select: **Build → Build Bundle(s) / APK(s) → Build APK(s)** Alternatively, use Terminal from the project directory: ```bash ./gradlew :app:assembleDebug ``` On my Mac, I needed to use Android Studio's bundled Java runtime rather than the system Java 8 installation: ```bash export JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home" ./gradlew :app:assembleDebug ``` The resulting APK should be located at: `app/build/outputs/apk/debug/app-debug.apk` ## Step 7: Install on the Nook Connect the Nook with USB debugging enabled. Verify the connection: ```bash adb devices ``` Install the APK: ```bash adb install -r app/build/outputs/apk/debug/app-debug.apk ``` Now grant the app permission to change Android's secure settings: ```bash adb shell pm grant com.nook.darkmode android.permission.WRITE_SECURE_SETTINGS ``` **This permission is essential.** Without it, the app cannot toggle system-wide color inversion. The permission cannot normally be granted through the regular app-permissions screen, which is why ADB is needed. ## Step 8: Enable the accessibility service Run: ```bash adb shell am start -a android.settings.ACCESSIBILITY_SETTINGS ``` Find **Nook Dark Mode Buttons** and enable it. If the Nook's settings interface doesn't expose the service, the following ADB commands can enable it: ```bash adb shell settings put secure enabled_accessibility_services com.nook.darkmode/com.nook.darkmode.ButtonAccessibilityService adb shell settings put secure accessibility_enabled 1 ``` Be careful if you already use other accessibility services: replacing `enabled_accessibility_services` can disable them. Preserve existing entries if needed. During testing, reinstalling the APK occasionally required restarting the accessibility service. ## Step 9: Test Open a book in the stock Barnes & Noble reader. Hold the upper-left physical page-turn button for about two seconds. The display should invert. Hold it again to restore normal colors. That's it! ## Troubleshooting **The button still turns pages but dark mode doesn't toggle** Verify that the accessibility service is enabled: ```bash adb shell settings get secure accessibility_enabled adb shell settings get secure enabled_accessibility_services ``` **The app is installed but cannot change colors** Regrant the secure-settings permission: ```bash adb shell pm grant com.nook.darkmode android.permission.WRITE_SECURE_SETTINGS ``` **I want to test inversion without the app** You can toggle the same Android setting manually: ```bash # Dark mode adb shell settings put secure accessibility_display_inversion_enabled 1 # Normal mode adb shell settings put secure accessibility_display_inversion_enabled 0 ``` **I want to see whether the app is detecting the button** Run: ```bash adb logcat -s NookDarkModeButtons:I '*:S' ``` When the toggle succeeds, you should see: ```text Dark mode toggled: 1 ``` or: ```text Dark mode toggled: 0 ``` **I have a different Nook model** You can investigate its physical buttons using: ```bash adb shell getevent -lp ``` Then monitor the appropriate input device: ```bash adb shell getevent -c 10 /dev/input/event0 ``` On the GlowLight 4 we tested, the upper-left button generated Linux `KEY_F21` events (hexadecimal `00bf`, decimal 191), which Android exposed to our accessibility service as key code `140`. Linux input codes and Android key codes are not interchangeable. You may need to log `KeyEvent.getKeyCode()` in the Java service to determine the correct value for your model. ## Final notes This is a small, standalone app. It doesn't replace the Nook reader, require root, or depend on KOReader. It does use an accessibility service and a privileged settings permission, so only install APKs from sources you trust. Building the APK yourself lets you inspect the code before installing it. The main drawback is that a long press also triggers a page turn. That could potentially be improved in a future version, but I preferred keeping the stock reader's normal page-turn behavior intact. |
|
|
|
![]() |
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Nook Glowlight 4 Plus Out of Stock | Lunar Ronin | Barnes & Noble NOOK | 9 | 02-02-2024 03:30 PM |
| Improve Dark Mode Slider Button Contrast? | LKraus | Calibre | 2 | 04-26-2022 10:26 AM |
| Dark Mode Toggle | Futuregrace | Amazon Kindle | 61 | 06-22-2020 11:37 AM |
| Nook Glowlight Plus back in stock | rcentros | News | 8 | 07-05-2019 02:56 PM |
| can you add bolder fonts to the nook glowlight 4gb? | tallulah28 | Barnes & Noble NOOK | 12 | 10-25-2014 08:12 AM |