Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,30 @@ AF stands for Ad-Free

##

### Accessibility Intents

Olauncher exposes two intents that allow external apps (such as physical key mappers or accessibility services) to trigger launcher actions without touch input.

| Intent Action | Description |
|---|---|
| `app.olauncher.ACTION_OPEN_APP_DRAWER` | Opens the app drawer from the home screen |
| `app.olauncher.ACTION_DISMISS_KEYGUARD` | Shows the PIN/pattern/password entry to unlock the device (Android 8.0+) |

**ADB example:**
```bash
adb shell am start -a app.olauncher.ACTION_OPEN_APP_DRAWER -n app.olauncher/.MainActivity
adb shell am start -a app.olauncher.ACTION_DISMISS_KEYGUARD -n app.olauncher/.MainActivity
```

**Android example (Kotlin):**
```kotlin
val intent = Intent("app.olauncher.ACTION_OPEN_APP_DRAWER")
intent.setPackage("app.olauncher")
startActivity(intent)
```

##

License: [GNU GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html)

Dev: [X/twitter](https://x.com/tanujnotes) • [Bluesky](https://bsky.app/profile/tanujnotes.bsky.social)
Expand Down
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ android {
debuggable true
minifyEnabled false
applicationIdSuffix ".debug"
resValue "string", "app_name", "Olauncher (Debug)"
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="app.olauncher.ACTION_OPEN_APP_DRAWER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="app.olauncher.ACTION_DISMISS_KEYGUARD" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>

<activity
Expand Down
31 changes: 31 additions & 0 deletions app/src/main/java/app/olauncher/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package app.olauncher

import android.annotation.SuppressLint
import android.app.Activity
import android.app.KeyguardManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
Expand Down Expand Up @@ -109,6 +110,8 @@ class MainActivity : AppCompatActivity() {

window.addFlags(FLAG_LAYOUT_NO_LIMITS)

handleIntentAction(intent)

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
profileReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Expand Down Expand Up @@ -147,6 +150,11 @@ class MainActivity : AppCompatActivity() {
}

override fun onNewIntent(intent: Intent?) {
if (handleIntentAction(intent)) {
super.onNewIntent(intent)
return
}

val alreadyHome = navController.currentDestination?.id == R.id.mainFragment
backToHomeScreen()
if (alreadyHome && isResumed && prefs.homeButtonShowRecents)
Expand Down Expand Up @@ -332,6 +340,29 @@ class MainActivity : AppCompatActivity() {
navController.popBackStack(R.id.mainFragment, false)
}

private fun dismissKeyguard() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
keyguardManager.requestDismissKeyguard(this, null)
}
}

private fun handleIntentAction(intent: Intent?): Boolean {
return when (intent?.action) {
Constants.ACTION_OPEN_APP_DRAWER -> {
viewModel.showAppDrawer.call()
true
}

Constants.ACTION_DISMISS_KEYGUARD -> {
dismissKeyguard()
true
}

else -> false
}
}

private fun setPlainWallpaper() {
if (this.isDarkThemeOn())
setPlainWallpaper(this, android.R.color.black)
Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/app/olauncher/MainViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
val checkForMessages = SingleLiveEvent<Unit?>()
val resetLauncherLiveData = SingleLiveEvent<Unit?>()
val showRecentApps = SingleLiveEvent<Unit?>()
val showAppDrawer = SingleLiveEvent<Unit?>()

fun selectedApp(appModel: AppModel, flag: Int) {
if (appModel is AppModel.PrivateSpaceHeader) return
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/java/app/olauncher/data/Constants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ object Constants {
const val URL_DUCK_SEARCH = "https://duck.co/?q="
const val URL_DIGITAL_WELLBEING_LEARN_MORE = "https://tanujnotes.substack.com/p/digital-wellbeing-app-on-android?utm_source=olauncher"

const val ACTION_OPEN_APP_DRAWER = "app.olauncher.ACTION_OPEN_APP_DRAWER"
const val ACTION_DISMISS_KEYGUARD = "app.olauncher.ACTION_DISMISS_KEYGUARD"

const val DIGITAL_WELLBEING_PACKAGE_NAME = "com.google.android.apps.wellbeing"
const val DIGITAL_WELLBEING_ACTIVITY = "com.google.android.apps.wellbeing.settings.TopLevelSettingsActivity"
const val DIGITAL_WELLBEING_SAMSUNG_PACKAGE_NAME = "com.samsung.android.forest"
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/java/app/olauncher/ui/HomeFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,9 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener
viewModel.showRecentApps.observe(viewLifecycleOwner) {
binding.recents.performClick()
}
viewModel.showAppDrawer.observe(viewLifecycleOwner) {
showAppList(Constants.FLAG_LAUNCH_APP)
}
}

private fun initSwipeTouchListener() {
Expand Down