1 /* 2 * Copyright 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.core.splashscreen 18 19 import android.annotation.SuppressLint 20 import android.app.Activity 21 import android.os.Build 22 import android.view.View 23 import android.view.ViewGroup 24 import android.widget.FrameLayout 25 import android.window.SplashScreenView 26 import androidx.annotation.RequiresApi 27 28 /** 29 * Contains a copy of the splash screen used to create a custom animation from the splash screen to 30 * the application. 31 * 32 * The splashscreen is accessible using [SplashScreenViewProvider.view] and the view containing the 33 * icon using [SplashScreenViewProvider.iconView]. 34 * 35 * This class also contains time information about the animated icon (for API 31+). 36 * 37 * The application always needs to call [SplashScreenViewProvider.remove] once it's done with it. 38 */ 39 @SuppressLint("ViewConstructor") 40 public class SplashScreenViewProvider internal constructor(ctx: Activity) { 41 42 @RequiresApi(31) 43 internal constructor(platformView: SplashScreenView, ctx: Activity) : this(ctx) { 44 (impl as ViewImpl31).platformView = platformView 45 } 46 47 private val impl: ViewImpl = 48 when { 49 Build.VERSION.SDK_INT >= 31 -> ViewImpl31(ctx) 50 else -> ViewImpl(ctx) <lambda>null51 }.apply { createSplashScreenView() } 52 53 /** 54 * The splash screen view, copied into this application process. 55 * 56 * This view can be used to create custom animation from the splash screen to the application 57 */ 58 public val view: View 59 get() = impl.splashScreenView 60 61 /** 62 * The view containing the splashscreen icon as defined by 63 * [R.attr.windowSplashScreenAnimatedIcon] 64 */ 65 public val iconView: View 66 get() = impl.iconView 67 68 /** 69 * Start time of the icon animation. 70 * 71 * On API 31+, returns the number of millisecond since the Epoch time (1970-1-1T00:00:00Z) 72 * 73 * Below API 31, returns 0 because the icon cannot be animated. 74 */ 75 public val iconAnimationStartMillis: Long 76 get() = impl.iconAnimationStartMillis 77 78 /** Duration of the icon animation as provided in [R.attr. */ 79 public val iconAnimationDurationMillis: Long 80 get() = impl.iconAnimationDurationMillis 81 82 /** 83 * Remove the SplashScreen's view from the view hierarchy. 84 * 85 * This always needs to be called when an 86 * [androidx.core.splashscreen.SplashScreen.OnExitAnimationListener] is set. 87 */ removenull88 public fun remove(): Unit = impl.remove() 89 90 private open class ViewImpl(val activity: Activity) { 91 92 private val _splashScreenView: ViewGroup by lazy { 93 FrameLayout.inflate(activity, R.layout.splash_screen_view, null) as ViewGroup 94 } 95 96 open fun createSplashScreenView() { 97 val content = activity.findViewById<ViewGroup>(android.R.id.content) 98 (content.rootView as? ViewGroup)?.addView(_splashScreenView) 99 } 100 101 open val splashScreenView: ViewGroup 102 get() = _splashScreenView 103 104 open val iconView: View 105 get() = splashScreenView.findViewById(R.id.splashscreen_icon_view) 106 107 open val iconAnimationStartMillis: Long 108 get() = 0 109 110 open val iconAnimationDurationMillis: Long 111 get() = 0 112 113 open fun remove() { 114 (splashScreenView.parent as? ViewGroup)?.removeView(splashScreenView) 115 } 116 } 117 118 @RequiresApi(31) 119 private class ViewImpl31(activity: Activity) : ViewImpl(activity) { 120 lateinit var platformView: SplashScreenView 121 createSplashScreenViewnull122 override fun createSplashScreenView() { 123 // Do nothing 124 } 125 126 override val splashScreenView 127 get() = platformView 128 129 override val iconView: View 130 get() = if (platformView.iconView != null) platformView.iconView!! else View(activity) 131 132 override val iconAnimationStartMillis: Long 133 get() = platformView.iconAnimationStart?.toEpochMilli() ?: 0 134 135 override val iconAnimationDurationMillis: Long 136 get() = platformView.iconAnimationDuration?.toMillis() ?: 0 137 removenull138 override fun remove() { 139 platformView.remove() 140 if (Build.VERSION.SDK_INT < 33) { 141 ThemeUtils.Api31.applyThemesSystemBarAppearance( 142 activity.theme, 143 activity.window.decorView 144 ) 145 } 146 } 147 } 148 } 149