Compare commits

...
4 Commits
Author SHA1 Message Date
meoware.exe af28dda074 Merge pull request #89 from meowarex/dev
Fix offline Shader + Lyric Seeking
2026-08-19 16:50:59 +10:00
meowarex a594e23ee5 Fix offline Shader + Lyric Seeking 2026-08-19 06:54:51 +00:00
meowarex bbd0876324 Merge pull request #87 from meowarex/dev
Refactor Backdrop <3
2026-08-14 16:55:38 +00:00
meowarex 5d8e52ce9f Refactor Backdrop <3 2026-08-14 16:55:27 +00:00
34 changed files with 624 additions and 485 deletions
+12
View File
@@ -6,6 +6,8 @@ on:
- main
paths-ignore:
- "**/*.md"
# Lets a release be re-run by hand from the Actions tab if a push event is ever missed.
workflow_dispatch:
jobs:
Version:
@@ -23,6 +25,16 @@ jobs:
BASE=$(cat .version | tr -d '[:space:]')
echo "version=$BASE" >> $GITHUB_OUTPUT
# Releasing onto an existing tag silently overwrites that release's assets, so a
# forgotten .version bump replaces history instead of publishing. Fail loudly instead.
# ls-remote, not rev-parse: actions/checkout does not fetch tags by default,
# so a local lookup would always miss and the guard would never fire.
if git ls-remote --exit-code --tags origin "refs/tags/v$BASE" >/dev/null 2>&1; then
echo "::error::Tag v$BASE already exists - bump .version before releasing." \
"Re-running this workflow as-is would overwrite the v$BASE release assets."
exit 1
fi
Build:
needs: Version
uses: ./.github/workflows/build.yml
+1 -1
View File
@@ -1 +1 @@
1.1.1
1.1.5
+2 -2
View File
@@ -31,8 +31,8 @@ android {
defaultConfig {
minSdk = 24
targetSdk = 36
versionCode = 63
versionName = "1.1.1"
versionCode = 67
versionName = "1.1.5"
vectorDrawables {
useSupportLibrary = true
+1 -1
View File
@@ -1,5 +1,5 @@
{
"tidalVersionCode": 10004,
"tidalApkUrl": "https://github.com/meowarex/rl-mobile/releases/download/latest/tidal-stock.apk",
"patchesVersion": "1.2.1"
"patchesVersion": "1.2.5"
}
+35 -17
View File
@@ -34,12 +34,12 @@
.field private volatile coverToken:I
.field private volatile darkenBrightness:F
.field private volatile dithering:F
.field private lastFrameUptime:J
.field private volatile nextDarken:F
.field private volatile nextShader:Landroid/graphics/BitmapShader;
.field private final paint:Landroid/graphics/Paint;
@@ -50,6 +50,8 @@
.field private volatile playing:Z
.field private volatile prevDarken:F
.field private volatile prevShader:Landroid/graphics/BitmapShader;
.field private volatile saturation:F
@@ -155,7 +157,9 @@
iput-object v1, p0, Ldev/kawarp/KawarpEngine;->paint:Landroid/graphics/Paint;
iput v0, p0, Ldev/kawarp/KawarpEngine;->darkenBrightness:F
iput v0, p0, Ldev/kawarp/KawarpEngine;->prevDarken:F
iput v0, p0, Ldev/kawarp/KawarpEngine;->nextDarken:F
iput v0, p0, Ldev/kawarp/KawarpEngine;->speedFactor:F
@@ -163,7 +167,7 @@
move-result v0
if-eqz v0, :cond_55
if-eqz v0, :cond_57
new-instance v0, Landroid/graphics/RuntimeShader;
@@ -175,7 +179,7 @@
return-void
:cond_55
:cond_57
new-instance v0, Ljava/lang/IllegalStateException;
const-string v1, "KawarpEngine needs API 33+ (AGSL)"
@@ -738,11 +742,15 @@
iput-object v1, v0, Ldev/kawarp/KawarpEngine;->nextShader:Landroid/graphics/BitmapShader;
iget v1, v0, Ldev/kawarp/KawarpEngine;->nextDarken:F
iput v1, v0, Ldev/kawarp/KawarpEngine;->prevDarken:F
invoke-direct {v0, v12}, Ldev/kawarp/KawarpEngine;->brightnessFor(F)F
move-result v1
iput v1, v0, Ldev/kawarp/KawarpEngine;->darkenBrightness:F
iput v1, v0, Ldev/kawarp/KawarpEngine;->nextDarken:F
invoke-static {}, Landroid/os/SystemClock;->uptimeMillis()J
@@ -760,19 +768,19 @@
iget-object v0, p0, Ldev/kawarp/KawarpEngine;->nextShader:Landroid/graphics/BitmapShader;
if-eqz v0, :cond_ee
if-eqz v0, :cond_f5
const/4 v1, 0x0
cmpg-float v2, p2, v1
if-lez v2, :cond_ee
if-lez v2, :cond_f5
cmpg-float v2, p3, v1
if-gtz v2, :cond_f
goto/16 :goto_ee
goto/16 :goto_f5
:cond_f
invoke-static {}, Landroid/os/SystemClock;->uptimeMillis()J
@@ -976,17 +984,27 @@
invoke-virtual {v0, v1, v2}, Landroid/graphics/RuntimeShader;->setFloatUniform(Ljava/lang/String;F)V
iget-object v0, p0, Ldev/kawarp/KawarpEngine;->shader:Landroid/graphics/RuntimeShader;
iget v0, p0, Ldev/kawarp/KawarpEngine;->prevDarken:F
iget v1, p0, Ldev/kawarp/KawarpEngine;->brightness:F
iget v1, p0, Ldev/kawarp/KawarpEngine;->nextDarken:F
iget v2, p0, Ldev/kawarp/KawarpEngine;->darkenBrightness:F
iget v2, p0, Ldev/kawarp/KawarpEngine;->prevDarken:F
mul-float/2addr v1, v2
sub-float/2addr v1, v2
const-string v2, "uBright"
mul-float/2addr v1, v6
invoke-virtual {v0, v2, v1}, Landroid/graphics/RuntimeShader;->setFloatUniform(Ljava/lang/String;F)V
add-float/2addr v0, v1
iget-object v1, p0, Ldev/kawarp/KawarpEngine;->shader:Landroid/graphics/RuntimeShader;
iget v2, p0, Ldev/kawarp/KawarpEngine;->brightness:F
mul-float/2addr v2, v0
const-string v0, "uBright"
invoke-virtual {v1, v0, v2}, Landroid/graphics/RuntimeShader;->setFloatUniform(Ljava/lang/String;F)V
iget-object v0, p0, Ldev/kawarp/KawarpEngine;->shader:Landroid/graphics/RuntimeShader;
@@ -1020,8 +1038,8 @@
return p1
:cond_ee
:goto_ee
:cond_f5
:goto_f5
const/4 p1, 0x0
return p1
+1 -25
View File
@@ -5,9 +5,6 @@
# static fields
.field public static volatile currentAlbumId:I
# 2 = Stock (TIDAL's blurred cover, follows live play state), 3 = Kawarp (AGSL shader)
.field public static volatile mode:I
# Live play state from the mini-player (t.c PlayState = Playing)
.field public static isPlayingState:Landroidx/compose/runtime/MutableState;
.annotation system Ldalvik/annotation/Signature;
@@ -38,10 +35,6 @@
sput v0, Lradiant/HomeBackdrop;->currentAlbumId:I
const/4 v0, 0x2
sput v0, Lradiant/HomeBackdrop;->mode:I
sget-object v0, Ljava/lang/Boolean;->FALSE:Ljava/lang/Boolean;
const/4 v1, 0x0
@@ -73,16 +66,6 @@
return-void
.end method
.method public static setModePlayback()V
.locals 1
const/4 v0, 0x2
sput v0, Lradiant/HomeBackdrop;->mode:I
return-void
.end method
# from the mini-player state ctor (t.<init>) whenever play state changes.
.method public static onPlayState(Lcom/tidal/android/feature/appscaffold/ui/MiniPlayerContract$PlayState;)V
.locals 2
@@ -358,13 +341,7 @@
move-object v9, v1 # v9 = cover uuid
# v10 = isPlaying, mirrored from the Player Backdrop variant
sget v10, Lradiant/HomeBackdrop;->mode:I
const/4 v11, 0x2
if-ne v10, v11, :rl_mode_done
# v10 = isPlaying, straight from the live mini-player state (both modes follow it)
sget-object v10, Lradiant/HomeBackdrop;->isPlayingState:Landroidx/compose/runtime/MutableState;
invoke-interface {v10}, Landroidx/compose/runtime/State;->getValue()Ljava/lang/Object;
@@ -377,7 +354,6 @@
move-result v10
:rl_mode_done
const/4 v11, 0x0 # v11 = isSeeking = false
const/4 v12, 0x0 # v12 = progress callback = null (unused while not seeking)
+303 -322
View File
@@ -5,6 +5,7 @@
.implements Lam0/l;
.implements Ljava/lang/Runnable;
.implements Landroid/view/Choreographer$FrameCallback;
.implements Lb0/c;
# static fields
@@ -14,7 +15,7 @@
.field private static final LOADER:Ljava/util/concurrent/ExecutorService;
.field private static final TAG:Ljava/lang/String; = "RLKawarp"
.field private static volatile appContext:Landroid/content/Context;
.field private static engine:Ldev/kawarp/KawarpEngine;
@@ -22,7 +23,7 @@
.field private static frameScheduled:Z
.field private static final frameState:Landroidx/compose/runtime/MutableState;
.field private static final frameState:Landroidx/compose/runtime/MutableIntState;
.field private static frameTick:I
@@ -30,12 +31,14 @@
.field private static volatile loadToken:I
.field private static loggedDraw:Z
.field private static volatile loader:Lcoil/f;
.field private static volatile requestedUuid:Ljava/lang/String;
# instance fields
.field private final albumId:I
.field private final token:I
.field private final uuid:Ljava/lang/String;
@@ -53,23 +56,19 @@
const/4 v0, 0x0
invoke-static {v0}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
invoke-static {v0}, Landroidx/compose/runtime/SnapshotIntStateKt;->mutableIntStateOf(I)Landroidx/compose/runtime/MutableIntState;
move-result-object v1
const/4 v2, 0x0
const/4 v3, 0x2
invoke-static {v1, v2, v3, v2}, Landroidx/compose/runtime/SnapshotStateKt;->mutableStateOf$default(Ljava/lang/Object;Landroidx/compose/runtime/SnapshotMutationPolicy;ILjava/lang/Object;)Landroidx/compose/runtime/MutableState;
move-result-object v1
sput-object v1, Lradiant/Kawarp;->frameState:Landroidx/compose/runtime/MutableState;
sput-object v1, Lradiant/Kawarp;->frameState:Landroidx/compose/runtime/MutableIntState;
sget-object v1, Ljava/lang/Boolean;->FALSE:Ljava/lang/Boolean;
invoke-static {v1, v2, v3, v2}, Landroidx/compose/runtime/SnapshotStateKt;->mutableStateOf$default(Ljava/lang/Object;Landroidx/compose/runtime/SnapshotMutationPolicy;ILjava/lang/Object;)Landroidx/compose/runtime/MutableState;
const/4 v2, 0x2
const/4 v3, 0x0
invoke-static {v1, v3, v2, v3}, Landroidx/compose/runtime/SnapshotStateKt;->mutableStateOf$default(Ljava/lang/Object;Landroidx/compose/runtime/SnapshotMutationPolicy;ILjava/lang/Object;)Landroidx/compose/runtime/MutableState;
move-result-object v1
@@ -77,22 +76,101 @@
new-instance v1, Lradiant/Kawarp;
invoke-direct {v1, v2, v0}, Lradiant/Kawarp;-><init>(Ljava/lang/String;I)V
invoke-direct {v1, v0, v3, v0}, Lradiant/Kawarp;-><init>(ILjava/lang/String;I)V
sput-object v1, Lradiant/Kawarp;->DRAW:Lradiant/Kawarp;
return-void
.end method
.method private constructor <init>(Ljava/lang/String;I)V
.registers 3
.method private constructor <init>(ILjava/lang/String;I)V
.registers 4
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
iput-object p1, p0, Lradiant/Kawarp;->uuid:Ljava/lang/String;
iput p1, p0, Lradiant/Kawarp;->albumId:I
iput p2, p0, Lradiant/Kawarp;->token:I
iput-object p2, p0, Lradiant/Kawarp;->uuid:Ljava/lang/String;
iput p3, p0, Lradiant/Kawarp;->token:I
return-void
.end method
.method private static attach(Landroidx/compose/runtime/Composer;)V
.registers 3
sget-object v0, Lradiant/Kawarp;->loader:Lcoil/f;
if-eqz v0, :cond_5
return-void
:cond_5
:try_start_5
invoke-static {}, Landroidx/compose/ui/platform/AndroidCompositionLocals_androidKt;->getLocalContext()Landroidx/compose/runtime/ProvidableCompositionLocal;
move-result-object v0
invoke-interface {p0, v0}, Landroidx/compose/runtime/Composer;->consume(Landroidx/compose/runtime/CompositionLocal;)Ljava/lang/Object;
move-result-object p0
instance-of v0, p0, Landroid/content/Context;
if-nez v0, :cond_12
return-void
:cond_12
check-cast p0, Landroid/content/Context;
invoke-virtual {p0}, Landroid/content/Context;->getApplicationContext()Landroid/content/Context;
move-result-object p0
instance-of v0, p0, Lce0/b$a;
if-nez v0, :cond_1d
return-void
:cond_1d
move-object v0, p0
check-cast v0, Lce0/b$a;
invoke-interface {v0}, Lce0/b$a;->a()Lce0/b;
move-result-object v0
invoke-interface {v0}, Lce0/b;->a()Lxd0/e;
move-result-object v0
instance-of v1, v0, Lcom/tidal/android/image/coil/base/CoilImageLoader;
if-nez v1, :cond_2d
return-void
:cond_2d
sput-object p0, Lradiant/Kawarp;->appContext:Landroid/content/Context;
check-cast v0, Lcom/tidal/android/image/coil/base/CoilImageLoader;
iget-object p0, v0, Lcom/tidal/android/image/coil/base/CoilImageLoader;->a:Lcoil/f;
sput-object p0, Lradiant/Kawarp;->loader:Lcoil/f;
:try_end_35
.catchall {:try_start_5 .. :try_end_35} :catchall_36
goto :goto_37
:catchall_36
move-exception p0
:goto_37
return-void
.end method
@@ -105,11 +183,11 @@
.end method
.method private static draw(Landroidx/compose/ui/graphics/drawscope/DrawScope;)V
.registers 6
.registers 4
sget-object v0, Lradiant/Kawarp;->frameState:Landroidx/compose/runtime/MutableState;
sget-object v0, Lradiant/Kawarp;->frameState:Landroidx/compose/runtime/MutableIntState;
invoke-interface {v0}, Landroidx/compose/runtime/MutableState;->getValue()Ljava/lang/Object;
invoke-interface {v0}, Landroidx/compose/runtime/MutableIntState;->getIntValue()I
invoke-static {}, Landroid/os/SystemClock;->uptimeMillis()J
@@ -131,64 +209,7 @@
move-result v0
sget-boolean v1, Lradiant/Kawarp;->loggedDraw:Z
const-string v3, "RLKawarp"
if-nez v1, :cond_53
const/4 v1, 0x1
sput-boolean v1, Lradiant/Kawarp;->loggedDraw:Z
new-instance v1, Ljava/lang/StringBuilder;
invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V
const-string v4, "first draw: "
invoke-virtual {v1, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v1
invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(F)Ljava/lang/StringBuilder;
move-result-object v1
const-string v4, "x"
invoke-virtual {v1, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v1
invoke-virtual {v1, v0}, Ljava/lang/StringBuilder;->append(F)Ljava/lang/StringBuilder;
move-result-object v1
const-string v4, " ready="
invoke-virtual {v1, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v1
sget-object v4, Lradiant/Kawarp;->engine:Ldev/kawarp/KawarpEngine;
invoke-virtual {v4}, Ldev/kawarp/KawarpEngine;->isReady()Z
move-result v4
invoke-virtual {v1, v4}, Ljava/lang/StringBuilder;->append(Z)Ljava/lang/StringBuilder;
move-result-object v1
invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v1
invoke-static {v3, v1}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
:cond_53
:try_start_53
:try_start_1a
sget-object v1, Lradiant/Kawarp;->engine:Ldev/kawarp/KawarpEngine;
invoke-interface {p0}, Landroidx/compose/ui/graphics/drawscope/DrawScope;->getDrawContext()Landroidx/compose/ui/graphics/drawscope/DrawContext;
@@ -204,41 +225,21 @@
move-result-object p0
invoke-virtual {v1, p0, v2, v0}, Ldev/kawarp/KawarpEngine;->draw(Landroid/graphics/Canvas;FF)Z
:try_end_64
.catchall {:try_start_53 .. :try_end_64} :catchall_65
:try_end_2b
.catchall {:try_start_1a .. :try_end_2b} :catchall_2c
goto :goto_83
goto :goto_34
:catchall_65
:catchall_2c
move-exception p0
new-instance v0, Ljava/lang/StringBuilder;
invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
const-string v1, "AGSL draw failed, falling back: "
invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v0
invoke-virtual {v0, p0}, Ljava/lang/StringBuilder;->append(Ljava/lang/Object;)Ljava/lang/StringBuilder;
move-result-object p0
invoke-virtual {p0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object p0
invoke-static {v3, p0}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
sget-object p0, Lradiant/Kawarp;->fallbackState:Landroidx/compose/runtime/MutableState;
sget-object v0, Ljava/lang/Boolean;->TRUE:Ljava/lang/Boolean;
invoke-interface {p0, v0}, Landroidx/compose/runtime/MutableState;->setValue(Ljava/lang/Object;)V
:goto_83
:goto_34
return-void
.end method
@@ -401,28 +402,6 @@
:catchall_9f
move-exception v0
new-instance v1, Ljava/lang/StringBuilder;
invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V
const-string v3, "AGSL rejected, staying on the native backdrop: "
invoke-virtual {v1, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v1
invoke-virtual {v1, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/Object;)Ljava/lang/StringBuilder;
move-result-object v0
invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v0
const-string v1, "RLKawarp"
invoke-static {v1, v0}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
sget-object v0, Lradiant/Kawarp;->fallbackState:Landroidx/compose/runtime/MutableState;
sget-object v1, Ljava/lang/Boolean;->TRUE:Ljava/lang/Boolean;
@@ -432,6 +411,23 @@
return v2
.end method
.method private fail()V
.registers 3
iget v0, p0, Lradiant/Kawarp;->token:I
sget v1, Lradiant/Kawarp;->loadToken:I
if-ne v0, v1, :cond_9
const/4 v0, 0x0
sput-object v0, Lradiant/Kawarp;->requestedUuid:Ljava/lang/String;
:cond_9
return-void
.end method
.method public static render(ILjava/lang/String;ZLandroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;)V
.registers 13
@@ -439,6 +435,8 @@
invoke-interface {p4, v0}, Landroidx/compose/runtime/Composer;->startReplaceGroup(I)V
invoke-static {p4}, Lradiant/Kawarp;->attach(Landroidx/compose/runtime/Composer;)V
sget-object v0, Lradiant/Kawarp;->fallbackState:Landroidx/compose/runtime/MutableState;
invoke-interface {v0}, Landroidx/compose/runtime/MutableState;->getValue()Ljava/lang/Object;
@@ -451,19 +449,19 @@
move-result v0
if-nez v0, :cond_34
if-nez v0, :cond_37
invoke-static {}, Lradiant/Kawarp;->ensureEngine()Z
move-result v0
if-eqz v0, :cond_34
if-eqz v0, :cond_37
sget-object p0, Lradiant/Kawarp;->engine:Ldev/kawarp/KawarpEngine;
sget-object v0, Lradiant/Kawarp;->engine:Ldev/kawarp/KawarpEngine;
invoke-virtual {p0, p2}, Ldev/kawarp/KawarpEngine;->setPlaying(Z)V
invoke-virtual {v0, p2}, Ldev/kawarp/KawarpEngine;->setPlaying(Z)V
invoke-static {p1}, Lradiant/Kawarp;->request(Ljava/lang/String;)V
invoke-static {p0, p1}, Lradiant/Kawarp;->request(ILjava/lang/String;)V
const/high16 p0, 0x3f800000 # 1.0f
@@ -483,9 +481,9 @@
move-object v6, p4
goto :goto_3f
goto :goto_42
:cond_34
:cond_37
const/4 v4, 0x0
const/4 v7, 0x0
@@ -504,35 +502,42 @@
invoke-static/range {v0 .. v7}, Lcom/tidal/android/feature/playerscreen/ui/composables/p3;->a(ILjava/lang/String;ZZLam0/a;Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)V
:goto_3f
:goto_42
invoke-interface {v6}, Landroidx/compose/runtime/Composer;->endReplaceGroup()V
return-void
.end method
.method private static request(Ljava/lang/String;)V
.registers 4
.method private static request(ILjava/lang/String;)V
.registers 5
if-eqz p0, :cond_23
if-eqz p1, :cond_28
invoke-virtual {p0}, Ljava/lang/String;->length()I
invoke-virtual {p1}, Ljava/lang/String;->length()I
move-result v0
if-eqz v0, :cond_23
if-eqz v0, :cond_28
sget-object v0, Lradiant/Kawarp;->requestedUuid:Ljava/lang/String;
invoke-virtual {p0, v0}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
invoke-virtual {p1, v0}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v0
if-eqz v0, :cond_11
goto :goto_23
goto :goto_28
:cond_11
sput-object p0, Lradiant/Kawarp;->requestedUuid:Ljava/lang/String;
sget-object v0, Lradiant/Kawarp;->loader:Lcoil/f;
if-nez v0, :cond_16
return-void
:cond_16
sput-object p1, Lradiant/Kawarp;->requestedUuid:Ljava/lang/String;
sget-object v0, Lradiant/Kawarp;->LOADER:Ljava/util/concurrent/ExecutorService;
@@ -544,12 +549,12 @@
sput v2, Lradiant/Kawarp;->loadToken:I
invoke-direct {v1, p0, v2}, Lradiant/Kawarp;-><init>(Ljava/lang/String;I)V
invoke-direct {v1, p0, p1, v2}, Lradiant/Kawarp;-><init>(ILjava/lang/String;I)V
invoke-interface {v0, v1}, Ljava/util/concurrent/ExecutorService;->execute(Ljava/lang/Runnable;)V
:cond_23
:goto_23
:cond_28
:goto_28
return-void
.end method
@@ -584,8 +589,96 @@
return p0
.end method
.method private static toBitmap(Landroid/graphics/drawable/Drawable;)Landroid/graphics/Bitmap;
.registers 4
if-nez p0, :cond_4
const/4 p0, 0x0
return-object p0
:cond_4
instance-of v0, p0, Landroid/graphics/drawable/BitmapDrawable;
if-eqz v0, :cond_f
check-cast p0, Landroid/graphics/drawable/BitmapDrawable;
invoke-virtual {p0}, Landroid/graphics/drawable/BitmapDrawable;->getBitmap()Landroid/graphics/Bitmap;
move-result-object p0
return-object p0
:cond_f
sget-object v0, Landroid/graphics/Bitmap$Config;->ARGB_8888:Landroid/graphics/Bitmap$Config;
const/16 v1, 0x100
invoke-static {v1, v1, v0}, Landroid/graphics/Bitmap;->createBitmap(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;
move-result-object v0
const/4 v2, 0x0
invoke-virtual {p0, v2, v2, v1, v1}, Landroid/graphics/drawable/Drawable;->setBounds(IIII)V
new-instance v1, Landroid/graphics/Canvas;
invoke-direct {v1, v0}, Landroid/graphics/Canvas;-><init>(Landroid/graphics/Bitmap;)V
invoke-virtual {p0, v1}, Landroid/graphics/drawable/Drawable;->draw(Landroid/graphics/Canvas;)V
return-object v0
.end method
# virtual methods
.method public a(Landroid/graphics/drawable/Drawable;)V
.registers 4
iget v0, p0, Lradiant/Kawarp;->token:I
sget v1, Lradiant/Kawarp;->loadToken:I
if-eq v0, v1, :cond_7
return-void
:cond_7
invoke-static {p1}, Lradiant/Kawarp;->toBitmap(Landroid/graphics/drawable/Drawable;)Landroid/graphics/Bitmap;
move-result-object p1
if-nez p1, :cond_11
invoke-direct {p0}, Lradiant/Kawarp;->fail()V
return-void
:cond_11
sget-object v0, Lradiant/Kawarp;->engine:Ldev/kawarp/KawarpEngine;
invoke-virtual {v0, p1}, Ldev/kawarp/KawarpEngine;->setCover(Landroid/graphics/Bitmap;)V
return-void
.end method
.method public b(Landroid/graphics/drawable/Drawable;)V
.registers 2
return-void
.end method
.method public d(Landroid/graphics/drawable/Drawable;)V
.registers 2
invoke-direct {p0}, Lradiant/Kawarp;->fail()V
return-void
.end method
.method public doFrame(J)V
.registers 5
@@ -610,7 +703,7 @@
return-void
:cond_11
sget-object p1, Lradiant/Kawarp;->frameState:Landroidx/compose/runtime/MutableState;
sget-object p1, Lradiant/Kawarp;->frameState:Landroidx/compose/runtime/MutableIntState;
sget p2, Lradiant/Kawarp;->frameTick:I
@@ -618,11 +711,7 @@
sput p2, Lradiant/Kawarp;->frameTick:I
invoke-static {p2}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
move-result-object p2
invoke-interface {p1, p2}, Landroidx/compose/runtime/MutableState;->setValue(Ljava/lang/Object;)V
invoke-interface {p1, p2}, Landroidx/compose/runtime/MutableIntState;->setIntValue(I)V
invoke-static {}, Lradiant/Kawarp;->schedule()V
@@ -642,206 +731,98 @@
.end method
.method public run()V
.registers 8
.registers 15
const-string v0, "RLKawarp"
:try_start_0
new-instance v0, Lxd0/g;
sget-object v1, Lradiant/Kawarp;->appContext:Landroid/content/Context;
new-instance v2, Lcom/tidal/android/image/core/b$a;
iget v3, p0, Lradiant/Kawarp;->albumId:I
invoke-static {v3}, Ljava/lang/String;->valueOf(I)Ljava/lang/String;
move-result-object v3
iget-object v4, p0, Lradiant/Kawarp;->uuid:Ljava/lang/String;
invoke-direct {v2, v3, v4}, Lcom/tidal/android/image/core/b$a;-><init>(Ljava/lang/String;Ljava/lang/String;)V
const/4 v7, 0x0
const/4 v8, 0x0
const/4 v3, 0x0
const/4 v4, 0x0
const/4 v5, 0x0
const/4 v6, 0x0
invoke-direct/range {v0 .. v8}, Lxd0/g;-><init>(Landroid/content/Context;Lcom/tidal/android/image/core/b;Lcom/tidal/android/image/core/b$h$a;Lcom/tidal/android/image/core/b$h$a;ZLjava/util/List;Lxd0/f;Z)V
const/4 v1, 0x0
:try_start_3
new-instance v2, Ljava/net/URL;
invoke-static {v0, v1}, Lcom/tidal/android/image/coil/c;->a(Lxd0/g;Landroidx/compose/ui/layout/ContentScale;)Lcoil/request/h;
new-instance v3, Ljava/lang/StringBuilder;
move-result-object v0
invoke-direct {v3}, Ljava/lang/StringBuilder;-><init>()V
invoke-static {v0}, Lcoil/request/h;->a(Lcoil/request/h;)Lcoil/request/h$a;
const-string v4, "https://resources.tidal.com/images/"
move-result-object v0
invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
iget-object v1, v0, Lcoil/request/h$a;->b:Lcoil/request/b;
move-result-object v3
new-instance v2, Lcoil/request/b;
iget-object v4, p0, Lradiant/Kawarp;->uuid:Ljava/lang/String;
iget-object v3, v1, Lcoil/request/b;->a:Lkotlinx/coroutines/CoroutineDispatcher;
const/16 v5, 0x2d
iget-object v4, v1, Lcoil/request/b;->b:Lkotlinx/coroutines/CoroutineDispatcher;
const/16 v6, 0x2f
iget-object v5, v1, Lcoil/request/b;->c:Lkotlinx/coroutines/CoroutineDispatcher;
invoke-virtual {v4, v5, v6}, Ljava/lang/String;->replace(CC)Ljava/lang/String;
iget-object v6, v1, Lcoil/request/b;->d:Lkotlinx/coroutines/CoroutineDispatcher;
move-result-object v4
iget-object v7, v1, Lcoil/request/b;->e:Ld0/c$a;
invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
iget-object v8, v1, Lcoil/request/b;->f:Lcoil/size/Precision;
move-result-object v3
iget-object v9, v1, Lcoil/request/b;->g:Landroid/graphics/Bitmap$Config;
const-string v4, "/640x640.jpg"
iget-boolean v10, v1, Lcoil/request/b;->h:Z
invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
iget-object v11, v1, Lcoil/request/b;->i:Lcoil/request/CachePolicy;
move-result-object v3
iget-object v12, v1, Lcoil/request/b;->j:Lcoil/request/CachePolicy;
invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
sget-object v13, Lcoil/request/CachePolicy;->DISABLED:Lcoil/request/CachePolicy;
move-result-object v3
invoke-direct/range {v2 .. v13}, Lcoil/request/b;-><init>(Lkotlinx/coroutines/CoroutineDispatcher;Lkotlinx/coroutines/CoroutineDispatcher;Lkotlinx/coroutines/CoroutineDispatcher;Lkotlinx/coroutines/CoroutineDispatcher;Ld0/c$a;Lcoil/size/Precision;Landroid/graphics/Bitmap$Config;ZLcoil/request/CachePolicy;Lcoil/request/CachePolicy;Lcoil/request/CachePolicy;)V
invoke-direct {v2, v3}, Ljava/net/URL;-><init>(Ljava/lang/String;)V
iput-object v2, v0, Lcoil/request/h$a;->b:Lcoil/request/b;
invoke-virtual {v2}, Ljava/net/URL;->openConnection()Ljava/net/URLConnection;
iput-object p0, v0, Lcoil/request/h$a;->d:Lb0/c;
move-result-object v2
sget-object v1, Lradiant/Kawarp;->loader:Lcoil/f;
check-cast v2, Ljava/net/HttpURLConnection;
:try_end_31
.catchall {:try_start_3 .. :try_end_31} :catchall_7f
invoke-virtual {v0}, Lcoil/request/h$a;->a()Lcoil/request/h;
const/16 v3, 0x2710
move-result-object v0
:try_start_33
invoke-virtual {v2, v3}, Ljava/net/HttpURLConnection;->setConnectTimeout(I)V
invoke-interface {v1, v0}, Lcoil/f;->b(Lcoil/request/h;)Lcoil/request/d;
:try_end_4d
.catchall {:try_start_0 .. :try_end_4d} :catchall_4e
const/16 v3, 0x3a98
goto :goto_52
invoke-virtual {v2, v3}, Ljava/net/HttpURLConnection;->setReadTimeout(I)V
invoke-virtual {v2}, Ljava/net/HttpURLConnection;->getInputStream()Ljava/io/InputStream;
move-result-object v3
:try_end_3f
.catchall {:try_start_33 .. :try_end_3f} :catchall_7d
:try_start_3f
invoke-static {v3}, Landroid/graphics/BitmapFactory;->decodeStream(Ljava/io/InputStream;)Landroid/graphics/Bitmap;
move-result-object v4
:try_end_43
.catchall {:try_start_3f .. :try_end_43} :catchall_78
:try_start_43
invoke-virtual {v3}, Ljava/io/InputStream;->close()V
if-eqz v4, :cond_72
iget v3, p0, Lradiant/Kawarp;->token:I
sget v5, Lradiant/Kawarp;->loadToken:I
if-eq v3, v5, :cond_4f
goto :goto_72
:cond_4f
sget-object v3, Lradiant/Kawarp;->engine:Ldev/kawarp/KawarpEngine;
invoke-virtual {v3, v4}, Ldev/kawarp/KawarpEngine;->setCover(Landroid/graphics/Bitmap;)V
invoke-virtual {v4}, Landroid/graphics/Bitmap;->recycle()V
new-instance v3, Ljava/lang/StringBuilder;
invoke-direct {v3}, Ljava/lang/StringBuilder;-><init>()V
const-string v4, "cover submitted: "
invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v3
iget-object v4, p0, Lradiant/Kawarp;->uuid:Ljava/lang/String;
invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v3
invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v3
invoke-static {v0, v3}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
:try_end_6f
.catchall {:try_start_43 .. :try_end_6f} :catchall_7d
if-eqz v2, :cond_a4
goto :goto_a1
:cond_72
:goto_72
if-eqz v2, :cond_77
invoke-virtual {v2}, Ljava/net/HttpURLConnection;->disconnect()V
:cond_77
return-void
:catchall_78
move-exception v4
:try_start_79
invoke-virtual {v3}, Ljava/io/InputStream;->close()V
throw v4
:try_end_7d
.catchall {:try_start_79 .. :try_end_7d} :catchall_7d
:catchall_7d
move-exception v3
goto :goto_81
:catchall_7f
move-exception v3
move-object v2, v1
:goto_81
:try_start_81
new-instance v4, Ljava/lang/StringBuilder;
invoke-direct {v4}, Ljava/lang/StringBuilder;-><init>()V
const-string v5, "cover load failed: "
invoke-virtual {v4, v5}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v4
invoke-virtual {v4, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/Object;)Ljava/lang/StringBuilder;
move-result-object v3
invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v3
invoke-static {v0, v3}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
iget v0, p0, Lradiant/Kawarp;->token:I
sget v3, Lradiant/Kawarp;->loadToken:I
if-ne v0, v3, :cond_9f
sput-object v1, Lradiant/Kawarp;->requestedUuid:Ljava/lang/String;
:try_end_9f
.catchall {:try_start_81 .. :try_end_9f} :catchall_a5
:cond_9f
if-eqz v2, :cond_a4
:goto_a1
invoke-virtual {v2}, Ljava/net/HttpURLConnection;->disconnect()V
:cond_a4
return-void
:catchall_a5
:catchall_4e
move-exception v0
if-eqz v2, :cond_ab
invoke-direct {p0}, Lradiant/Kawarp;->fail()V
invoke-virtual {v2}, Ljava/net/HttpURLConnection;->disconnect()V
:cond_ab
throw v0
:goto_52
return-void
.end method
@@ -375,7 +375,7 @@
.end method
.method public static parseLines(Ljava/lang/String;)Ljava/util/ArrayList;
.locals 11
.locals 13
:try_start
new-instance v0, Lorg/json/JSONObject;
@@ -466,6 +466,46 @@
double-to-long v7, v7
# Prefer the first syllable time
const-string v6, "syllabus"
invoke-virtual {v4, v6}, Lorg/json/JSONObject;->optJSONArray(Ljava/lang/String;)Lorg/json/JSONArray;
move-result-object v6
if-eqz v6, :no_syl
invoke-virtual {v6}, Lorg/json/JSONArray;->length()I
move-result v9
if-eqz v9, :no_syl
const/4 v9, 0x0
invoke-virtual {v6, v9}, Lorg/json/JSONArray;->optJSONObject(I)Lorg/json/JSONObject;
move-result-object v6
if-eqz v6, :no_syl
const-string v9, "time"
const-wide/16 v11, -0x1
invoke-virtual {v6, v9, v11, v12}, Lorg/json/JSONObject;->optLong(Ljava/lang/String;J)J
move-result-wide v11
const-wide/16 v9, 0x0
cmp-long v6, v11, v9
if-ltz v6, :no_syl
move-wide v7, v11
:no_syl
new-instance v4, Lcom/tidal/android/feature/playerscreen/ui/f;
invoke-direct {v4, v5, v7, v8}, Lcom/tidal/android/feature/playerscreen/ui/f;-><init>(Ljava/lang/String;J)V
+12 -51
View File
@@ -1,11 +1,9 @@
--- a/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
+++ b/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
@@ -4613,8 +4613,10 @@
@@ -4613,8 +4613,8 @@
move-object/from16 v25, v10
+ invoke-static {}, Lradiant/HomeBackdrop;->setModeKawarp()V # RL: mirror the mode to Cover Everywhere
+
.line 171
- invoke-static/range {v16 .. v26}, Lcom/tidal/android/feature/playerscreen/ui/composables/p3;->b(Lcom/tidal/android/feature/playerscreen/ui/model/PlayerBackgroundStyle;JILjava/lang/String;ZZLam0/a;Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)V
+ invoke-static/range {v16 .. v26}, Lradiant/Kawarp;->b(Lcom/tidal/android/feature/playerscreen/ui/model/PlayerBackgroundStyle;JILjava/lang/String;ZZLam0/a;Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)V
@@ -27,53 +25,16 @@
.line 7
--- a/radiant/HomeBackdrop.smali
+++ b/radiant/HomeBackdrop.smali
@@ -83,6 +83,16 @@
return-void
.end method
+.method public static setModeKawarp()V
+ .locals 1
+
+ const/4 v0, 0x3
+
+ sput v0, Lradiant/HomeBackdrop;->mode:I
+
+ return-void
+.end method
+
# from the mini-player state ctor (t.<init>) whenever play state changes.
.method public static onPlayState(Lcom/tidal/android/feature/appscaffold/ui/MiniPlayerContract$PlayState;)V
.locals 2
@@ -363,8 +373,13 @@
const/4 v11, 0x2
+ if-eq v10, v11, :rl_live_play
+
+ const/4 v11, 0x3 # RL: Kawarp follows live play state as well
+
if-ne v10, v11, :rl_mode_done
+ :rl_live_play
sget-object v10, Lradiant/HomeBackdrop;->isPlayingState:Landroidx/compose/runtime/MutableState;
invoke-interface {v10}, Landroidx/compose/runtime/State;->getValue()Ljava/lang/Object;
@@ -378,6 +393,18 @@
move-result v10
:rl_mode_done
+ # RL: Kawarp renders its own AGSL backdrop rather than TIDAL's blurred cover
+ sget v11, Lradiant/HomeBackdrop;->mode:I
+
+ const/4 v12, 0x3
+
+ if-ne v11, v12, :rl_native_backdrop
+
+ invoke-static {v8, v9, v10, v13, v0}, Lradiant/Kawarp;->render(ILjava/lang/String;ZLandroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;)V
+
+ goto :skip
+
+ :rl_native_backdrop
const/4 v11, 0x0 # v11 = isSeeking = false
@@ -358,11 +358,7 @@
const/4 v12, 0x0 # v12 = progress callback = null (unused while not seeking)
- move-object v14, v0 # v14 = composer
-
- const/4 v15, 0x0 # v15 = changed flags
-
- invoke-static/range {v8 .. v15}, Lcom/tidal/android/feature/playerscreen/ui/composables/p3;->a(ILjava/lang/String;ZZLam0/a;Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)V
+ invoke-static {v8, v9, v10, v13, v0}, Lradiant/Kawarp;->render(ILjava/lang/String;ZLandroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;)V # RL: Radiant AGSL backdrop
:skip
invoke-interface {v0}, Landroidx/compose/runtime/Composer;->endReplaceGroup()V
+1 -3
View File
@@ -1,12 +1,10 @@
--- a/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
+++ b/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
@@ -4433,6 +4433,10 @@
@@ -4433,6 +4433,8 @@
move-object/from16 v25, v10
+ sget-object v16, Lcom/tidal/android/feature/playerscreen/ui/model/PlayerBackgroundStyle;->DARK_BLUR:Lcom/tidal/android/feature/playerscreen/ui/model/PlayerBackgroundStyle; # RL: force native Blur player background
+
+ invoke-static {}, Lradiant/HomeBackdrop;->setModePlayback()V # RL: mirror rotation to Cover Everywhere
+
.line 171
invoke-static/range {v16 .. v26}, Lcom/tidal/android/feature/playerscreen/ui/composables/p3;->b(Lcom/tidal/android/feature/playerscreen/ui/model/PlayerBackgroundStyle;JILjava/lang/String;ZZLam0/a;Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)V
+101 -62
View File
@@ -1,14 +1,18 @@
package radiant;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.SystemClock;
import android.util.Log;
import android.view.Choreographer;
import androidx.compose.foundation.layout.SizeKt;
import androidx.compose.foundation.layout.SpacerKt;
import androidx.compose.runtime.Composer;
import androidx.compose.runtime.MutableIntState;
import androidx.compose.runtime.SnapshotIntStateKt;
import androidx.compose.runtime.MutableState;
import androidx.compose.runtime.SnapshotStateKt;
import androidx.compose.ui.Modifier;
@@ -16,15 +20,17 @@ import androidx.compose.ui.draw.DrawModifierKt;
import androidx.compose.ui.geometry.Size;
import androidx.compose.ui.graphics.AndroidCanvas_androidKt;
import androidx.compose.ui.graphics.drawscope.DrawScope;
import androidx.compose.ui.platform.AndroidCompositionLocals_androidKt;
import coil.request.CachePolicy;
import com.tidal.android.feature.playerscreen.ui.composables.p3;
import com.tidal.android.feature.playerscreen.ui.model.PlayerBackgroundStyle;
import com.tidal.android.image.coil.base.CoilImageLoader;
import com.tidal.android.image.core.b;
import dev.kawarp.KawarpEngine;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -33,17 +39,10 @@ import java.util.concurrent.Executors;
*
* The engine (shader, blur pipeline, settings, crossfade) lives in the Kawarp-AGSL library
* (cloned at tools/kawarp-agsl) and is compiled into this bundle by tools/kawarp-build/build.sh;
* this class only holds what is TIDAL/Compose-specific:
* the patched-in composable entry points, cover fetching by TIDAL uuid, the Choreographer ->
* snapshot-state frame clock, the Manager's option tokens, and the fallback to TIDAL's own
* blurred backdrop.
*
* One class on purpose (its own draw lambda, frame callback and loader) - see the engine's
* class doc for the dex-injection constraints.
* this class only holds what is TIDAL/Compose-specific
*/
public final class Kawarp implements am0.l, Runnable, Choreographer.FrameCallback {
public final class Kawarp implements am0.l, Runnable, Choreographer.FrameCallback, b0.c {
private static final String TAG = "RLKawarp";
/** Stop the frame loop once nothing has drawn for this long (player left / backgrounded). */
private static final long IDLE_STOP_MS = 500L;
@@ -56,34 +55,42 @@ public final class Kawarp implements am0.l, Runnable, Choreographer.FrameCallbac
private static final ExecutorService LOADER = Executors.newSingleThreadExecutor();
/** Bumped every frame so the draw lambda's snapshot read invalidates the draw phase. */
private static final MutableState frameState =
SnapshotStateKt.mutableStateOf$default(Integer.valueOf(0), null, 2, null);
/**
* Bumped every frame so the draw lambda's snapshot read invalidates the draw phase.
* An int state rather than MutableState<Integer>: this ticks at 60 Hz, and boxing here
* would allocate an Integer per frame for nothing.
*/
private static final MutableIntState frameState = SnapshotIntStateKt.mutableIntStateOf(0);
/** Flips true on any shader failure; read during composition so we recompose onto p3.a. */
private static final MutableState fallbackState =
SnapshotStateKt.mutableStateOf$default(Boolean.FALSE, null, 2, null);
/** The shared instance render passes to drawBehind (also serves as the frame callback). */
private static final Kawarp DRAW = new Kawarp(null, 0);
private static final Kawarp DRAW = new Kawarp(0, null, 0);
private static KawarpEngine engine;
/** TIDAL's application-scoped Coil loader and the context its requests are built with. */
private static volatile coil.f loader;
private static volatile Context appContext;
private static volatile String requestedUuid;
private static volatile int loadToken;
private static long lastDrawUptime;
private static boolean frameScheduled, loggedDraw;
private static boolean frameScheduled;
private static int frameTick;
/** Set when this instance is a queued cover load; null/0 on the shared DRAW instance. */
/** Set when this instance is a queued cover load; 0/null/0 on the shared DRAW instance. */
private final int albumId;
private final String uuid;
private final int token;
private Kawarp(String uuid, int token) {
private Kawarp(int albumId, String uuid, int token) {
this.albumId = albumId;
this.uuid = uuid;
this.token = token;
}
// Composition
@@ -101,19 +108,39 @@ public final class Kawarp implements am0.l, Runnable, Choreographer.FrameCallbac
public static void render(int albumId, String coverUuid, boolean isPlaying,
Modifier modifier, Composer composer) {
composer.startReplaceGroup(0x52415750);
attach(composer);
boolean ok = !((Boolean) fallbackState.getValue()).booleanValue() && ensureEngine();
if (!ok) {
// No (working) AGSL here - fall back to TIDAL's own blurred backdrop.
p3.a(albumId, coverUuid, isPlaying, false, null, modifier, composer, 0);
} else {
engine.setPlaying(isPlaying);
request(coverUuid);
request(albumId, coverUuid);
Modifier m = DrawModifierKt.drawBehind(SizeKt.fillMaxSize(modifier, 1.0f), DRAW);
SpacerKt.Spacer(m, composer, 0);
}
composer.endReplaceGroup();
}
/**
* Grab the app's image loader the same way TIDAL's composables do (yd0.c)
*/
private static void attach(Composer composer) {
if (loader != null) return;
try {
Object local = composer.consume(AndroidCompositionLocals_androidKt.getLocalContext());
if (!(local instanceof Context)) return;
Context app = ((Context) local).getApplicationContext();
if (!(app instanceof ce0.b.a)) return;
Object tidalLoader = ((ce0.b.a) app).a().a();
if (!(tidalLoader instanceof CoilImageLoader)) return;
appContext = app;
loader = ((CoilImageLoader) tidalLoader).a;
} catch (Throwable t) {
// No loader -> request() never runs and the backdrop simply stays on the last cover.
}
}
/** Engine construction compiles the AGSL so this doubles as the support probe. */
private static boolean ensureEngine() {
if (engine != null) return true;
@@ -133,52 +160,69 @@ public final class Kawarp implements am0.l, Runnable, Choreographer.FrameCallbac
engine = e;
return true;
} catch (Throwable t) {
Log.i(TAG, "AGSL rejected, staying on the native backdrop: " + t);
fallbackState.setValue(Boolean.TRUE);
fallbackState.setValue(Boolean.TRUE); // AGSL rejected: stay on the native backdrop
return false;
}
}
// Cover loading (Runnable on LOADER)
private static void request(String coverUuid) {
// Cover loading: a queued Kawarp is both the LOADER task and the request's Coil Target
private static void request(int albumId, String coverUuid) {
if (coverUuid == null || coverUuid.length() == 0 || coverUuid.equals(requestedUuid)) return;
if (loader == null) return; // attach() failed; retried next composition
requestedUuid = coverUuid;
LOADER.execute(new Kawarp(coverUuid, ++loadToken));
LOADER.execute(new Kawarp(albumId, coverUuid, ++loadToken));
}
/**
* TIDAL's own backdrop request (PlayerBackgroundKt.rememberBlurredArtwork)
*/
public void run() {
HttpURLConnection connection = null;
try {
// Same URL shape TIDAL itself builds in he0.a; 640 is plenty ahead of a 128 downscale.
URL url = new URL("https://resources.tidal.com/images/"
+ uuid.replace('-', '/') + "/640x640.jpg");
connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(10000);
connection.setReadTimeout(15000);
InputStream stream = connection.getInputStream();
Bitmap source;
try {
source = BitmapFactory.decodeStream(stream);
} finally {
stream.close();
}
if (source == null || token != loadToken) return;
engine.setCover(source);
source.recycle();
Log.i(TAG, "cover submitted: " + uuid);
xd0.g tidal = new xd0.g(appContext, new b.a(String.valueOf(albumId), uuid),
null, null, false, null, null, false);
coil.request.h.a req = coil.request.h.a(com.tidal.android.image.coil.c.a(tidal, null));
coil.request.b d = req.b;
req.b = new coil.request.b(d.a, d.b, d.c, d.d, d.e, d.f, d.g, d.h,
d.i, d.j, CachePolicy.DISABLED);
req.d = this;
loader.b(req.a());
} catch (Throwable t) {
Log.i(TAG, "cover load failed: " + t);
// Let the next track (or a re-entry into the player) retry this cover.
if (token == loadToken) requestedUuid = null;
} finally {
if (connection != null) connection.disconnect();
fail();
}
}
/** Target.onSuccess */
public void a(Drawable drawable) {
if (token != loadToken) return; // user skipped on
Bitmap cover = toBitmap(drawable);
if (cover == null) { fail(); return; }
// setCover copies, the bitmap stays Coil's (memory cache)
engine.setCover(cover);
}
/** Target.onStart - nothing to show while loading. */
public void b(Drawable placeholder) {}
/** Target.onError - not in any of TIDAL's stores. */
public void d(Drawable error) { fail(); }
private void fail() {
if (token == loadToken) requestedUuid = null;
}
private static Bitmap toBitmap(Drawable d) {
if (d == null) return null;
if (d instanceof BitmapDrawable) return ((BitmapDrawable) d).getBitmap();
Bitmap out = Bitmap.createBitmap(256, 256, Bitmap.Config.ARGB_8888);
d.setBounds(0, 0, 256, 256);
d.draw(new Canvas(out));
return out;
}
// Frame loop
@@ -186,7 +230,7 @@ public final class Kawarp implements am0.l, Runnable, Choreographer.FrameCallbac
frameScheduled = false;
// Nothing has drawn for a while: the backdrop is off-screen, so stop burning frames.
if (SystemClock.uptimeMillis() - lastDrawUptime > IDLE_STOP_MS) return;
frameState.setValue(Integer.valueOf(++frameTick));
frameState.setIntValue(++frameTick);
schedule();
}
@@ -203,23 +247,18 @@ public final class Kawarp implements am0.l, Runnable, Choreographer.FrameCallbac
private static void draw(DrawScope scope) {
// Snapshot read: this is what ties the draw phase to the frame clock.
frameState.getValue();
frameState.getIntValue();
lastDrawUptime = SystemClock.uptimeMillis();
schedule();
long packed = scope.getSizeNHjbRc();
float width = Size.getWidthImpl(packed);
float height = Size.getHeightImpl(packed);
if (!loggedDraw) {
loggedDraw = true;
Log.i(TAG, "first draw: " + width + "x" + height + " ready=" + engine.isReady());
}
try {
engine.draw(AndroidCanvas_androidKt.getNativeCanvas(scope.getDrawContext().getCanvas()),
width, height);
} catch (Throwable t) {
Log.i(TAG, "AGSL draw failed, falling back: " + t);
fallbackState.setValue(Boolean.TRUE);
fallbackState.setValue(Boolean.TRUE); // AGSL draw failed: recompose onto p3.a
}
}
}
@@ -2,4 +2,5 @@ package androidx.compose.runtime;
public interface Composer {
void startReplaceGroup(int key);
void endReplaceGroup();
Object consume(CompositionLocal key);
}
@@ -0,0 +1,2 @@
package androidx.compose.runtime;
public abstract class CompositionLocal {}
@@ -0,0 +1,5 @@
package androidx.compose.runtime;
public interface MutableIntState extends State {
int getIntValue();
void setIntValue(int value);
}
@@ -0,0 +1,2 @@
package androidx.compose.runtime;
public abstract class ProvidableCompositionLocal extends CompositionLocal {}
@@ -0,0 +1,4 @@
package androidx.compose.runtime;
public final class SnapshotIntStateKt {
public static MutableIntState mutableIntStateOf(int value) { return null; }
}
@@ -0,0 +1,2 @@
package androidx.compose.ui.layout;
public interface ContentScale {}
@@ -0,0 +1,5 @@
package androidx.compose.ui.platform;
import androidx.compose.runtime.ProvidableCompositionLocal;
public final class AndroidCompositionLocals_androidKt {
public static ProvidableCompositionLocal getLocalContext() { return null; }
}
+8
View File
@@ -0,0 +1,8 @@
package b0;
import android.graphics.drawable.Drawable;
/** coil.target.Target (R8 name in TIDAL 2.200): a=onSuccess, b=onStart, d=onError. */
public interface c {
void a(Drawable success);
void b(Drawable start);
void d(Drawable error);
}
+6
View File
@@ -0,0 +1,6 @@
package ce0;
/** Dagger image component; the Application implements b.a and hands out the loader. */
public interface b {
xd0.e a();
interface a { b a(); }
}
+5
View File
@@ -0,0 +1,5 @@
package coil;
/** coil.ImageLoader; b() is enqueue(). */
public interface f {
coil.request.d b(coil.request.h request);
}
@@ -0,0 +1,2 @@
package coil.request;
public enum CachePolicy { ENABLED, READ_ONLY, WRITE_ONLY, DISABLED }
@@ -0,0 +1,19 @@
package coil.request;
import kotlinx.coroutines.CoroutineDispatcher;
/**
* coil.request.DefaultRequestOptions; i/j/k are the memory/disk/network cache policies (proven
* via h$a.a() -> ImageRequest.o/p/q -> Options.m/n/o, the last of which HttpUriFetcher gates on).
* Fields are deliberately non-final: a `final boolean h = false` would be a compile-time constant
* and javac would fold the read away instead of emitting iget-boolean. (claude)
*/
public final class b {
public CoroutineDispatcher a, b, c, d;
public d0.c.a e;
public coil.size.Precision f;
public android.graphics.Bitmap.Config g;
public boolean h;
public CachePolicy i, j, k;
public b(CoroutineDispatcher a, CoroutineDispatcher b, CoroutineDispatcher c, CoroutineDispatcher d,
d0.c.a transition, coil.size.Precision precision, android.graphics.Bitmap.Config config,
boolean h, CachePolicy memory, CachePolicy disk, CachePolicy network) {}
}
@@ -0,0 +1,3 @@
package coil.request;
/** coil.request.Disposable */
public interface d {}
@@ -0,0 +1,12 @@
package coil.request;
/** coil.request.ImageRequest; a(h) is newBuilder(), h.a is the Builder. */
public final class h {
public static a a(h request) { return null; }
public static final class a {
/** defaults block the built request copies its cache policies from */
public b b;
/** target */
public b0.c d;
public h a() { return null; }
}
}
@@ -0,0 +1,2 @@
package coil.size;
public enum Precision { EXACT, INEXACT, AUTOMATIC }
@@ -0,0 +1,5 @@
package com.tidal.android.image.coil.base;
/** TIDAL's xd0.e implementation; a is the underlying Coil ImageLoader. */
public final class CoilImageLoader implements xd0.e {
public final coil.f a = null;
}
@@ -0,0 +1,5 @@
package com.tidal.android.image.coil;
/** TIDAL request -> Coil request; installs the AlbumCover data the interceptor resolves. */
public final class c {
public static coil.request.h a(xd0.g request, androidx.compose.ui.layout.ContentScale scale) { return null; }
}
@@ -0,0 +1,7 @@
package com.tidal.android.image.core;
/** TIDAL's sealed image-source type; b$a is AlbumCover(albumId, coverUuid). */
public abstract class b {
public static final class a extends b { public a(String albumId, String cover) {} }
/** b$h = a resolved location; b$h$a is the placeholder/error drawable spec. */
public interface h { interface a {} }
}
+3
View File
@@ -0,0 +1,3 @@
package d0;
/** coil.transition.Transition; c.a is Transition.Factory. */
public interface c { interface a {} }
@@ -0,0 +1,2 @@
package kotlinx.coroutines;
public abstract class CoroutineDispatcher {}
+3
View File
@@ -0,0 +1,3 @@
package xd0;
/** TIDAL's ImageLoader interface (implemented by CoilImageLoader). */
public interface e {}
+3
View File
@@ -0,0 +1,3 @@
package xd0;
/** Size spec wrapper accepted by xd0.g's constructor; we always pass null. */
public final class f {}
+8
View File
@@ -0,0 +1,8 @@
package xd0;
import android.content.Context;
import com.tidal.android.image.core.b;
/** TIDAL's ImageRequest. */
public final class g {
public g(Context context, b source, b.h.a placeholder, b.h.a error, boolean crossfade,
java.util.List transformations, f size, boolean allowHardware) {}
}