One4HomeGet the app

For Android developers · Integration kit 1.0.2

Your wallpapers.
One clear connection.

Let One4Home’s Glass and Acrylic show the wallpaper your app actually applies. Add one Kotlin helper, ask the user to connect, then share the exact image after a successful Home wallpaper change.

  • One4Home 0.5.80 (392)+
  • MIT license
  • No API key or account
  • No service or polling

Keep your existing apply flow

Your app sets the wallpaper with Android’s WallpaperManager. The bridge then gives One4Home a private copy of that same static image for its wallpaper-based surfaces. It does not open Home, add a background service or unlock Pro features.

This protocol supports static Home wallpapers, including Home + Lock together. Live/video wallpaper services and Lock-only changes use a separate pipeline.

Step 1

Add the helper

Download the kit and copy One4HomeWallpaperBridge.kt into your Android app. Keep its package, or adjust the import to match yours. Use your existing compatible AndroidX Core dependency for FileProvider; the tested library uses androidx.core:core-ktx:1.17.0.

The helper supports API 23+. The apply example below uses API 24+; One4Home itself requires Android 10 / API 29+. This is a source integration, with no published Maven coordinate to add.

Step 2

Share one dedicated directory

Merge these declarations into your existing manifest. The package query lets Android resolve One4Home for URI permissions. SET_WALLPAPER belongs to your normal wallpaper apply flow.

AndroidManifest.xml — merge into your appDownload file ↓
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.SET_WALLPAPER" />
    <queries>
        <package android:name="com.one4studio.one4home" />
    </queries>
    <application>
        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.one4home.bridge"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/one4home_bridge_paths" />
        </provider>
    </application>
</manifest>

Save the following as res/xml/one4home_bridge_paths.xml. Only place images intended for this connection in cacheDir/one4home-bridge/. Keep the authority exactly ${applicationId}.one4home.bridge.

res/xml/one4home_bridge_paths.xmlDownload file ↓
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <cache-path name="applied" path="one4home-bridge/" />
</paths>

Step 3

Let the user connect

Use AndroidX Activity Result from a visible Activity when the user taps your Connect to One4Home action. One4Home shows your verified app name and asks for permission. Enable sharing only after Activity.RESULT_OK. A plain startActivity has no verified result caller and is rejected.

Connection — inside an AndroidX ComponentActivityDownload file ↓
// In an AndroidX ComponentActivity. Register before the Activity is started.
private val connectOne4Home = registerForActivityResult(
    ActivityResultContracts.StartActivityForResult()
) { result ->
    if (result.resultCode == Activity.RESULT_OK) {
        // Remember the opt-in locally; offer a disconnect action in your app.
        // Do not reconnect automatically or repeatedly show the consent prompt.
        preferences.edit().putBoolean("one4home_connected", true).apply()
    }
}

// Run only when the user taps your "Connect to One4Home" button.
fun connectToOne4Home() {
    try {
        connectOne4Home.launch(One4HomeWallpaperBridge.connectionIntent())
    } catch (_: ActivityNotFoundException) {
        // Show an install/update option for One4Home 0.5.80 (392) or newer.
    }
}

This fragment assumes an existing SharedPreferences instance named preferences. Import the Android and AndroidX Activity Result classes plus com.one4studio.wallpaperbridge.One4HomeWallpaperBridge. Register the callback before the Activity is started.

The connection is bound to the installed signing certificate. Offer a disconnect action in your wallpaper app that stops further sharing; users do not configure the integration in One4Home settings. Your saved preference is not proof of an active grant: revoked imports are ignored. Offer reconnect only when the user requests it.

Step 4

Notify after a successful Home apply

Use the wallpaper ID returned by your existing successful setStream call. Share the final image with the same crop and orientation. Do not apply twice, send a thumbnail or substitute an uncropped original.

Apply hook — worker threadDownload file ↓
// Run on a worker thread, as part of your EXISTING successful apply flow.
// croppedImage is your exact final Home image, including crop and orientation.
val bridgeDirectory = File(context.cacheDir, "one4home-bridge").apply { mkdirs() }
val appliedFile = File.createTempFile("applied-", ".jpg", bridgeDirectory)
croppedImage.copyTo(appliedFile, overwrite = true)

// For Home + Lock use FLAG_SYSTEM or FLAG_LOCK. Never notify for Lock only.
val wallpaperId = appliedFile.inputStream().use { stream ->
    WallpaperManager.getInstance(context).setStream(
        stream, null, true, WallpaperManager.FLAG_SYSTEM
    )
}

if (wallpaperId > 0 && preferences.getBoolean("one4home_connected", false)) {
    // Bridge failure must not turn an already successful wallpaper apply into an error.
    runCatching {
        One4HomeWallpaperBridge.notifyApplied(
            context, appliedFile, wallpaperId, mimeType = "image/jpeg"
        )
    }
}
// Keep this uniquely named file after dispatch: the receiver runs asynchronously.
// During your existing cache cleanup (e.g. after 24 hours), first call
// One4HomeWallpaperBridge.revoke(context, appliedFile), then delete the file.
// Do not revoke or delete it in a finally block immediately after dispatch.

This fragment assumes context, preferences and croppedImage: File already exist. For PNG images, preserve the PNG bytes and use a .png file and image/png. For Home + Lock, use FLAG_SYSTEM or FLAG_LOCK and notify once. Never notify for a Lock-only change.

File lifetime and optional depth

Use a unique file for every apply. Broadcast dispatch is asynchronous and has no import-complete acknowledgement: keep the file available, for example for 24 hours. During your existing cache cleanup, call One4HomeWallpaperBridge.revoke(context, file) before deleting each expired image or depth file. Do not revoke or delete immediately after sending.

One4Home makes a bounded private copy and ignores stale wallpaper IDs. Images above 64 MiB are rejected. Do not grant access to the whole cache directory or request persistable URI permissions. An Android cache eviction or a missed import must not fail your normal wallpaper apply.

The optional depth: File? argument accepts a transparent PNG in the same directory, matching the image’s dimensions, crop and orientation. Invalid layers are rejected; users still need the corresponding One4Home feature and settings.

Before you ship

  • Missing or older One4Home: offer install/update; ordinary wallpaper application still works.
  • Cancel consent: do not enable sharing. Approve: apply a distinctive image and check Glass/Acrylic when returning to Home.
  • Test Home, Home + Lock and Lock only. Notify only when Home changes.
  • Disable the connection in your app and confirm ordinary wallpaper application still works without sending bridge imports.
  • Apply two images quickly: the latest image wins and stale IDs are ignored.
  • Check the exact crop on phones, landscape and both foldable screens. Android/OEM wallpaper scaling can differ.

For a local debug build, add com.one4studio.one4home.debug to your debug manifest queries and pass it as homePackage to the helper calls, including cleanup. Production uses the default package.

The helper and actual FileProvider grant/import flow were verified in One4Home’s native emulator fixture. Verify your own app on your target devices.

The full Kotlin helper

This is the exact helper shipped with One4Home 0.5.80 (392). The kit also includes the manifest, path XML, connection/apply fragments, README, license and version metadata.

View One4HomeWallpaperBridge.kt
One4HomeWallpaperBridge.ktDownload file ↓
package com.one4studio.wallpaperbridge

import android.content.ClipData
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.core.content.FileProvider
import java.io.File

/** Copyable AndroidX helper. Connect with StartActivityForResult, then notify after a successful Home apply. */
object One4HomeWallpaperBridge {
    const val HOME_PACKAGE = "com.one4studio.one4home"
    fun connectionIntent(homePackage: String = HOME_PACKAGE): Intent = Intent().setClassName(
        homePackage, "com.one4studio.one4home.ConnectWallpaperActivity")

    /** Call when expiring a shared cache file, after allowing time for asynchronous delivery. */
    fun revoke(context: Context, file: File, homePackage: String = HOME_PACKAGE) {
        val uri = FileProvider.getUriForFile(context, "${context.packageName}.one4home.bridge", file)
        if (android.os.Build.VERSION.SDK_INT >= 26) context.revokeUriPermission(homePackage, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
        else context.revokeUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
    }

    /** The exact file applied to FLAG_SYSTEM; wallpaperId is WallpaperManager.setStream's returned ID. */
    fun notifyApplied(context: Context, image: File, wallpaperId: Int, depth: File? = null,
        mimeType: String = "image/jpeg", homePackage: String = HOME_PACKAGE) {
        require(wallpaperId > 0) { "A successful system wallpaper apply is required" }
        require(mimeType.startsWith("image/"))
        val authority = "${context.packageName}.one4home.bridge"
        val uri = FileProvider.getUriForFile(context, authority, image)
        val depthUri = depth?.let { FileProvider.getUriForFile(context, authority, it) }
        val intent = Intent("com.one4studio.one4home.IMPORT_STATIC_WALLPAPER_SOURCE")
            .setClassName(homePackage, "com.one4studio.one4home.WallpaperSourceImportReceiver")
            .setDataAndType(uri, mimeType)
            .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
            .putExtra("com.one4studio.one4home.extra.WALLPAPER_ID", wallpaperId)
            .putExtra("com.one4studio.one4home.extra.REQUEST_DEPTH", false)
        intent.clipData = ClipData.newRawUri("Applied wallpaper", uri).apply {
            depthUri?.let { addItem(ClipData.Item(it)) }
        }
        depthUri?.let { intent.putExtra("com.one4studio.one4home.extra.DEPTH_SOURCE", it.toString()) }
        // Manifest receivers do not receive Activity-lifetime URI grants reliably on all Android versions.
        context.grantUriPermission(homePackage, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
        depthUri?.let { context.grantUriPermission(homePackage, it, Intent.FLAG_GRANT_READ_URI_PERMISSION) }
        context.sendBroadcast(intent)
    }
}

Download the complete kit · SHA-256 checksum · MIT license · Plain-text guide

Building an integration?

Send your app name, package and the exact apply flow to support.one4studio@gmail.com.

Android references: WallpaperManager and FileProvider. Explore the One4Home Help Center →