Skip to content

v0.3.0#9

Merged
kxxoling merged 15 commits into
mainfrom
dev
Jun 20, 2026
Merged

v0.3.0#9
kxxoling merged 15 commits into
mainfrom
dev

Conversation

@kxxoling

Copy link
Copy Markdown
Owner

No description provided.

kxxoling added 15 commits June 15, 2026 01:48
…tings hot-reload and frame pacing

- Move renderer.release() off the main thread into the GL thread's finally
  block (called while the EGL context is still current); previously it ran
  from onDestroy on a thread with no current context and silently no-op'd.
- stopGLThread() now joins (with timeout + interrupt fallback) the previous
  thread before nulling the reference, fixing the race where rapid visibility
  toggles could spawn overlapping GL threads competing for the same Surface
  and EGL display.
- registerReceiver now uses ContextCompat + RECEIVER_NOT_EXPORTED to avoid
  the SecurityException on Android 14+ (targetSdk 36).
- Register a SharedPreferences.OnSharedPreferenceChangeListener so template /
  portrait-effect changes apply live instead of only after toggling visibility.
- Replace fixed Thread.sleep(16) with nanoTime-based adaptive frame pacing
  (better on 120Hz devices and slow GPUs).
- Log render-loop exceptions instead of swallowing them silently.
- destroyEGL: null out surface/context handles after teardown.
fix(wallpaper): correct GL thread lifecycle, Android 14 receiver, settings hot-reload and frame pacing
Some vendors report a 5th 'heading' element for TYPE_ROTATION_VECTOR, which
makes SensorManager.getRotationMatrixFromVector throw
IllegalArgumentException and crash the wallpaper. Truncate values to the
first 4 elements before the call.

Also replace Math.sqrt(Double) with kotlin.math.sqrt(Float) to avoid the
double round-trip in the accelerometer fallback path.
fix(sensor): guard getRotationMatrixFromVector against length-5 values
…bs, i18n)

- Directory import: resolve wallpaper/portrait paths via canonical-path
  comparison (safeResolveChild); reject entries escaping source/target dir.
  Previously File(sourceDir, name) allowed ../ traversal writes.
- ZIP extraction: authoritative byte-count limit per entry (copyToWithLimit)
  plus 200MB total-decompressed budget. ZipEntry.size is attacker-controlled
  and was the only cap, enabling decompression bombs.
- deleteTemplate: validate id regex and canonical path before recursive delete.
- First pass: reject absolute paths instead of naive '..' substring match.
- Fix ZipInputStream closed prematurely by bufferedReader().readText() while
  scanning template.json; use readBytes() instead.

HTTP & i18n (per review):
- HTTP is no longer hard-rejected: importFromUrl throws HttpProtocolException so
  the settings UI shows a confirmation dialog; if the user trusts the source
  (community-shared packs) it retries with allowHttp=true. HTTPS passes through.
- New text prompts use string resources (default values/ = English, values-zh/
  = Chinese): HTTP warning dialog and the path-traversal / extracted-total
  errors. TemplateLoadException carries an optional messageResId + args so the
  loader (no Context) can surface localized strings; the UI resolves them via
  getString. Existing error literals are untouched.
- New-code comments are in English; existing behavior sections left as-is.

Tests:
- Real unit + integration tests covering safeResolveChild, copyToWithLimit,
  end-to-end zip/dir import, traversal rejection and overwrite handling; the
  traversal test asserts the localized resource id rather than the literal text.
- Enable unitTests.isReturnDefaultValues and add a real org.json test impl so
  Log/JSON-backed code becomes unit-testable.
fix(security): harden remote template import (path traversal, ZIP bombs) with HTTP warning
trimOldLogs captured files.size once outside the loop and never updated the
condition, so once >=10 logs existed every new crash erased ALL of them rather
than keeping the newest 9. Extract logsToTrim() (now unit-tested) and delete
only the oldest surplus files.
- SettingsActivity used remember { CoroutineScope(Dispatchers.Main) } whose
  coroutines outlived the Activity; switch to rememberCoroutineScope()
  (cancelled on leaving composition).
- Local import used fixed names local_import.zip / local_import_dir in the
  cache dir; concurrent/double imports overwrote each other. Use
  File.createTempFile and a UUID-suffixed temp dir.
- lerp now clamps t to [0,1] defensively (its callers currently only pass 0/1
  but the smoothing path could overshoot by epsilon).
- selectRandomLayout used biased System.nanoTime() % size; switch to
  Random.nextInt.
- LICENSE: fix 'ropyright' typo.
- AndroidManifest: remove unused READ_EXTERNAL_STORAGE (file access goes through
  SAF/MediaStore, never the legacy storage permission).
- LicenseActivity: point the project URL at the canonical kxxoling/FloatDeck
  (was windrunner/FloatDeck, inconsistent with README/UpdateChecker/git remote).
- README: simplify the project structure to package-level (easier to maintain).
chore: docs accuracy and drop unused storage permission
Adds values-ja/ and values-ko/ mirroring the full default string set (76 each,
matching values/ and values-zh/), so Japanese and Korean users get a fully
localized UI. Motivated by growing JP traffic.
@kxxoling kxxoling merged commit e4935d4 into main Jun 20, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant