mirror of
https://github.com/meowarex/rl-mobile.git
synced 2026-08-26 22:17:44 +10:00
feat(patch): waze integration patch
This commit is contained in:
+5
@@ -6,6 +6,7 @@ import com.meowarex.rlmobile.patcher.steps.StepGroup
|
||||
import com.meowarex.rlmobile.patcher.steps.base.Step
|
||||
import com.meowarex.rlmobile.patcher.steps.download.CopyDependenciesStep
|
||||
import com.meowarex.rlmobile.patcher.util.ManifestPatcher
|
||||
import com.meowarex.rlmobile.ui.screens.patchopts.KnownPatch
|
||||
import com.meowarex.rlmobile.ui.screens.patchopts.PatchOptions
|
||||
import com.github.diamondminer88.zip.ZipReader
|
||||
import com.github.diamondminer88.zip.ZipWriter
|
||||
@@ -26,11 +27,15 @@ class PatchManifestStep(private val options: PatchOptions) : Step() {
|
||||
?: throw IllegalArgumentException("No manifest found in APK")
|
||||
|
||||
container.log("Patching manifest")
|
||||
val enableWazeIntegration =
|
||||
options.patchStates[KnownPatch.WazeIntegration.name] ?: KnownPatch.WazeIntegration.default.isEnabled
|
||||
|
||||
val patchedManifest = ManifestPatcher.patchManifest(
|
||||
manifestBytes = manifest,
|
||||
packageName = options.packageName,
|
||||
appName = options.appName,
|
||||
debuggable = options.debuggable,
|
||||
enableWazeIntegration = enableWazeIntegration,
|
||||
)
|
||||
|
||||
container.log("Repacking apk with patched manifest")
|
||||
|
||||
@@ -18,12 +18,16 @@ object ManifestPatcher {
|
||||
private const val IS_SPLIT_REQUIRED = "isSplitRequired"
|
||||
private const val REQUIRED_SPLIT_TYPES = "requiredSplitTypes"
|
||||
private const val SPLIT_TYPES = "splitTypes"
|
||||
private const val WAZE_PACKAGE = "com.waze"
|
||||
private const val WAZE_INIT_RECEIVER = "radiant.WazeInitReceiver"
|
||||
private const val WAZE_ACTION_INIT = "com.waze.sdk.audio.ACTION_INIT"
|
||||
|
||||
fun patchManifest(
|
||||
manifestBytes: ByteArray,
|
||||
packageName: String,
|
||||
appName: String,
|
||||
debuggable: Boolean,
|
||||
enableWazeIntegration: Boolean,
|
||||
): ByteArray {
|
||||
// Extract original package name to rewrite every reference to it
|
||||
// (permissions, provider authorities) to the new packageName.
|
||||
@@ -84,6 +88,49 @@ object ManifestPatcher {
|
||||
}
|
||||
|
||||
return when (name) {
|
||||
"queries" -> object : NodeVisitor(nv) {
|
||||
private var hasWazePackage = false
|
||||
|
||||
override fun child(ns: String?, name: String): NodeVisitor {
|
||||
val visitor = super.child(ns, name)
|
||||
|
||||
return if (enableWazeIntegration && name == "package") {
|
||||
object : NodeVisitor(visitor) {
|
||||
override fun attr(
|
||||
ns: String?,
|
||||
name: String?,
|
||||
resourceId: Int,
|
||||
type: Int,
|
||||
value: Any?,
|
||||
) {
|
||||
if (name == "name" && value == WAZE_PACKAGE) {
|
||||
hasWazePackage = true
|
||||
}
|
||||
super.attr(ns, name, resourceId, type, value)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
visitor
|
||||
}
|
||||
}
|
||||
|
||||
override fun end() {
|
||||
if (enableWazeIntegration && !hasWazePackage) {
|
||||
super.child(null, "package").apply {
|
||||
attr(
|
||||
ANDROID_NAMESPACE,
|
||||
"name",
|
||||
android.R.attr.name,
|
||||
TYPE_STRING,
|
||||
WAZE_PACKAGE,
|
||||
)
|
||||
end()
|
||||
}
|
||||
}
|
||||
super.end()
|
||||
}
|
||||
}
|
||||
|
||||
"uses-permission" -> object : NodeVisitor(nv) {
|
||||
override fun attr(ns: String?, name: String?, resourceId: Int, type: Int, value: Any?) {
|
||||
if (name != "maxSdkVersion") {
|
||||
@@ -132,6 +179,7 @@ object ManifestPatcher {
|
||||
private var addUseEmbeddedDex = true
|
||||
private var addExtractNativeLibs = true
|
||||
private var addMetadata = true
|
||||
private var hasWazeInitReceiver = false
|
||||
|
||||
override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) {
|
||||
if (name == REQUEST_LEGACY_EXTERNAL_STORAGE) addLegacyStorage = false
|
||||
@@ -161,6 +209,22 @@ object ManifestPatcher {
|
||||
|
||||
return when (name) {
|
||||
"activity" -> ReplaceAttrsVisitor(visitor, mapOf("label" to appName))
|
||||
|
||||
"receiver" -> object : NodeVisitor(visitor) {
|
||||
override fun attr(
|
||||
ns: String?,
|
||||
name: String,
|
||||
resourceId: Int,
|
||||
type: Int,
|
||||
value: Any?
|
||||
) {
|
||||
if (name == "name" && value == WAZE_INIT_RECEIVER) {
|
||||
hasWazeInitReceiver = true
|
||||
}
|
||||
super.attr(ns, name, resourceId, type, value)
|
||||
}
|
||||
}
|
||||
|
||||
"provider" -> object : NodeVisitor(visitor) {
|
||||
override fun attr(
|
||||
ns: String?,
|
||||
@@ -219,6 +283,39 @@ object ManifestPatcher {
|
||||
0
|
||||
)
|
||||
|
||||
if (enableWazeIntegration && !hasWazeInitReceiver) {
|
||||
super.child(null, "receiver").apply {
|
||||
attr(
|
||||
ANDROID_NAMESPACE,
|
||||
"name",
|
||||
android.R.attr.name,
|
||||
TYPE_STRING,
|
||||
WAZE_INIT_RECEIVER,
|
||||
)
|
||||
attr(
|
||||
ANDROID_NAMESPACE,
|
||||
"exported",
|
||||
android.R.attr.exported,
|
||||
TYPE_INT_BOOLEAN,
|
||||
1,
|
||||
)
|
||||
child(null, "intent-filter").apply {
|
||||
child(null, "action").apply {
|
||||
attr(
|
||||
ANDROID_NAMESPACE,
|
||||
"name",
|
||||
android.R.attr.name,
|
||||
TYPE_STRING,
|
||||
WAZE_ACTION_INIT,
|
||||
)
|
||||
end()
|
||||
}
|
||||
end()
|
||||
}
|
||||
end()
|
||||
}
|
||||
}
|
||||
|
||||
super.end()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,6 +130,17 @@ enum class KnownPatch(
|
||||
descRes = R.string.patch_debug_menu_unlock_desc,
|
||||
default = Disabled,
|
||||
),
|
||||
WazeIntegration(
|
||||
order = 90,
|
||||
fileNames = listOf("waze-media-browser.patch"),
|
||||
extensionFiles = listOf(
|
||||
"radiant/WazeInitReceiver.smali",
|
||||
"radiant/WazeServiceConnection.smali",
|
||||
),
|
||||
titleRes = R.string.patch_waze_integration_title,
|
||||
descRes = R.string.patch_waze_integration_desc,
|
||||
default = Disabled,
|
||||
),
|
||||
LyricsProgressPill(
|
||||
order = 40,
|
||||
fileNames = listOf(
|
||||
|
||||
@@ -286,6 +286,8 @@
|
||||
<string
|
||||
name="patch_debug_menu_unlock_desc"
|
||||
>Reveals TIDAL\'s hidden Debug Menu in Settings. (Unlocks Feature Flags & the legacy Debug Options)</string>
|
||||
<string name="patch_waze_integration_title">Waze Integration</string>
|
||||
<string name="patch_waze_integration_desc">Control TIDAL playback from the Waze app</string>
|
||||
<string name="patch_enable_legacy_ui_title">Enable Legacy UI</string>
|
||||
<string
|
||||
name="patch_enable_legacy_ui_desc"
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"tidalVersionCode": 9090,
|
||||
"tidalApkUrl": "https://github.com/meowarex/rl-mobile/releases/download/latest/tidal-stock.apk",
|
||||
"patchesVersion": "0.9.14"
|
||||
"patchesVersion": "0.9.15"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
.class public final Lradiant/WazeInitReceiver;
|
||||
.super Landroid/content/BroadcastReceiver;
|
||||
.source "WazeInitReceiver.smali"
|
||||
|
||||
|
||||
# direct methods
|
||||
.method public constructor <init>()V
|
||||
.locals 0
|
||||
|
||||
invoke-direct {p0}, Landroid/content/BroadcastReceiver;-><init>()V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
|
||||
# virtual methods
|
||||
.method public onReceive(Landroid/content/Context;Landroid/content/Intent;)V
|
||||
.locals 5
|
||||
|
||||
if-eqz p1, :return
|
||||
|
||||
if-eqz p2, :return
|
||||
|
||||
const-string v0, "com.waze.sdk.audio.ACTION_INIT"
|
||||
|
||||
invoke-virtual {p2}, Landroid/content/Intent;->getAction()Ljava/lang/String;
|
||||
|
||||
move-result-object v1
|
||||
|
||||
invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
|
||||
|
||||
move-result v0
|
||||
|
||||
if-eqz v0, :return
|
||||
|
||||
const-string v0, "token"
|
||||
|
||||
invoke-virtual {p2, v0}, Landroid/content/Intent;->getStringExtra(Ljava/lang/String;)Ljava/lang/String;
|
||||
|
||||
move-result-object v0
|
||||
|
||||
if-eqz v0, :return
|
||||
|
||||
invoke-virtual {v0}, Ljava/lang/String;->length()I
|
||||
|
||||
move-result v1
|
||||
|
||||
if-lez v1, :return
|
||||
|
||||
invoke-virtual {p1}, Landroid/content/Context;->getApplicationContext()Landroid/content/Context;
|
||||
|
||||
move-result-object v1
|
||||
|
||||
if-eqz v1, :context_ready
|
||||
|
||||
move-object p1, v1
|
||||
|
||||
:context_ready
|
||||
new-instance v1, Landroid/content/Intent;
|
||||
|
||||
invoke-direct {v1}, Landroid/content/Intent;-><init>()V
|
||||
|
||||
const-string v2, "com.waze"
|
||||
|
||||
const-string v3, "com.waze.sdk.SdkService"
|
||||
|
||||
invoke-virtual {v1, v2, v3}, Landroid/content/Intent;->setClassName(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;
|
||||
|
||||
new-instance v2, Lradiant/WazeServiceConnection;
|
||||
|
||||
invoke-direct {v2, p1, v0}, Lradiant/WazeServiceConnection;-><init>(Landroid/content/Context;Ljava/lang/String;)V
|
||||
|
||||
:try_start_0
|
||||
const/4 v3, 0x1
|
||||
|
||||
invoke-virtual {p1, v1, v2, v3}, Landroid/content/Context;->bindService(Landroid/content/Intent;Landroid/content/ServiceConnection;I)Z
|
||||
:try_end_0
|
||||
.catch Ljava/lang/Throwable; {:try_start_0 .. :try_end_0} :catch_0
|
||||
|
||||
goto :return
|
||||
|
||||
:catch_0
|
||||
move-exception v4
|
||||
|
||||
:return
|
||||
return-void
|
||||
.end method
|
||||
@@ -0,0 +1,222 @@
|
||||
.class public final Lradiant/WazeServiceConnection;
|
||||
.super Ljava/lang/Object;
|
||||
.source "WazeServiceConnection.smali"
|
||||
|
||||
# interfaces
|
||||
.implements Landroid/content/ServiceConnection;
|
||||
|
||||
|
||||
# instance fields
|
||||
.field private final context:Landroid/content/Context;
|
||||
|
||||
.field private final token:Ljava/lang/String;
|
||||
|
||||
|
||||
# direct methods
|
||||
.method public constructor <init>(Landroid/content/Context;Ljava/lang/String;)V
|
||||
.locals 0
|
||||
|
||||
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
|
||||
|
||||
iput-object p1, p0, Lradiant/WazeServiceConnection;->context:Landroid/content/Context;
|
||||
|
||||
iput-object p2, p0, Lradiant/WazeServiceConnection;->token:Ljava/lang/String;
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method private addOpenMeIntent(Landroid/os/Bundle;)V
|
||||
.locals 4
|
||||
|
||||
iget-object v0, p0, Lradiant/WazeServiceConnection;->context:Landroid/content/Context;
|
||||
|
||||
invoke-virtual {v0}, Landroid/content/Context;->getPackageManager()Landroid/content/pm/PackageManager;
|
||||
|
||||
move-result-object v1
|
||||
|
||||
invoke-virtual {v0}, Landroid/content/Context;->getPackageName()Ljava/lang/String;
|
||||
|
||||
move-result-object v2
|
||||
|
||||
invoke-virtual {v1, v2}, Landroid/content/pm/PackageManager;->getLaunchIntentForPackage(Ljava/lang/String;)Landroid/content/Intent;
|
||||
|
||||
move-result-object v1
|
||||
|
||||
if-eqz v1, :return
|
||||
|
||||
const/high16 v2, 0x10000000
|
||||
|
||||
invoke-virtual {v1, v2}, Landroid/content/Intent;->addFlags(I)Landroid/content/Intent;
|
||||
|
||||
const v2, 0xc000000
|
||||
|
||||
const/4 v3, 0x0
|
||||
|
||||
invoke-static {v0, v3, v1, v2}, Landroid/app/PendingIntent;->getActivity(Landroid/content/Context;ILandroid/content/Intent;I)Landroid/app/PendingIntent;
|
||||
|
||||
move-result-object v1
|
||||
|
||||
const-string v2, "openMeIntent"
|
||||
|
||||
invoke-virtual {p1, v2, v1}, Landroid/os/Bundle;->putParcelable(Ljava/lang/String;Landroid/os/Parcelable;)V
|
||||
|
||||
:return
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method private createClientMessenger()Landroid/os/Messenger;
|
||||
.locals 3
|
||||
|
||||
new-instance v0, Landroid/os/Handler;
|
||||
|
||||
invoke-static {}, Landroid/os/Looper;->getMainLooper()Landroid/os/Looper;
|
||||
|
||||
move-result-object v1
|
||||
|
||||
invoke-direct {v0, v1}, Landroid/os/Handler;-><init>(Landroid/os/Looper;)V
|
||||
|
||||
new-instance v2, Landroid/os/Messenger;
|
||||
|
||||
invoke-direct {v2, v0}, Landroid/os/Messenger;-><init>(Landroid/os/Handler;)V
|
||||
|
||||
return-object v2
|
||||
.end method
|
||||
|
||||
.method private createConfigBundle()Landroid/os/Bundle;
|
||||
.locals 3
|
||||
|
||||
new-instance v0, Landroid/os/Bundle;
|
||||
|
||||
invoke-direct {v0}, Landroid/os/Bundle;-><init>()V
|
||||
|
||||
const-string v1, "versionCode"
|
||||
|
||||
const/16 v2, 0xa
|
||||
|
||||
invoke-virtual {v0, v1, v2}, Landroid/os/Bundle;->putInt(Ljava/lang/String;I)V
|
||||
|
||||
invoke-direct {p0, v0}, Lradiant/WazeServiceConnection;->addOpenMeIntent(Landroid/os/Bundle;)V
|
||||
|
||||
return-object v0
|
||||
.end method
|
||||
|
||||
.method private register(Landroid/os/IBinder;)V
|
||||
.locals 5
|
||||
|
||||
if-eqz p1, :return
|
||||
|
||||
invoke-static {}, Landroid/os/Parcel;->obtain()Landroid/os/Parcel;
|
||||
|
||||
move-result-object v0
|
||||
|
||||
invoke-static {}, Landroid/os/Parcel;->obtain()Landroid/os/Parcel;
|
||||
|
||||
move-result-object v1
|
||||
|
||||
const-string v2, "com.waze.sdk.ISdkService"
|
||||
|
||||
invoke-virtual {v0, v2}, Landroid/os/Parcel;->writeInterfaceToken(Ljava/lang/String;)V
|
||||
|
||||
iget-object v2, p0, Lradiant/WazeServiceConnection;->token:Ljava/lang/String;
|
||||
|
||||
invoke-virtual {v0, v2}, Landroid/os/Parcel;->writeString(Ljava/lang/String;)V
|
||||
|
||||
invoke-direct {p0}, Lradiant/WazeServiceConnection;->createConfigBundle()Landroid/os/Bundle;
|
||||
|
||||
move-result-object v2
|
||||
|
||||
invoke-static {v0, v2}, Lradiant/WazeServiceConnection;->writeParcelable(Landroid/os/Parcel;Landroid/os/Parcelable;)V
|
||||
|
||||
invoke-direct {p0}, Lradiant/WazeServiceConnection;->createClientMessenger()Landroid/os/Messenger;
|
||||
|
||||
move-result-object v2
|
||||
|
||||
invoke-static {v0, v2}, Lradiant/WazeServiceConnection;->writeParcelable(Landroid/os/Parcel;Landroid/os/Parcelable;)V
|
||||
|
||||
const/4 v2, 0x1
|
||||
|
||||
const/4 v3, 0x0
|
||||
|
||||
invoke-interface {p1, v2, v0, v1, v3}, Landroid/os/IBinder;->transact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z
|
||||
|
||||
move-result v4
|
||||
|
||||
if-eqz v4, :cleanup
|
||||
|
||||
invoke-virtual {v1}, Landroid/os/Parcel;->readException()V
|
||||
|
||||
:cleanup
|
||||
invoke-virtual {v1}, Landroid/os/Parcel;->recycle()V
|
||||
|
||||
invoke-virtual {v0}, Landroid/os/Parcel;->recycle()V
|
||||
|
||||
:return
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method private safeUnbind()V
|
||||
.locals 1
|
||||
|
||||
:try_start_0
|
||||
iget-object v0, p0, Lradiant/WazeServiceConnection;->context:Landroid/content/Context;
|
||||
|
||||
invoke-virtual {v0, p0}, Landroid/content/Context;->unbindService(Landroid/content/ServiceConnection;)V
|
||||
:try_end_0
|
||||
.catch Ljava/lang/Throwable; {:try_start_0 .. :try_end_0} :catch_0
|
||||
|
||||
goto :return
|
||||
|
||||
:catch_0
|
||||
move-exception v0
|
||||
|
||||
:return
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method private static writeParcelable(Landroid/os/Parcel;Landroid/os/Parcelable;)V
|
||||
.locals 2
|
||||
|
||||
const/4 v0, 0x0
|
||||
|
||||
if-eqz p1, :null_value
|
||||
|
||||
const/4 v1, 0x1
|
||||
|
||||
invoke-virtual {p0, v1}, Landroid/os/Parcel;->writeInt(I)V
|
||||
|
||||
invoke-interface {p1, p0, v0}, Landroid/os/Parcelable;->writeToParcel(Landroid/os/Parcel;I)V
|
||||
|
||||
return-void
|
||||
|
||||
:null_value
|
||||
invoke-virtual {p0, v0}, Landroid/os/Parcel;->writeInt(I)V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
|
||||
# virtual methods
|
||||
.method public onServiceConnected(Landroid/content/ComponentName;Landroid/os/IBinder;)V
|
||||
.locals 1
|
||||
|
||||
:try_start_0
|
||||
invoke-direct {p0, p2}, Lradiant/WazeServiceConnection;->register(Landroid/os/IBinder;)V
|
||||
:try_end_0
|
||||
.catch Ljava/lang/Throwable; {:try_start_0 .. :try_end_0} :catch_0
|
||||
|
||||
goto :unbind
|
||||
|
||||
:catch_0
|
||||
move-exception v0
|
||||
|
||||
:unbind
|
||||
invoke-direct {p0}, Lradiant/WazeServiceConnection;->safeUnbind()V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method public onServiceDisconnected(Landroid/content/ComponentName;)V
|
||||
.locals 0
|
||||
|
||||
return-void
|
||||
.end method
|
||||
@@ -212,6 +212,15 @@
|
||||
"description": "Inverts the auto-hide behavior on the lyrics screen, playback controls stay visible by default and only hide when you tap them off.",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"id": "WazeIntegration",
|
||||
"order": 90,
|
||||
"fileNames": ["waze-media-browser.patch"],
|
||||
"extensionFiles": ["radiant/WazeInitReceiver.smali", "radiant/WazeServiceConnection.smali"],
|
||||
"title": "Waze Integration",
|
||||
"description": "Control TIDAL playback from the Waze app",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"id": "DebugMenuUnlock",
|
||||
"order": 100,
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
--- a/pb/c.smali
|
||||
+++ b/pb/c.smali
|
||||
@@ -700,0 +701,24 @@
|
||||
+ iget-object v15, v1, Lcom/aspiro/wamp/util/y$a;->b:Ljava/lang/String;
|
||||
+
|
||||
+ const-string/jumbo v14, "com.waze"
|
||||
+
|
||||
+ invoke-static {v15, v14}, Lkotlin/jvm/internal/n;->b(Ljava/lang/Object;Ljava/lang/Object;)Z # check caller
|
||||
+
|
||||
+ move-result v12
|
||||
+
|
||||
+ if-eqz v12, :rl_waze_done
|
||||
+
|
||||
+ iget-object v15, v1, Lcom/aspiro/wamp/util/y$a;->d:Ljava/lang/String; # caller cert
|
||||
+
|
||||
+ const-string v14, "03:63:7f:6c:5d:8f:60:4e:6f:db:79:a6:ff:bf:a5:78:de:4e:31:8f:8d:a2:2f:c6:10:66:65:24:7f:88:07:d7" # Waze cert
|
||||
+
|
||||
+ invoke-static {v15, v14}, Lkotlin/jvm/internal/n;->b(Ljava/lang/Object;Ljava/lang/Object;)Z # check cert
|
||||
+
|
||||
+ move-result v12 # cert match
|
||||
+
|
||||
+ if-eqz v12, :rl_waze_done # reject mismatch
|
||||
+
|
||||
+ goto :goto_9 # trust Waze
|
||||
+
|
||||
+ :rl_waze_done
|
||||
+
|
||||
Reference in New Issue
Block a user