Skip to content

Commit a94f1a0

Browse files
committed
Wake up faster, more reliably
1 parent 00e24e9 commit a94f1a0

File tree

7 files changed

+327
-163
lines changed

7 files changed

+327
-163
lines changed

README.md

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,27 +18,50 @@ While initially designed for an Android-based home security system, it's also pe
1818

1919
## Features
2020

21-
- Camera motion detection with adjustable sensitivity
22-
- Ambient light sensor for detecting lighting changes
23-
- Auto-unlock screen and launch your dashboard app
24-
- Automatic keyguard dismissal (works with swipe-to-unlock and no security)
25-
- **App preload for instant startup** - Optional background preloading for near-instant app appearance
26-
- Configurable notification sound on wake
27-
- Start at boot for set-and-forget operation
28-
- **Optimized for low-end devices** - Intelligent memory management and frame throttling
29-
- Zero-animation instant transitions for snappy responsiveness
30-
- Clean, simple UI with tablet layouts
31-
- Full accessibility support with TalkBack
21+
- **Motion detection** - Detects when you walk up using the camera or light sensor
22+
- **Automatic unlock** - Wakes up and unlocks your device (works with swipe-to-unlock or no lock screen security)
23+
- **Launch your favorite app** - Automatically opens your chosen app (Home Assistant, calendar, transit schedule, etc.)
24+
- **Fast startup** - Optional instant app loading so your app appears immediately
25+
- **Notification sound** - Optional sound to let you know the device has woken up
26+
- **Automatic start** - Starts working when you turn on your device, no need to open the app
27+
- **Works on budget devices** - Runs smoothly even on cheap tablets with limited memory
28+
- **Clean and simple** - Easy-to-use interface that works on both phones and tablets
29+
- **Accessibility support** - Works with TalkBack for vision-impaired users
3230

33-
## Permissions
31+
## Installation
3432

35-
On first launch, the app will request the following permissions:
33+
1. Download the latest APK file from the [Releases](../../releases) page
34+
2. On your Android device, open the downloaded APK file
35+
3. If prompted, allow installation from unknown sources
36+
4. Tap "Install"
37+
5. Once installed, open The Observer Effect and follow the setup prompts
3638

37-
- **Camera** - For motion detection
38-
- **Display over other apps** (SYSTEM_ALERT_WINDOW) - Required to reliably launch apps from background on Android 10+
39-
- **Battery optimization exemption** - For reliable background operation
39+
**Requires Android 8.0 or newer**
4040

41-
These permissions are essential for the app to function properly.
41+
## Getting Started
42+
43+
The Observer Effect is designed to be simple to use, even if you're not a technical user. Just install the app and follow the on-screen prompts.
44+
45+
### Permissions
46+
47+
**The app will automatically prompt you for the following permissions when you first launch it:**
48+
49+
- **Camera** - Allows the app to detect when you approach the device
50+
- **Display over other apps** - Lets the app wake up your device and launch your chosen app
51+
- **Battery optimization exemption** - Keeps the app running in the background so it can detect your presence
52+
53+
Simply tap "Allow" or "Grant" when prompted. These permissions are required for the app to work.
54+
55+
### Important: Background Management (Low-End Devices)
56+
57+
**If you have a budget tablet or low-end Android device**, you may need to manually allow the app to run in the background without being killed by the system. Without this setting, the app won't be able to detect your presence when the screen is off.
58+
59+
**How to allow background operation:**
60+
61+
- **AllWinner tablets**: Go to **Settings → Background Manage** and add The Observer Effect to the allowed apps list
62+
- **Other devices**: Look for settings like "Battery Management", "App Battery Saver", "Background Apps", or "Protected Apps" in your device settings and ensure The Observer Effect is allowed to run in the background
63+
64+
If you're not sure where to find this setting, search your device settings for "background" or "battery optimization" and look for The Observer Effect in the list.
4265

4366
## Performance
4467

@@ -60,7 +83,11 @@ The Observer Effect is optimized to run on a wide range of devices, from high-en
6083
- Disable app preload to save memory
6184
- Choose simple launch apps (launchers, calendars) over browsers
6285

63-
## Building
86+
---
87+
88+
## For Developers
89+
90+
### Building from Source
6491

6592
You are probably best off using Android Studio, but we have make targets too:
6693

@@ -70,7 +97,7 @@ make release # Build release APK → out/observer-effect-release.apk
7097
make sideload # Install via adb
7198
```
7299

73-
**Requirements:** Android 8.0+, JDK 17+
100+
**Requirements:** JDK 17+
74101

75102
## License
76103

app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
88
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
99
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
10+
<uses-permission android:name="android.permission.WAKE_LOCK" />
1011

1112
<uses-feature android:name="android.hardware.camera" android:required="false" />
1213
<uses-feature android:name="android.hardware.sensor.light" android:required="false" />

app/src/main/kotlin/com/observer/effect/LauncherActivity.kt

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import android.os.Build
88
import android.os.Bundle
99
import android.os.Handler
1010
import android.os.Looper
11+
import android.os.PowerManager
1112
import android.util.Log
1213
import android.view.WindowManager
1314

@@ -33,6 +34,16 @@ class LauncherActivity : Activity() {
3334
// This prevents hanging if target app never comes to foreground
3435
timeoutHandler.postDelayed(timeoutRunnable, FINISH_TIMEOUT_MS)
3536

37+
// Acquire a wake lock to ensure the screen turns on reliably
38+
// This is more robust than just relying on window flags
39+
val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
40+
val wakeLock =
41+
powerManager.newWakeLock(
42+
PowerManager.SCREEN_BRIGHT_WAKE_LOCK or PowerManager.ACQUIRE_CAUSES_WAKEUP,
43+
"ObserverEffect:LauncherWakeLock",
44+
)
45+
wakeLock.acquire(1 * 1000L /* 1 second */)
46+
3647
val targetPackage = intent.getStringExtra(EXTRA_TARGET_PACKAGE)
3748
Log.i(TAG, "LauncherActivity started for package: $targetPackage (API ${Build.VERSION.SDK_INT})")
3849

@@ -52,25 +63,36 @@ class LauncherActivity : Activity() {
5263
// Request keyguard dismissal
5364
val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as? KeyguardManager
5465
if (keyguardManager != null) {
55-
keyguardManager.requestDismissKeyguard(
56-
this,
57-
object : KeyguardManager.KeyguardDismissCallback() {
58-
override fun onDismissSucceeded() {
59-
Log.i(TAG, "Keyguard dismissed successfully")
60-
launchTargetApp()
61-
}
62-
63-
override fun onDismissError() {
64-
Log.e(TAG, "Keyguard dismiss error")
65-
launchTargetApp()
66-
}
67-
68-
override fun onDismissCancelled() {
69-
Log.w(TAG, "Keyguard dismiss cancelled")
70-
finish()
71-
}
72-
},
73-
)
66+
// Check if keyguard is actually locked
67+
val isKeyguardLocked = keyguardManager.isKeyguardLocked
68+
Log.d(TAG, "Keyguard locked state: $isKeyguardLocked")
69+
70+
if (isKeyguardLocked) {
71+
// Only request dismissal if keyguard is actually shown
72+
keyguardManager.requestDismissKeyguard(
73+
this,
74+
object : KeyguardManager.KeyguardDismissCallback() {
75+
override fun onDismissSucceeded() {
76+
Log.i(TAG, "Keyguard dismissed successfully")
77+
launchTargetApp()
78+
}
79+
80+
override fun onDismissError() {
81+
Log.e(TAG, "Keyguard dismiss error")
82+
launchTargetApp()
83+
}
84+
85+
override fun onDismissCancelled() {
86+
Log.w(TAG, "Keyguard dismiss cancelled")
87+
finish()
88+
}
89+
},
90+
)
91+
} else {
92+
// Keyguard not locked, launch app immediately
93+
Log.d(TAG, "Keyguard not locked, launching app immediately")
94+
launchTargetApp()
95+
}
7496
} else {
7597
Log.e(TAG, "KeyguardManager not available, launching app anyway")
7698
launchTargetApp()

app/src/main/kotlin/com/observer/effect/MainActivity.kt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,6 @@ class MainActivity : AppCompatActivity() {
9393
val notificationSound = prefs.getString(KEY_NOTIFICATION_SOUND, "") ?: ""
9494

9595
with(binding) {
96-
// Set build type indicator
97-
val isDebug = (applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE) != 0
98-
buildTypeIndicator?.text = if (isDebug) "[D]" else "[R]"
99-
10096
// Setup camera spinner
10197
val cameraOptions =
10298
arrayOf(

0 commit comments

Comments
 (0)