The Android 12+ SplashScreen API
Starting with Android 12 (API 31), the platform enforces a standardized splash screen for every app launch. The old approach of defining a custom windowBackground drawable in your theme is no longer sufficient on its own. Android now manages the splash screen lifecycle directly, displaying a branded launch experience that consists of a centered app icon on a solid background color, with optional animation support.
This system-level splash screen appears during the cold start, warm start, and even hot start transitions. It cannot be disabled. If you do not configure it, the system falls back to your adaptive icon and your theme's windowBackground color. Understanding how to properly configure and supply the right assets ensures your app makes a polished first impression across all device densities.
For a deeper understanding of how density-independent pixels work on Android, see the complete DPI guide.
Splash Screen Components
The Android 12+ splash screen is composed of four configurable elements:
- App icon (centered) — The primary visual element. This is an adaptive icon displayed inside a circular mask. The icon occupies the center of the screen and must conform to the adaptive icon safe zone to avoid clipping.
- Icon background — An optional background layer behind the icon, useful when your icon requires contrast against the window background. Set via
windowSplashScreenIconBackgroundColor. - Window background color — A single opaque color that fills the entire screen behind the icon. Configured through
windowSplashScreenBackgroundor inherited from your theme'scolorBackground. - Branding image (optional) — A small image placed at the bottom of the splash screen, typically a company logo. Set via
windowSplashScreenBrandingImage. Google discourages its use, and it is not available through the compat library.
Additionally, Android 12 supports animated splash icons using AnimatedVectorDrawable. Animated icons follow the same sizing constraints but allow frame-based or path-morphing animations that play once during the splash transition. The animation duration is capped at 1000 milliseconds.
Splash Icon Sizing and the Circle Mask
The splash screen icon follows adaptive icon conventions. Each adaptive icon layer is 108 dp, but only the inner 72 dp (two-thirds) is guaranteed to be visible after the system applies a circular mask. For the splash screen specifically, the icon must fit within a 240 dp circle on the screen, but at the asset level you supply an adaptive icon where the visible content sits inside the inner 72 dp of the 108 dp canvas.
The following table lists the required icon asset sizes per density bucket. These dimensions apply to the full adaptive icon canvas (foreground and background layers). Keep critical artwork within the inner two-thirds.
| Density | Scale | Icon layer size | Visible area (circle) |
|---|---|---|---|
| mdpi | 1x | 108 x 108 px | 72 x 72 px |
| hdpi | 1.5x | 162 x 162 px | 108 x 108 px |
| xhdpi | 2x | 216 x 216 px | 144 x 144 px |
| xxhdpi | 3x | 324 x 324 px | 216 x 216 px |
| xxxhdpi | 4x | 432 x 432 px | 288 x 288 px |
For the optional branding image, the recommended maximum height is 80 dp (200 px at xxxhdpi). Keep the branding image narrow and legible, as the system will not scale it. For full details on how drawable density folders work, see the Android drawable sizes guide.
Implementation: themes.xml Configuration
To customize the splash screen on Android 12+, override the relevant attributes in your app's theme. The following example shows a typical res/values-v31/themes.xml configuration:
<resources>
<style name="Theme.MyApp" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<!-- Splash screen attributes (API 31+) -->
<item name="android:windowSplashScreenBackground">@color/splash_bg</item>
<item name="android:windowSplashScreenAnimatedIcon">@drawable/ic_splash</item>
<item name="android:windowSplashScreenAnimationDuration">800</item>
<item name="android:windowSplashScreenIconBackgroundColor">@color/icon_bg</item>
</style>
</resources> The windowSplashScreenAnimatedIcon attribute accepts both static and animated drawables. If you use an AnimatedVectorDrawable, set windowSplashScreenAnimationDuration to match the animation length (maximum 1000 ms).
SplashScreen Compat Library
To provide a consistent splash screen experience across Android 6 (API 23) through Android 14+ while using the new API surface, add the AndroidX SplashScreen compat library:
// build.gradle (app module)
dependencies {
implementation "androidx.core:core-splashscreen:1.0.1"
} Then update your base theme (in res/values/themes.xml) to use the compat parent:
<style name="Theme.MyApp.Splash" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">@color/splash_bg</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/ic_splash</item>
<item name="postSplashScreenTheme">@style/Theme.MyApp</item>
</style> In your launcher activity, call installSplashScreen() before super.onCreate():
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
val splashScreen = installSplashScreen()
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}The compat library backports the splash screen behavior to older API levels, using a theme-based approach under the hood while exposing the same API. On API 31+ it delegates to the native implementation.
Handling the Splash-to-Main Transition
The splash screen is dismissed as soon as your app draws its first frame. If your app needs to load data before displaying meaningful content (network requests, database queries, dependency injection), you can keep the splash visible by installing a setKeepOnScreenCondition callback:
val splashScreen = installSplashScreen()
splashScreen.setKeepOnScreenCondition {
// Return true while loading; false to dismiss
viewModel.isLoading.value
} You can also customize the exit animation using setOnExitAnimationListener. This gives you access to the splash screen view, which you can animate (fade, slide, scale) before removing it:
splashScreen.setOnExitAnimationListener { splashScreenView ->
val fadeOut = ObjectAnimator.ofFloat(splashScreenView.view, View.ALPHA, 1f, 0f)
fadeOut.duration = 300L
fadeOut.doOnEnd { splashScreenView.remove() }
fadeOut.start()
}Avoid keeping the splash screen visible for too long. Android vitals tracks startup latency, and an artificially prolonged splash contributes to a poor Time to Initial Display (TTID) metric.
Legacy Splash Screen (Pre-Android 12)
Before Android 12, the standard approach was to create a custom theme with a windowBackground drawable and assign it to the launcher activity. This drawable could be a layer-list containing a background color and a centered bitmap, or a full-screen raster image.
<!-- res/values/themes.xml (legacy approach) -->
<style name="Theme.MyApp.Splash" parent="Theme.AppCompat.NoActionBar">
<item name="android:windowBackground">@drawable/splash_background</item>
</style>
<!-- res/drawable/splash_background.xml -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/splash_bg" />
<item android:gravity="center">
<bitmap android:src="@drawable/logo_splash" />
</item>
</layer-list>If you used full-screen raster splash images, you needed a different asset for every screen density and common resolution. The table below lists typical sizes:
| Density | Scale | Portrait (px) | Landscape (px) |
|---|---|---|---|
| mdpi | 1x | 320 x 480 | 480 x 320 |
| hdpi | 1.5x | 480 x 800 | 800 x 480 |
| xhdpi | 2x | 720 x 1280 | 1280 x 720 |
| xxhdpi | 3x | 1080 x 1920 | 1920 x 1080 |
| xxxhdpi | 4x | 1440 x 2560 | 2560 x 1440 |
The legacy approach still works on Android 12+ as a fallback, but the system will always display its own splash screen first. If you are migrating to the new API, remove the old splash activity or theme override once you have adopted the compat library to avoid showing a splash twice.
Best Practices
- Design at the highest density first. Create your splash icon at 432 px (xxxhdpi adaptive icon canvas) and scale down. Downscaling preserves quality; upscaling does not.
- Respect the safe zone. Place all critical artwork within the inner 72 dp circle of the 108 dp adaptive icon canvas. Content outside this area will be clipped by the circular mask.
- Use a simple, recognizable icon. The splash screen is visible for a fraction of a second. Detailed illustrations or text are hard to read at launch speed.
- Test on multiple densities. Use Android Studio's density emulators to verify your icon looks correct at mdpi through xxxhdpi. A common error is placing fine detail that disappears on lower densities.
- Keep animations short. The maximum animation duration is 1000 ms. Aim for 500-800 ms to keep startup feeling fast.
- Adopt the compat library. Even if your
minSdkVersionis below 31, the compat library gives you a single, consistent API surface for splash screen configuration. - Avoid full-screen raster splash images. The modern API uses a centered icon on a solid background. If you need legacy support, prefer a layer-list drawable over a full-screen bitmap to reduce APK size and avoid resolution mismatches.
Generate Your Splash Assets
Manually exporting splash icons at five different densities is tedious and error-prone. Use App Image Kit to generate all required density variants from a single high-resolution source image. The tool runs entirely in your browser — no uploads, no server processing, no installation required.
For related Android asset guides, see:
Ready to export your assets?
App Image Kit generates all density variants from a single source image — free, private, and instant.