diff options
19 files changed, 376 insertions, 268 deletions
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags index 6ffd66163653..ed01494a911b 100644 --- a/packages/SystemUI/proguard.flags +++ b/packages/SystemUI/proguard.flags @@ -9,8 +9,8 @@ -keep class com.android.systemui.statusbar.phone.CentralSurfaces -keep class com.android.systemui.statusbar.tv.TvStatusBar -keep class com.android.systemui.car.CarSystemUIFactory --keep class com.android.systemui.SystemUIFactory --keep class com.android.systemui.tv.TvSystemUIFactory +-keep class com.android.systemui.SystemUIInitializer +-keep class com.android.systemui.tv.TvSystemUIInitializer -keep class * extends com.android.systemui.CoreStartable -keep class * implements com.android.systemui.CoreStartable$Injector diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml index 94f6c3952e06..375bd394bb4c 100644 --- a/packages/SystemUI/res/values-television/config.xml +++ b/packages/SystemUI/res/values-television/config.xml @@ -22,7 +22,7 @@ <resources> <!-- SystemUIFactory component --> <string name="config_systemUIFactoryComponent" translatable="false"> - com.android.systemui.tv.TvSystemUIFactory + com.android.systemui.tv.TvSystemUIInitializer </string> <!-- Svelte specific logic, see RecentsConfiguration.SVELTE_* constants. --> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 771973c36053..82a3b58a5155 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -286,7 +286,7 @@ <bool name="config_enableFullscreenUserSwitcher">false</bool> <!-- SystemUIFactory component --> - <string name="config_systemUIFactoryComponent" translatable="false">com.android.systemui.SystemUIFactory</string> + <string name="config_systemUIFactoryComponent" translatable="false">com.android.systemui.SystemUIInitializerImpl</string> <!-- QS tile shape store width. negative implies fill configuration instead of stroke--> <dimen name="config_qsTileStrokeWidthActive">-1dp</dimen> diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java index 714d267bb07d..527ce127820e 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java @@ -16,160 +16,22 @@ package com.android.systemui; -import android.app.Activity; -import android.app.Application; -import android.app.Service; -import android.content.BroadcastReceiver; -import android.content.ContentProvider; import android.content.Context; -import android.content.Intent; -import android.util.Log; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.app.AppComponentFactory; - -import com.android.systemui.dagger.ContextComponentHelper; -import com.android.systemui.dagger.SysUIComponent; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -import javax.inject.Inject; /** - * Implementation of AppComponentFactory that injects into constructors. + * Starts up SystemUI using the AOSP {@link SystemUIInitializerImpl}. * - * This class sets up dependency injection when creating our application. + * This initializer relies on reflection to start everything up and should be considered deprecated. + * Instead, create your own {@link SystemUIAppComponentFactoryBase}, specify it in your + * AndroidManifest.xml and construct your own {@link SystemUIInitializer} directly. * - * Services support dependency injection into their constructors. - * - * ContentProviders support injection into member variables - _not_ constructors. + * @deprecated Define your own SystemUIAppComponentFactoryBase implementation and use that. This + * implementation may be changed or removed in future releases. */ -public class SystemUIAppComponentFactory extends AppComponentFactory { - - private static final String TAG = "AppComponentFactory"; - @Inject - public ContextComponentHelper mComponentHelper; - - public SystemUIAppComponentFactory() { - super(); - } - - @NonNull +@Deprecated +public class SystemUIAppComponentFactory extends SystemUIAppComponentFactoryBase { @Override - public Application instantiateApplicationCompat( - @NonNull ClassLoader cl, @NonNull String className) - throws InstantiationException, IllegalAccessException, ClassNotFoundException { - Application app = super.instantiateApplicationCompat(cl, className); - if (app instanceof ContextInitializer) { - ((ContextInitializer) app).setContextAvailableCallback( - context -> { - SystemUIFactory.createFromConfig(context); - SystemUIFactory.getInstance().getSysUIComponent().inject( - SystemUIAppComponentFactory.this); - } - ); - } - - return app; - } - - @NonNull - @Override - public ContentProvider instantiateProviderCompat( - @NonNull ClassLoader cl, @NonNull String className) - throws InstantiationException, IllegalAccessException, ClassNotFoundException { - - ContentProvider contentProvider = super.instantiateProviderCompat(cl, className); - if (contentProvider instanceof ContextInitializer) { - ((ContextInitializer) contentProvider).setContextAvailableCallback( - context -> { - SystemUIFactory.createFromConfig(context); - SysUIComponent rootComponent = - SystemUIFactory.getInstance().getSysUIComponent(); - try { - Method injectMethod = rootComponent.getClass() - .getMethod("inject", contentProvider.getClass()); - injectMethod.invoke(rootComponent, contentProvider); - } catch (NoSuchMethodException - | IllegalAccessException - | InvocationTargetException e) { - Log.w(TAG, "No injector for class: " + contentProvider.getClass(), e); - } - } - ); - } - - return contentProvider; - } - - @NonNull - @Override - public Activity instantiateActivityCompat(@NonNull ClassLoader cl, @NonNull String className, - @Nullable Intent intent) - throws InstantiationException, IllegalAccessException, ClassNotFoundException { - if (mComponentHelper == null) { - // This shouldn't happen, but is seen on occasion. - // Bug filed against framework to take a look: http://b/141008541 - SystemUIFactory.getInstance().getSysUIComponent().inject( - SystemUIAppComponentFactory.this); - } - Activity activity = mComponentHelper.resolveActivity(className); - if (activity != null) { - return activity; - } - return super.instantiateActivityCompat(cl, className, intent); - } - - @NonNull - @Override - public Service instantiateServiceCompat( - @NonNull ClassLoader cl, @NonNull String className, Intent intent) - throws InstantiationException, IllegalAccessException, ClassNotFoundException { - if (mComponentHelper == null) { - // This shouldn't happen, but does when a device is freshly formatted. - // Bug filed against framework to take a look: http://b/141008541 - SystemUIFactory.getInstance().getSysUIComponent().inject( - SystemUIAppComponentFactory.this); - } - Service service = mComponentHelper.resolveService(className); - if (service != null) { - return service; - } - return super.instantiateServiceCompat(cl, className, intent); - } - - @NonNull - @Override - public BroadcastReceiver instantiateReceiverCompat(@NonNull ClassLoader cl, - @NonNull String className, @Nullable Intent intent) - throws InstantiationException, IllegalAccessException, ClassNotFoundException { - if (mComponentHelper == null) { - // This shouldn't happen, but does when a device is freshly formatted. - // Bug filed against framework to take a look: http://b/141008541 - SystemUIFactory.getInstance().getSysUIComponent().inject( - SystemUIAppComponentFactory.this); - } - BroadcastReceiver receiver = mComponentHelper.resolveBroadcastReceiver(className); - if (receiver != null) { - return receiver; - } - - return super.instantiateReceiverCompat(cl, className, intent); - } - - /** - * A callback that receives a Context when one is ready. - */ - public interface ContextAvailableCallback { - void onContextAvailable(Context context); - } - - /** - * Implemented in classes that get started by the system before a context is available. - */ - public interface ContextInitializer { - void setContextAvailableCallback(ContextAvailableCallback callback); + protected SystemUIInitializer createSystemUIInitializer(Context context) { + return SystemUIInitializerFactory.createWithContext(context); } } diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactoryBase.kt b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactoryBase.kt new file mode 100644 index 000000000000..12108b01ab28 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactoryBase.kt @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui + +import android.app.Activity +import android.app.Application +import android.app.Service +import android.content.BroadcastReceiver +import android.content.ContentProvider +import android.content.Context +import android.content.Intent +import android.util.Log +import androidx.core.app.AppComponentFactory +import com.android.systemui.dagger.ContextComponentHelper +import java.lang.reflect.InvocationTargetException +import java.util.concurrent.ExecutionException +import javax.inject.Inject + +/** + * Implementation of AppComponentFactory that injects into constructors. + * + * This class sets up dependency injection when creating our application. + * + * Activities, Services, and BroadcastReceivers support dependency injection into + * their constructors. + * + * ContentProviders support injection into member variables - _not_ constructors. + */ +abstract class SystemUIAppComponentFactoryBase : AppComponentFactory() { + companion object { + private const val TAG = "AppComponentFactory" + // Must be static due to http://b/141008541. + var systemUIInitializer: SystemUIInitializer? = null + } + + @set:Inject + lateinit var componentHelper: ContextComponentHelper + + /** + * Returns a new [SystemUIInitializer]. + * + * The returned implementation should be specific to your build. + */ + protected abstract fun createSystemUIInitializer(context: Context): SystemUIInitializer + + private fun createSystemUIInitializerInternal(context: Context): SystemUIInitializer { + return systemUIInitializer ?: run { + val initializer = createSystemUIInitializer(context.applicationContext) + try { + initializer.init(false) + } catch (exception: ExecutionException) { + throw RuntimeException("Failed to initialize SysUI", exception) + } catch (exception: InterruptedException) { + throw RuntimeException("Failed to initialize SysUI", exception) + } + initializer.sysUIComponent.inject( + this@SystemUIAppComponentFactoryBase + ) + + systemUIInitializer = initializer + return initializer + } + } + + override fun instantiateApplicationCompat(cl: ClassLoader, className: String): Application { + val app = super.instantiateApplicationCompat(cl, className) + if (app !is ContextInitializer) { + throw RuntimeException("App must implement ContextInitializer") + } else { + app.setContextAvailableCallback { context -> + createSystemUIInitializerInternal(context) + } + } + + return app + } + + override fun instantiateProviderCompat(cl: ClassLoader, className: String): ContentProvider { + val contentProvider = super.instantiateProviderCompat(cl, className) + if (contentProvider is ContextInitializer) { + contentProvider.setContextAvailableCallback { context -> + val initializer = createSystemUIInitializerInternal(context) + val rootComponent = initializer.sysUIComponent + try { + val injectMethod = rootComponent.javaClass + .getMethod("inject", contentProvider.javaClass) + injectMethod.invoke(rootComponent, contentProvider) + } catch (e: NoSuchMethodException) { + Log.w(TAG, "No injector for class: " + contentProvider.javaClass, e) + } catch (e: IllegalAccessException) { + Log.w(TAG, "No injector for class: " + contentProvider.javaClass, e) + } catch (e: InvocationTargetException) { + Log.w(TAG, "No injector for class: " + contentProvider.javaClass, e) + } + initializer + } + } + return contentProvider + } + + override fun instantiateActivityCompat( + cl: ClassLoader, + className: String, + intent: Intent? + ): Activity { + if (!this::componentHelper.isInitialized) { + // This shouldn't happen, but is seen on occasion. + // Bug filed against framework to take a look: http://b/141008541 + systemUIInitializer?.sysUIComponent?.inject(this@SystemUIAppComponentFactoryBase) + } + return componentHelper.resolveActivity(className) + ?: super.instantiateActivityCompat(cl, className, intent) + } + + override fun instantiateServiceCompat( + cl: ClassLoader, + className: String, + intent: Intent? + ): Service { + if (!this::componentHelper.isInitialized) { + // This shouldn't happen, but does when a device is freshly formatted. + // Bug filed against framework to take a look: http://b/141008541 + systemUIInitializer?.sysUIComponent?.inject(this@SystemUIAppComponentFactoryBase) + } + return componentHelper.resolveService(className) + ?: super.instantiateServiceCompat(cl, className, intent) + } + + override fun instantiateReceiverCompat( + cl: ClassLoader, + className: String, + intent: Intent? + ): BroadcastReceiver { + if (!this::componentHelper.isInitialized) { + // This shouldn't happen, but does when a device is freshly formatted. + // Bug filed against framework to take a look: http://b/141008541 + systemUIInitializer?.sysUIComponent?.inject(this@SystemUIAppComponentFactoryBase) + } + return componentHelper.resolveBroadcastReceiver(className) + ?: super.instantiateReceiverCompat(cl, className, intent) + } + + /** + * An Interface for classes that can be notified when an Application Context becomes available. + * + * An instance of this will be passed to implementers of [ContextInitializer]. + */ + fun interface ContextAvailableCallback { + /** Notifies when the Application Context is available. */ + fun onContextAvailable(context: Context): SystemUIInitializer + } + + /** + * Interface for classes that can be constructed by the system before a context is available. + * + * This is intended for [Application] and [ContentProvider] implementations that + * either may not have a Context until some point after construction or are themselves + * a [Context]. + * + * Implementers will be passed a [ContextAvailableCallback] that they should call as soon + * as an Application Context is ready. + */ + interface ContextInitializer { + /** + * Called to supply the [ContextAvailableCallback] that should be called when an + * Application [Context] is available. + */ + fun setContextAvailableCallback(callback: ContextAvailableCallback) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java index 6d3fd503dff6..9138b2346ab8 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java @@ -42,7 +42,6 @@ import android.view.SurfaceControl; import android.view.ThreadedRenderer; import com.android.internal.protolog.common.ProtoLog; -import com.android.systemui.dagger.ContextComponentHelper; import com.android.systemui.dagger.GlobalRootComponent; import com.android.systemui.dagger.SysUIComponent; import com.android.systemui.dump.DumpManager; @@ -65,7 +64,6 @@ public class SystemUIApplication extends Application implements public static final String TAG = "SystemUIService"; private static final boolean DEBUG = false; - private ContextComponentHelper mComponentHelper; private BootCompleteCacheImpl mBootCompleteCache; private DumpManager mDumpManager; @@ -80,8 +78,8 @@ public class SystemUIApplication extends Application implements private CoreStartable[] mServices; private boolean mServicesStarted; private SystemUIAppComponentFactory.ContextAvailableCallback mContextAvailableCallback; - private GlobalRootComponent mRootComponent; private SysUIComponent mSysUIComponent; + private SystemUIInitializer mInitializer; public SystemUIApplication() { super(); @@ -90,6 +88,10 @@ public class SystemUIApplication extends Application implements ProtoLog.REQUIRE_PROTOLOGTOOL = false; } + protected GlobalRootComponent getRootComponent() { + return mInitializer.getRootComponent(); + } + @Override public void onCreate() { super.onCreate(); @@ -99,10 +101,8 @@ public class SystemUIApplication extends Application implements TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming", Trace.TRACE_TAG_APP); log.traceBegin("DependencyInjection"); - mContextAvailableCallback.onContextAvailable(this); - mRootComponent = SystemUIFactory.getInstance().getRootComponent(); - mSysUIComponent = SystemUIFactory.getInstance().getSysUIComponent(); - mComponentHelper = mSysUIComponent.getContextComponentHelper(); + mInitializer = mContextAvailableCallback.onContextAvailable(this); + mSysUIComponent = mInitializer.getSysUIComponent(); mBootCompleteCache = mSysUIComponent.provideBootCacheImpl(); log.traceEnd(); @@ -189,15 +189,14 @@ public class SystemUIApplication extends Application implements */ public void startServicesIfNeeded() { - final String vendorComponent = SystemUIFactory.getInstance() - .getVendorComponent(getResources()); + final String vendorComponent = mInitializer.getVendorComponent(getResources()); // Sort the startables so that we get a deterministic ordering. // TODO: make #start idempotent and require users of CoreStartable to call it. Map<Class<?>, Provider<CoreStartable>> sortedStartables = new TreeMap<>( Comparator.comparing(Class::getName)); - sortedStartables.putAll(SystemUIFactory.getInstance().getStartableComponents()); - sortedStartables.putAll(SystemUIFactory.getInstance().getStartableComponentsPerUser()); + sortedStartables.putAll(mSysUIComponent.getStartables()); + sortedStartables.putAll(mSysUIComponent.getPerUserStartables()); startServicesIfNeeded( sortedStartables, "StartServices", vendorComponent); } @@ -212,7 +211,7 @@ public class SystemUIApplication extends Application implements // Sort the startables so that we get a deterministic ordering. Map<Class<?>, Provider<CoreStartable>> sortedStartables = new TreeMap<>( Comparator.comparing(Class::getName)); - sortedStartables.putAll(SystemUIFactory.getInstance().getStartableComponentsPerUser()); + sortedStartables.putAll(mSysUIComponent.getPerUserStartables()); startServicesIfNeeded( sortedStartables, "StartSecondaryServices", null); } diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java index ca94b8cd05b7..5100c09912c8 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -11,7 +11,7 @@ * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and - * limitations under the License + * limitations under the License. */ package com.android.systemui; @@ -22,8 +22,6 @@ import android.os.Handler; import android.os.HandlerThread; import android.util.Log; -import com.android.internal.annotations.VisibleForTesting; -import com.android.systemui.dagger.DaggerGlobalRootComponent; import com.android.systemui.dagger.GlobalRootComponent; import com.android.systemui.dagger.SysUIComponent; import com.android.systemui.dagger.WMComponent; @@ -31,66 +29,47 @@ import com.android.systemui.util.InitializationChecker; import com.android.wm.shell.dagger.WMShellConcurrencyModule; import com.android.wm.shell.transition.ShellTransitions; -import java.util.Map; import java.util.Optional; import java.util.concurrent.ExecutionException; -import javax.inject.Provider; - /** - * Class factory to provide customizable SystemUI components. + * Initializer that stands up SystemUI. + * + * Implementations should override {@link #getGlobalRootComponentBuilder()} to fill in their own + * Dagger root component. */ -public class SystemUIFactory { +public abstract class SystemUIInitializer { private static final String TAG = "SystemUIFactory"; - static SystemUIFactory mFactory; + private final Context mContext; + private GlobalRootComponent mRootComponent; private WMComponent mWMComponent; private SysUIComponent mSysUIComponent; private InitializationChecker mInitializationChecker; - public static <T extends SystemUIFactory> T getInstance() { - return (T) mFactory; + public SystemUIInitializer(Context context) { + mContext = context; } - public static void createFromConfig(Context context) { - createFromConfig(context, false); - } - - @VisibleForTesting - public static void createFromConfig(Context context, boolean fromTest) { - if (mFactory != null) { - return; - } - - final String clsName = context.getString(R.string.config_systemUIFactoryComponent); - if (clsName == null || clsName.length() == 0) { - throw new RuntimeException("No SystemUIFactory component configured"); - } - - try { - Class<?> cls = null; - cls = context.getClassLoader().loadClass(clsName); - mFactory = (SystemUIFactory) cls.newInstance(); - mFactory.init(context, fromTest); - } catch (Throwable t) { - Log.w(TAG, "Error creating SystemUIFactory component: " + clsName, t); - throw new RuntimeException(t); - } - } + protected abstract GlobalRootComponent.Builder getGlobalRootComponentBuilder(); - @VisibleForTesting - static void cleanup() { - mFactory = null; + /** + * Prepares the SysUIComponent builder before it is built. + * @param sysUIBuilder the builder provided by the root component's getSysUIComponent() method + * @param wm the built WMComponent from the root component's getWMComponent() method + */ + protected SysUIComponent.Builder prepareSysUIComponentBuilder( + SysUIComponent.Builder sysUIBuilder, WMComponent wm) { + return sysUIBuilder; } - public SystemUIFactory() {} - - @VisibleForTesting - public void init(Context context, boolean fromTest) - throws ExecutionException, InterruptedException { + /** + * Starts the initialization process. This stands up the Dagger graph. + */ + public void init(boolean fromTest) throws ExecutionException, InterruptedException { mRootComponent = getGlobalRootComponentBuilder() - .context(context) + .context(mContext) .instrumentationTest(fromTest) .build(); @@ -98,7 +77,7 @@ public class SystemUIFactory { boolean initializeComponents = mInitializationChecker.initializeComponents(); // Stand up WMComponent - setupWmComponent(context); + setupWmComponent(mContext); if (initializeComponents) { // Only initialize when not starting from tests since this currently initializes some // components that shouldn't be run in the test environment @@ -188,20 +167,6 @@ public class SystemUIFactory { } } - /** - * Prepares the SysUIComponent builder before it is built. - * @param sysUIBuilder the builder provided by the root component's getSysUIComponent() method - * @param wm the built WMComponent from the root component's getWMComponent() method - */ - protected SysUIComponent.Builder prepareSysUIComponentBuilder( - SysUIComponent.Builder sysUIBuilder, WMComponent wm) { - return sysUIBuilder; - } - - protected GlobalRootComponent.Builder getGlobalRootComponentBuilder() { - return DaggerGlobalRootComponent.builder(); - } - public GlobalRootComponent getRootComponent() { return mRootComponent; } @@ -215,23 +180,9 @@ public class SystemUIFactory { } /** - * Returns the list of {@link CoreStartable} components that should be started at startup. - */ - public Map<Class<?>, Provider<CoreStartable>> getStartableComponents() { - return mSysUIComponent.getStartables(); - } - - /** * Returns the list of additional system UI components that should be started. */ public String getVendorComponent(Resources resources) { return resources.getString(R.string.config_systemUIVendorServiceComponent); } - - /** - * Returns the list of {@link CoreStartable} components that should be started per user. - */ - public Map<Class<?>, Provider<CoreStartable>> getStartableComponentsPerUser() { - return mSysUIComponent.getPerUserStartables(); - } } diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIInitializerFactory.kt b/packages/SystemUI/src/com/android/systemui/SystemUIInitializerFactory.kt new file mode 100644 index 000000000000..b9454e8c3be8 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/SystemUIInitializerFactory.kt @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui + +import android.annotation.SuppressLint +import android.content.Context +import android.util.Log +import com.android.internal.annotations.VisibleForTesting +import com.android.systemui.util.Assert + +/** + * Factory to reflectively lookup a [SystemUIInitializer] to start SystemUI with. + */ +@Deprecated("Provide your own {@link SystemUIAppComponentFactoryBase} that doesn't need this.") +object SystemUIInitializerFactory { + private const val TAG = "SysUIInitializerFactory" + @SuppressLint("StaticFieldLeak") + private var initializer: SystemUIInitializer? = null + + /** + * Instantiate a [SystemUIInitializer] reflectively. + */ + @JvmStatic + fun createWithContext(context: Context): SystemUIInitializer { + return createFromConfig(context) + } + + /** + * Instantiate a [SystemUIInitializer] reflectively. + */ + @JvmStatic + private fun createFromConfig(context: Context): SystemUIInitializer { + Assert.isMainThread() + + return createFromConfigNoAssert(context) + } + + @JvmStatic + @VisibleForTesting + fun createFromConfigNoAssert(context: Context): SystemUIInitializer { + + return initializer ?: run { + val className = context.getString(R.string.config_systemUIFactoryComponent) + if (className.isEmpty()) { + throw RuntimeException("No SystemUIFactory component configured") + } + try { + val cls = context.classLoader.loadClass(className) + val constructor = cls.getConstructor(Context::class.java) + (constructor.newInstance(context) as SystemUIInitializer).apply { + initializer = this + } + } catch (t: Throwable) { + Log.w(TAG, "Error creating SystemUIInitializer component: $className", t) + throw t + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIInitializerImpl.kt b/packages/SystemUI/src/com/android/systemui/SystemUIInitializerImpl.kt new file mode 100644 index 000000000000..8920c928da09 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/SystemUIInitializerImpl.kt @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui + +import android.content.Context +import com.android.systemui.dagger.DaggerGlobalRootComponent +import com.android.systemui.dagger.GlobalRootComponent + +/** + * {@link SystemUIInitializer} that stands up AOSP SystemUI. + */ +class SystemUIInitializerImpl(context: Context) : SystemUIInitializer(context) { + override fun getGlobalRootComponentBuilder(): GlobalRootComponent.Builder { + return DaggerGlobalRootComponent.builder() + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java index 3a1b12955647..550af7cafc75 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java @@ -21,7 +21,7 @@ import com.android.systemui.BootCompleteCacheImpl; import com.android.systemui.CoreStartable; import com.android.systemui.Dependency; import com.android.systemui.InitController; -import com.android.systemui.SystemUIAppComponentFactory; +import com.android.systemui.SystemUIAppComponentFactoryBase; import com.android.systemui.dagger.qualifiers.PerUser; import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.KeyguardSliceProvider; @@ -241,7 +241,7 @@ public interface SysUIComponent { /** * Member injection into the supplied argument. */ - void inject(SystemUIAppComponentFactory factory); + void inject(SystemUIAppComponentFactoryBase factory); /** * Member injection into the supplied argument. diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index 137e28888728..8cc952df47ed 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -26,7 +26,6 @@ import com.android.keyguard.clock.ClockModule; import com.android.keyguard.dagger.KeyguardBouncerComponent; import com.android.systemui.BootCompleteCache; import com.android.systemui.BootCompleteCacheImpl; -import com.android.systemui.SystemUIFactory; import com.android.systemui.appops.dagger.AppOpsModule; import com.android.systemui.assist.AssistModule; import com.android.systemui.biometrics.AlternateUdfpsTouchProvider; @@ -198,11 +197,6 @@ public abstract class SystemUIModule { @Binds abstract SystemClock bindSystemClock(SystemClockImpl systemClock); - @Provides - static SystemUIFactory getSystemUIFactory() { - return SystemUIFactory.getInstance(); - } - // TODO: This should provided by the WM component /** Provides Optional of BubbleManager */ @SysUISingleton diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java index 1570a7ebc0c4..f2f1798c94f6 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java @@ -21,7 +21,7 @@ import android.os.HandlerThread; import androidx.annotation.Nullable; -import com.android.systemui.SystemUIFactory; +import com.android.systemui.SystemUIInitializerFactory; import com.android.systemui.tv.TvWMComponent; import com.android.wm.shell.ShellCommandHandler; import com.android.wm.shell.ShellInit; @@ -52,7 +52,7 @@ import dagger.Subcomponent; /** * Dagger Subcomponent for WindowManager. This class explicitly describes the interfaces exported * from the WM component into the SysUI component (in - * {@link SystemUIFactory#init(Context, boolean)}), and references the specific dependencies + * {@link SystemUIInitializerFactory#init(Context, boolean)}), and references the specific dependencies * provided by its particular device/form-factor SystemUI implementation. * * ie. {@link WMComponent} includes {@link WMShellModule} diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleProvider.java b/packages/SystemUI/src/com/android/systemui/people/PeopleProvider.java index b55d86e8fb1c..0ba077eb0912 100644 --- a/packages/SystemUI/src/com/android/systemui/people/PeopleProvider.java +++ b/packages/SystemUI/src/com/android/systemui/people/PeopleProvider.java @@ -29,7 +29,8 @@ import android.os.UserHandle; import android.util.Log; import android.widget.RemoteViews; -import com.android.systemui.SystemUIAppComponentFactory; +import com.android.systemui.SystemUIAppComponentFactoryBase.ContextAvailableCallback; +import com.android.systemui.SystemUIAppComponentFactoryBase.ContextInitializer; import com.android.systemui.people.widget.PeopleSpaceWidgetManager; import com.android.systemui.shared.system.PeopleProviderUtils; @@ -37,11 +38,11 @@ import javax.inject.Inject; /** API that returns a People Tile preview. */ public class PeopleProvider extends ContentProvider implements - SystemUIAppComponentFactory.ContextInitializer { + ContextInitializer { private static final String TAG = "PeopleProvider"; private static final boolean DEBUG = PeopleSpaceUtils.DEBUG; private static final String EMPTY_STRING = ""; - private SystemUIAppComponentFactory.ContextAvailableCallback mCallback; + private ContextAvailableCallback mCallback; @Inject PeopleSpaceWidgetManager mPeopleSpaceWidgetManager; @@ -144,7 +145,7 @@ public class PeopleProvider extends ContentProvider implements @Override public void setContextAvailableCallback( - SystemUIAppComponentFactory.ContextAvailableCallback callback) { + ContextAvailableCallback callback) { mCallback = callback; } } diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIInitializer.java index 0b5594b14d0e..fabbb2c1f44d 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIFactory.java +++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIInitializer.java @@ -16,14 +16,20 @@ package com.android.systemui.tv; -import com.android.systemui.SystemUIFactory; +import android.content.Context; + +import com.android.systemui.SystemUIInitializer; import com.android.systemui.dagger.GlobalRootComponent; /** - * TV variant {@link SystemUIFactory}, that substitutes default {@link GlobalRootComponent} for + * TV variant {@link SystemUIInitializer}, that substitutes default {@link GlobalRootComponent} for * {@link TvGlobalRootComponent} */ -public class TvSystemUIFactory extends SystemUIFactory { +public class TvSystemUIInitializer extends SystemUIInitializer { + public TvSystemUIInitializer(Context context) { + super(context); + } + @Override protected GlobalRootComponent.Builder getGlobalRootComponentBuilder() { return DaggerTvGlobalRootComponent.builder(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java index 5d8e4351cfd9..a0fdc8f1555e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java @@ -26,6 +26,8 @@ import com.android.systemui.statusbar.policy.FlashlightController; import org.junit.Assert; import org.junit.Test; +import java.util.concurrent.ExecutionException; + @SmallTest public class DependencyTest extends SysuiTestCase { @@ -44,10 +46,12 @@ public class DependencyTest extends SysuiTestCase { } @Test - public void testInitDependency() { + public void testInitDependency() throws ExecutionException, InterruptedException { Dependency.clearDependencies(); - Dependency dependency = - SystemUIFactory.getInstance().getSysUIComponent().createDependency(); + SystemUIInitializer initializer = + SystemUIInitializerFactory.createFromConfigNoAssert(mContext); + initializer.init(true); + Dependency dependency = initializer.getSysUIComponent().createDependency(); dependency.start(); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiBaseFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiBaseFragmentTest.java index 8c20b248d02c..9179efc9f39f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/SysuiBaseFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiBaseFragmentTest.java @@ -34,6 +34,8 @@ import org.junit.Before; import org.junit.Rule; import org.mockito.Mockito; +import java.util.concurrent.ExecutionException; + public abstract class SysuiBaseFragmentTest extends BaseFragmentTest { public static final Class<?>[] ALL_SUPPORTED_CLASSES = LeakCheckedTest.ALL_SUPPORTED_CLASSES; @@ -54,10 +56,11 @@ public abstract class SysuiBaseFragmentTest extends BaseFragmentTest { } @Before - public void SysuiSetup() { - SystemUIFactory.createFromConfig(mContext, true); - mDependency = new TestableDependency( - SystemUIFactory.getInstance().getSysUIComponent().createDependency()); + public void sysuiSetup() throws ExecutionException, InterruptedException { + SystemUIInitializer initializer = + SystemUIInitializerFactory.createFromConfigNoAssert(mContext); + initializer.init(true); + mDependency = new TestableDependency(initializer.getSysUIComponent().createDependency()); Dependency.setInstance(mDependency); // TODO: Figure out another way to give reference to a SysuiTestableContext. @@ -77,7 +80,6 @@ public abstract class SysuiBaseFragmentTest extends BaseFragmentTest { public void SysuiTeardown() { InstrumentationRegistry.registerInstance(mRealInstrumentation, InstrumentationRegistry.getArguments()); - SystemUIFactory.cleanup(); } @AfterClass diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java index 8c7927782d2d..c52ea60f0bfc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java +++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java @@ -76,9 +76,10 @@ public abstract class SysuiTestCase { @Before public void SysuiSetup() throws Exception { - SystemUIFactory.createFromConfig(mContext, true); - mDependency = new TestableDependency( - SystemUIFactory.getInstance().getSysUIComponent().createDependency()); + SystemUIInitializer initializer = + SystemUIInitializerFactory.createFromConfigNoAssert(mContext); + initializer.init(true); + mDependency = new TestableDependency(initializer.getSysUIComponent().createDependency()); Dependency.setInstance(mDependency); mFakeBroadcastDispatcher = new FakeBroadcastDispatcher(mContext, mock(Looper.class), mock(Executor.class), mock(DumpManager.class), diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java index 51c258055465..23516c94d851 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java @@ -45,6 +45,7 @@ import androidx.slice.core.SliceQuery; import androidx.test.filters.SmallTest; import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.systemui.SystemUIInitializerImpl; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationMediaManager; @@ -100,7 +101,7 @@ public class KeyguardSliceProviderTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); mIsZenMode = false; mProvider = new TestableKeyguardSliceProvider(); - mProvider.setContextAvailableCallback(context -> { }); + mProvider.setContextAvailableCallback(context -> new SystemUIInitializerImpl(mContext)); mProvider.attachInfo(getContext(), null); reset(mContentResolver); SliceProvider.setSpecs(new HashSet<>(Arrays.asList(SliceSpecs.LIST))); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java index 3d03c4750869..6f9e60fc5d69 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java @@ -44,6 +44,7 @@ import com.android.systemui.SysuiBaseFragmentTest; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.log.LogBuffer; import com.android.systemui.log.LogcatEchoTracker; +import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.DisableFlagsLogger; @@ -112,6 +113,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { @Before public void setup() { injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES); + mDependency.injectMockDependency(DarkIconDispatcher.class); } @Test |