1 /* <lambda>null2 * Copyright (C) 2019 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 package com.android.systemui 17 18 import android.app.Activity 19 import android.app.Application 20 import android.app.Service 21 import android.content.BroadcastReceiver 22 import android.content.ContentProvider 23 import android.content.Context 24 import android.content.Intent 25 import android.util.Log 26 import androidx.core.app.AppComponentFactory 27 import com.android.systemui.dagger.ContextComponentHelper 28 import java.lang.reflect.InvocationTargetException 29 import java.util.concurrent.ExecutionException 30 import javax.inject.Inject 31 32 /** 33 * Implementation of AppComponentFactory that injects into constructors. 34 * 35 * This class sets up dependency injection when creating our application. 36 * 37 * Activities, Services, and BroadcastReceivers support dependency injection into 38 * their constructors. 39 * 40 * ContentProviders support injection into member variables - _not_ constructors. 41 */ 42 abstract class SystemUIAppComponentFactoryBase : AppComponentFactory() { 43 companion object { 44 private const val TAG = "AppComponentFactory" 45 // Must be static due to http://b/141008541. 46 var systemUIInitializer: SystemUIInitializer? = null 47 } 48 49 @set:Inject 50 lateinit var componentHelper: ContextComponentHelper 51 52 /** 53 * Returns a new [SystemUIInitializer]. 54 * 55 * The returned implementation should be specific to your build. 56 */ 57 protected abstract fun createSystemUIInitializer(context: Context): SystemUIInitializer 58 59 private fun createSystemUIInitializerInternal(context: Context): SystemUIInitializer { 60 return systemUIInitializer ?: run { 61 val initializer = createSystemUIInitializer(context.applicationContext) 62 try { 63 initializer.init(false) 64 } catch (exception: ExecutionException) { 65 throw RuntimeException("Failed to initialize SysUI", exception) 66 } catch (exception: InterruptedException) { 67 throw RuntimeException("Failed to initialize SysUI", exception) 68 } 69 initializer.sysUIComponent.inject( 70 this@SystemUIAppComponentFactoryBase 71 ) 72 73 systemUIInitializer = initializer 74 return initializer 75 } 76 } 77 78 override fun instantiateApplicationCompat(cl: ClassLoader, className: String): Application { 79 val app = super.instantiateApplicationCompat(cl, className) 80 if (app !is ContextInitializer) { 81 throw RuntimeException("App must implement ContextInitializer") 82 } else { 83 app.setContextAvailableCallback { context -> 84 createSystemUIInitializerInternal(context) 85 } 86 } 87 88 return app 89 } 90 91 override fun instantiateProviderCompat(cl: ClassLoader, className: String): ContentProvider { 92 val contentProvider = super.instantiateProviderCompat(cl, className) 93 if (contentProvider is ContextInitializer) { 94 contentProvider.setContextAvailableCallback { context -> 95 val initializer = createSystemUIInitializerInternal(context) 96 val rootComponent = initializer.sysUIComponent 97 try { 98 val injectMethod = rootComponent.javaClass 99 .getMethod("inject", contentProvider.javaClass) 100 injectMethod.invoke(rootComponent, contentProvider) 101 } catch (e: NoSuchMethodException) { 102 Log.w(TAG, "No injector for class: " + contentProvider.javaClass, e) 103 } catch (e: IllegalAccessException) { 104 Log.w(TAG, "No injector for class: " + contentProvider.javaClass, e) 105 } catch (e: InvocationTargetException) { 106 Log.w(TAG, "No injector for class: " + contentProvider.javaClass, e) 107 } 108 initializer 109 } 110 } 111 return contentProvider 112 } 113 114 override fun instantiateActivityCompat( 115 cl: ClassLoader, 116 className: String, 117 intent: Intent? 118 ): Activity { 119 if (!this::componentHelper.isInitialized) { 120 // This shouldn't happen, but is seen on occasion. 121 // Bug filed against framework to take a look: http://b/141008541 122 systemUIInitializer?.sysUIComponent?.inject(this@SystemUIAppComponentFactoryBase) 123 } 124 return componentHelper.resolveActivity(className) 125 ?: super.instantiateActivityCompat(cl, className, intent) 126 } 127 128 override fun instantiateServiceCompat( 129 cl: ClassLoader, 130 className: String, 131 intent: Intent? 132 ): Service { 133 if (!this::componentHelper.isInitialized) { 134 // This shouldn't happen, but does when a device is freshly formatted. 135 // Bug filed against framework to take a look: http://b/141008541 136 systemUIInitializer?.sysUIComponent?.inject(this@SystemUIAppComponentFactoryBase) 137 } 138 return componentHelper.resolveService(className) 139 ?: super.instantiateServiceCompat(cl, className, intent) 140 } 141 142 override fun instantiateReceiverCompat( 143 cl: ClassLoader, 144 className: String, 145 intent: Intent? 146 ): BroadcastReceiver { 147 if (!this::componentHelper.isInitialized) { 148 // This shouldn't happen, but does when a device is freshly formatted. 149 // Bug filed against framework to take a look: http://b/141008541 150 systemUIInitializer?.sysUIComponent?.inject(this@SystemUIAppComponentFactoryBase) 151 } 152 return componentHelper.resolveBroadcastReceiver(className) 153 ?: super.instantiateReceiverCompat(cl, className, intent) 154 } 155 156 /** 157 * An Interface for classes that can be notified when an Application Context becomes available. 158 * 159 * An instance of this will be passed to implementers of [ContextInitializer]. 160 */ 161 fun interface ContextAvailableCallback { 162 /** Notifies when the Application Context is available. */ 163 fun onContextAvailable(context: Context): SystemUIInitializer 164 } 165 166 /** 167 * Interface for classes that can be constructed by the system before a context is available. 168 * 169 * This is intended for [Application] and [ContentProvider] implementations that 170 * either may not have a Context until some point after construction or are themselves 171 * a [Context]. 172 * 173 * Implementers will be passed a [ContextAvailableCallback] that they should call as soon 174 * as an Application Context is ready. 175 */ 176 interface ContextInitializer { 177 /** 178 * Called to supply the [ContextAvailableCallback] that should be called when an 179 * Application [Context] is available. 180 */ 181 fun setContextAvailableCallback(callback: ContextAvailableCallback) 182 } 183 } 184