Skip to content

Commit

Permalink
Merge pull request #1242 from keymapperorg/feature/1229-target-androi…
Browse files Browse the repository at this point in the history
…d-14

Feature/1229 target android 14
  • Loading branch information
sds100 authored Jul 2, 2024
2 parents bca5053 + 5d05be6 commit 4621b52
Show file tree
Hide file tree
Showing 14 changed files with 138 additions and 100 deletions.
30 changes: 5 additions & 25 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ apply plugin: "org.jlleitschuh.gradle.ktlint"
android {

namespace 'io.github.sds100.keymapper'
compileSdk 33
buildToolsVersion = '33.0.1'
compileSdk 34
buildToolsVersion = '34.0.0'

def versionProperties = new Properties()
file("version.properties").withInputStream { versionProperties.load(it) }

defaultConfig {
applicationId "io.github.sds100.keymapper"
minSdkVersion 21
targetSdkVersion 33
targetSdkVersion 34
versionCode versionProperties.getProperty("VERSION_CODE").toInteger()
versionName versionProperties.getProperty("VERSION_NAME")
multiDexEnabled true
Expand Down Expand Up @@ -50,32 +50,12 @@ android {
signingConfig signingConfigs.release
}

debug_release {
debuggable = true

postprocessing {
removeUnusedCode true
removeUnusedResources true
obfuscate false //don't obfuscate so stacktraces are easier to read
optimizeCode true
proguardFiles 'proguard-rules.pro'
}

/*
This is required because the splitties library doesn't have a ci build type.
*/
matchingFallbacks = ['debug']
signingConfig signingConfigs.debug
}

debug {
applicationIdSuffix ".debug"
versionNameSuffix "-debug"
}

ci {
debuggable = true

postprocessing {
removeUnusedCode true
removeUnusedResources true
Expand Down Expand Up @@ -179,7 +159,7 @@ dependencies {

// androidx
implementation 'androidx.legacy:legacy-support-core-ui:1.0.0'
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.core:core-ktx:1.13.1'

implementation 'androidx.fragment:fragment-ktx:1.4.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0'
Expand All @@ -191,7 +171,7 @@ dependencies {
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
implementation "androidx.multidex:multidex:$multidex_version"
implementation "androidx.browser:browser:1.4.0"
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'androidx.appcompat:appcompat:1.7.0'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation 'androidx.preference:preference-ktx:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
Expand Down
12 changes: 11 additions & 1 deletion app/src/ci/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<permission android:name="io.github.sds100.keymapper.ci.KEY_EVENT_RELAY_SERVICE">
<!-- I would make this have signature protection level
but I already released the Key Mapper GUI Keyboard
with a different signature -->
</permission>

<application>
<!-- Use the ci permission for key event relay service. -->
<service
android:name=".api.KeyEventRelayService"
android:exported="true"
android:permission="io.github.sds100.keymapper.ci.KEY_EVENT_RELAY_SERVICE"
tools:replace="android:permission" />

</application>
</manifest>
12 changes: 11 additions & 1 deletion app/src/debug/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<permission android:name="io.github.sds100.keymapper.debug.KEY_EVENT_RELAY_SERVICE">
<!-- I would make this have signature protection level
but I already released the Key Mapper GUI Keyboard
with a different signature -->
</permission>

<application>
<!-- Use the debug permission for key event relay service. -->
<service
android:name=".api.KeyEventRelayService"
android:exported="true"
android:permission="io.github.sds100.keymapper.debug.KEY_EVENT_RELAY_SERVICE"
tools:replace="android:permission" />

</application>
</manifest>
10 changes: 0 additions & 10 deletions app/src/debug_release/AndroidManifest.xml

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,9 @@ class PickCoordinateImageView(
color = context.color(R.color.coordinate_line)
}

override fun onDraw(canvas: Canvas?) {
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)

if (canvas == null) return

pointCoordinates.value?.let {
canvas.drawLine(
it.x.toFloat(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import android.graphics.Point
import android.os.Build
import android.view.KeyEvent
import android.view.accessibility.AccessibilityEvent
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import androidx.core.os.bundleOf
import androidx.lifecycle.Lifecycle
Expand Down Expand Up @@ -162,10 +163,16 @@ class MyAccessibilityService :
lifecycleRegistry = LifecycleRegistry(this)
lifecycleRegistry.currentState = Lifecycle.State.CREATED

IntentFilter().apply {
addAction(Api.ACTION_TRIGGER_KEYMAP_BY_UID)
addAction(Intent.ACTION_INPUT_METHOD_CHANGED)
registerReceiver(broadcastReceiver, this)
IntentFilter().also { filter ->
filter.addAction(Api.ACTION_TRIGGER_KEYMAP_BY_UID)
filter.addAction(Intent.ACTION_INPUT_METHOD_CHANGED)

ContextCompat.registerReceiver(
this,
broadcastReceiver,
filter,
ContextCompat.RECEIVER_EXPORTED,
)
}

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.github.sds100.keymapper.system.apps

import android.annotation.SuppressLint
import android.app.ActivityOptions
import android.app.PendingIntent
import android.content.ActivityNotFoundException
import android.content.BroadcastReceiver
Expand All @@ -16,6 +17,7 @@ import android.os.Build
import android.os.TransactionTooLargeException
import android.provider.MediaStore
import android.provider.Settings
import androidx.core.content.ContextCompat
import io.github.sds100.keymapper.util.Error
import io.github.sds100.keymapper.util.Result
import io.github.sds100.keymapper.util.State
Expand Down Expand Up @@ -77,15 +79,19 @@ class AndroidPackageManagerAdapter(
.launchIn(this)
}

IntentFilter().apply {
addAction(Intent.ACTION_PACKAGE_CHANGED)
addAction(Intent.ACTION_PACKAGE_ADDED)
addAction(Intent.ACTION_PACKAGE_REMOVED)
addAction(Intent.ACTION_PACKAGE_REPLACED)
addDataScheme("package")

ctx.registerReceiver(broadcastReceiver, this)
}
val filter = IntentFilter()
filter.addAction(Intent.ACTION_PACKAGE_CHANGED)
filter.addAction(Intent.ACTION_PACKAGE_ADDED)
filter.addAction(Intent.ACTION_PACKAGE_REMOVED)
filter.addAction(Intent.ACTION_PACKAGE_REPLACED)
filter.addDataScheme("package")

ContextCompat.registerReceiver(
ctx,
broadcastReceiver,
filter,
ContextCompat.RECEIVER_NOT_EXPORTED,
)
}

override fun downloadApp(packageName: String) {
Expand Down Expand Up @@ -183,22 +189,12 @@ class AndroidPackageManagerAdapter(
@SuppressLint("UnspecifiedImmutableFlag") // only specify the flag on SDK 23+. SDK 31 is first to enforce it.
override fun openApp(packageName: String): Result<*> {
val leanbackIntent = packageManager.getLeanbackLaunchIntentForPackage(packageName)

val normalIntent = packageManager.getLaunchIntentForPackage(packageName)

val intent = leanbackIntent ?: normalIntent

// intent = null if the app doesn't exist
if (intent != null) {
val pendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
PendingIntent.getActivity(ctx, 0, intent, PendingIntent.FLAG_IMMUTABLE)
} else {
PendingIntent.getActivity(ctx, 0, intent, 0)
}

pendingIntent.send()
return Success(Unit)
} else {
if (intent == null) {
try {
val appInfo = ctx.packageManager.getApplicationInfo(packageName, 0)

Expand All @@ -211,6 +207,26 @@ class AndroidPackageManagerAdapter(
} catch (e: Exception) {
return Error.AppNotFound(packageName)
}
} else {
val pendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
PendingIntent.getActivity(ctx, 0, intent, PendingIntent.FLAG_IMMUTABLE)
} else {
PendingIntent.getActivity(ctx, 0, intent, 0)
}

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
val bundle = ActivityOptions.makeBasic()
.setPendingIntentBackgroundActivityStartMode(
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED,
)
.toBundle()

pendingIntent.send(bundle)
} else {
pendingIntent.send()
}

return Success(Unit)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,15 @@ class AndroidDevicesAdapter(
}.launchIn(coroutineScope)
}

override fun deviceHasKey(id: Int, keyCode: Int): Boolean =
InputDevice.getDevice(id).hasKeys(keyCode)[0]
override fun deviceHasKey(id: Int, keyCode: Int): Boolean {
val device = InputDevice.getDevice(id) ?: return false

return device.hasKeys(keyCode)[0]
}

override fun getInputDeviceName(descriptor: String): Result<String> {
InputDevice.getDeviceIds().forEach {
val device = InputDevice.getDevice(it)
val device = InputDevice.getDevice(it) ?: return@forEach

if (device.descriptor == descriptor) {
return Success(device.name)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import android.content.IntentFilter
import android.hardware.display.DisplayManager
import android.provider.Settings
import android.view.Surface
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import io.github.sds100.keymapper.system.SettingsUtils
import io.github.sds100.keymapper.util.Error
Expand Down Expand Up @@ -66,12 +67,16 @@ class AndroidDisplayAdapter(context: Context) : DisplayAdapter {
override var orientation: Orientation = getDisplayOrientation()

init {
IntentFilter().apply {
addAction(Intent.ACTION_SCREEN_ON)
addAction(Intent.ACTION_SCREEN_OFF)

ctx.registerReceiver(broadcastReceiver, this)
}
val filter = IntentFilter()
filter.addAction(Intent.ACTION_SCREEN_ON)
filter.addAction(Intent.ACTION_SCREEN_OFF)

ContextCompat.registerReceiver(
ctx,
broadcastReceiver,
filter,
ContextCompat.RECEIVER_NOT_EXPORTED,
)
}

override fun isAutoRotateEnabled(): Boolean =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import android.os.Handler
import android.os.Looper
import android.provider.Settings
import android.view.inputmethod.InputMethodManager
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import io.github.sds100.keymapper.system.JobSchedulerHelper
import io.github.sds100.keymapper.system.SettingsUtils
Expand Down Expand Up @@ -148,11 +149,15 @@ class AndroidInputMethodAdapter(
)
}

IntentFilter().apply {
addAction(Intent.ACTION_INPUT_METHOD_CHANGED)
val filter = IntentFilter()
filter.addAction(Intent.ACTION_INPUT_METHOD_CHANGED)

ctx.registerReceiver(broadcastReceiver, this)
}
ContextCompat.registerReceiver(
ctx,
broadcastReceiver,
filter,
ContextCompat.RECEIVER_NOT_EXPORTED,
)
}

override fun showImePicker(fromForeground: Boolean): Result<*> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,10 @@ class KeyMapperImeMessengerImpl(
return
}

// TODO use Android SDK and get version code properly
if (Build.VERSION.SDK_INT >= 34) {
// Only use the new key event relay service on Android 14+ because
// it introduced a 1 second delay for broadcasts to context-registered
// receivers.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
inputKeyEventRelayService(model, imePackageName)
} else {
inputKeyEventBroadcast(model, imePackageName)
Expand Down
Loading

0 comments on commit 4621b52

Please sign in to comment.