Register Guidelines E-Books Today's Posts Search

Go Back   MobileRead Forums > E-Book Readers > Barnes & Noble NOOK

Notices

Reply
 
Thread Tools Search this Thread
Old Yesterday, 06:45 PM   #1
kalkn
Junior Member
kalkn began at the beginning.
 
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"
androidermission="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.
kalkn is offline   Reply With Quote
Reply


Forum Jump

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


All times are GMT -4. The time now is 03:23 PM.


MobileRead.com is a privately owned, operated and funded community.