diff --git a/app/src/main/java/de/jrpie/android/launcher/Application.kt b/app/src/main/java/de/jrpie/android/launcher/Application.kt
index 88a0fb3..0a1c0e8 100644
--- a/app/src/main/java/de/jrpie/android/launcher/Application.kt
+++ b/app/src/main/java/de/jrpie/android/launcher/Application.kt
@@ -1,14 +1,22 @@
package de.jrpie.android.launcher
+import android.os.Build
+import android.os.Build.VERSION_CODES
import androidx.preference.PreferenceManager
+import de.jrpie.android.launcher.actions.TorchManager
import de.jrpie.android.launcher.preferences.LauncherPreferences
class Application : android.app.Application() {
+ var torchManager: TorchManager? = null
override fun onCreate() {
super.onCreate()
+ if (Build.VERSION.SDK_INT >= VERSION_CODES.M) {
+ torchManager = TorchManager(this)
+ }
+
val preferences = PreferenceManager.getDefaultSharedPreferences(this)
LauncherPreferences.init(preferences, this.resources)
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/de/jrpie/android/launcher/actions/LauncherAction.kt b/app/src/main/java/de/jrpie/android/launcher/actions/LauncherAction.kt
index 562ce44..05f8a13 100644
--- a/app/src/main/java/de/jrpie/android/launcher/actions/LauncherAction.kt
+++ b/app/src/main/java/de/jrpie/android/launcher/actions/LauncherAction.kt
@@ -5,10 +5,15 @@ import android.content.Intent
import android.content.SharedPreferences.Editor
import android.graphics.Rect
import android.graphics.drawable.Drawable
+import android.hardware.camera2.CameraAccessException
+import android.hardware.camera2.CameraCharacteristics
+import android.hardware.camera2.CameraManager
import android.media.AudioManager
+import android.os.Build
import android.os.SystemClock
import android.view.KeyEvent
import android.widget.Toast
+import de.jrpie.android.launcher.Application
import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.apps.AppFilter
import de.jrpie.android.launcher.apps.AppInfo.Companion.INVALID_USER
@@ -37,7 +42,7 @@ enum class LauncherAction(
"launcher:chooseFromFavorites",
R.string.list_other_list_favorites,
R.drawable.baseline_favorite_24,
- { context -> openAppsList(context, true)}
+ { context -> openAppsList(context, true) }
),
VOLUME_UP(
"launcher:volumeUp",
@@ -77,6 +82,12 @@ enum class LauncherAction(
R.drawable.baseline_lock_24px,
LauncherDeviceAdmin::lockScreen
),
+ TORCH(
+ "launcher:toggleTorch",
+ R.string.list_other_torch,
+ R.drawable.baseline_flashlight_on_24,
+ ::toggleTorch
+ ),
NOP("launcher:nop", R.string.list_other_nop, R.drawable.baseline_not_interested_24, {});
override fun invoke(context: Context, rect: Rect?): Boolean {
@@ -171,6 +182,19 @@ private fun audioVolumeDown(context: Context) {
}
/* End media player actions */
+private fun toggleTorch(context: Context) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ Toast.makeText(
+ context,
+ context.getString(R.string.alert_requires_android_m),
+ Toast.LENGTH_LONG
+ ).show()
+ return
+ }
+
+ (context.applicationContext as Application).torchManager?.toggleTorch(context)
+}
+
private fun expandNotificationsPanel(context: Context) {
/* https://stackoverflow.com/a/15582509 */
try {
diff --git a/app/src/main/java/de/jrpie/android/launcher/actions/TorchManager.kt b/app/src/main/java/de/jrpie/android/launcher/actions/TorchManager.kt
new file mode 100644
index 0000000..166373c
--- /dev/null
+++ b/app/src/main/java/de/jrpie/android/launcher/actions/TorchManager.kt
@@ -0,0 +1,91 @@
+package de.jrpie.android.launcher.actions
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.hardware.camera2.CameraAccessException
+import android.hardware.camera2.CameraCharacteristics
+import android.hardware.camera2.CameraManager
+import android.os.Build
+import android.os.Build.VERSION_CODES
+import android.os.Handler
+import android.os.Looper
+import android.widget.Toast
+import androidx.annotation.RequiresApi
+import de.jrpie.android.launcher.R
+
+@RequiresApi(VERSION_CODES.M)
+class TorchManager(context: Context) {
+
+ private val camera = getCameraId(context)
+ private var torchEnabled = false
+
+ private val torchCallback = object : CameraManager.TorchCallback() {
+ override fun onTorchModeChanged(cameraId: String, enabled: Boolean) {
+ synchronized(this@TorchManager) {
+ if (cameraId == camera) {
+ torchEnabled = enabled
+ }
+ }
+ }
+ }
+
+ init {
+ registerCallback(context)
+ }
+
+ private fun getCameraId(context: Context): String? {
+ val cameraManager =
+ context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
+
+ return cameraManager.cameraIdList.firstOrNull { c ->
+ cameraManager
+ .getCameraCharacteristics(c)
+ .get(CameraCharacteristics.FLASH_INFO_AVAILABLE) ?: false
+ }
+ }
+
+ private fun registerCallback(context: Context) {
+ val cameraManager =
+ context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
+
+ cameraManager.registerTorchCallback(
+ torchCallback,
+ Handler(Looper.getMainLooper())
+ )
+ }
+
+ fun toggleTorch(context: Context) {
+ synchronized(this) {
+ val cameraManager =
+ context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
+
+ if (camera == null) {
+ Toast.makeText(
+ context,
+ context.getString(R.string.alert_no_torch_found),
+ Toast.LENGTH_LONG
+ ).show()
+ return
+ }
+
+ try {
+ if (!torchEnabled && Build.VERSION.SDK_INT >= VERSION_CODES.TIRAMISU) {
+ cameraManager.turnOnTorchWithStrengthLevel(
+ camera,
+ cameraManager.getCameraCharacteristics(camera)
+ .get(CameraCharacteristics.FLASH_INFO_STRENGTH_MAXIMUM_LEVEL) ?: 1
+ )
+ } else {
+ cameraManager.setTorchMode(camera, !torchEnabled)
+ }
+
+ } catch (e: CameraAccessException) {
+ Toast.makeText(
+ context,
+ context.getString(R.string.alert_torch_access_exception),
+ Toast.LENGTH_LONG
+ ).show()
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/baseline_flashlight_on_24.xml b/app/src/main/res/drawable/baseline_flashlight_on_24.xml
new file mode 100644
index 0000000..e1326ae
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_flashlight_on_24.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 17bdff8..637dfd3 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -234,10 +234,13 @@
Settings
More options
Error: Can\'t expand status bar.\nThis action is using functionality that is not part of the published Android API. Unfortunately, it does not seem to work on your device.
+ This functionality requires Android 6.0 or later.
App hidden. You can make it visible again in settings.
Undo
Quick Settings
µLauncher needs to be a device admin in order to lock the screen.
This is required for the lock screen action.
Enable the lock screen action
+ No camera with torch detected.
+ Error: Can\'t access torch.