Revert "Change SysemUIFactory to SystemUIInitializer."

Revert submission 18917521-b235624311-app-component

Reason for revert: Broken test b/238359875 and b/238372209
Reverted Changes:
I7029fb296:Change SysemUIFactory to SystemUIInitializer.
I082787983:Conform to new SystemUIInitializer pattern.
I923e5bbbc:Conform to new SystemUIInitializer pattern.
I7af1a39b2:Conform to new SystemUIInitializer pattern.
Iba9a5ba24:Conform to new SystemUIInitializer pattern.
I4fe83e292:Conform to new SystemUIInitializer pattern.
I7f54204ae:Conform to new SystemUIInitializer pattern.
I6246c6eb4:Conform to new SystemUIInitializer pattern.

Bug: 238359875
Bug: 238372209
Change-Id: I833ec524c4f6072d64eba55e22f0b37341d38f4f
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index ed01494..6ffd661 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.SystemUIInitializer
--keep class com.android.systemui.tv.TvSystemUIInitializer
+-keep class com.android.systemui.SystemUIFactory
+-keep class com.android.systemui.tv.TvSystemUIFactory
 -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 375bd39..94f6c39 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.TvSystemUIInitializer
+        com.android.systemui.tv.TvSystemUIFactory
     </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 82a3b58..771973c 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.SystemUIInitializerImpl</string>
+    <string name="config_systemUIFactoryComponent" translatable="false">com.android.systemui.SystemUIFactory</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 527ce12..714d267bb 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java
@@ -16,22 +16,160 @@
 
 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;
 
 /**
- * Starts up SystemUI using the AOSP {@link SystemUIInitializerImpl}.
+ * Implementation of AppComponentFactory that injects into constructors.
  *
- * 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.
+ * This class sets up dependency injection when creating our application.
  *
- * @deprecated Define your own SystemUIAppComponentFactoryBase implementation and use that. This
- *             implementation may be changed or removed in future releases.
+ * Services support dependency injection into their constructors.
+ *
+ * ContentProviders support injection into member variables - _not_ constructors.
  */
-@Deprecated
-public class SystemUIAppComponentFactory extends SystemUIAppComponentFactoryBase {
+public class SystemUIAppComponentFactory extends AppComponentFactory {
+
+    private static final String TAG = "AppComponentFactory";
+    @Inject
+    public ContextComponentHelper mComponentHelper;
+
+    public SystemUIAppComponentFactory() {
+        super();
+    }
+
+    @NonNull
     @Override
-    protected SystemUIInitializer createSystemUIInitializer(Context context) {
-        return SystemUIInitializerFactory.createWithContext(context);
+    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);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactoryBase.kt b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactoryBase.kt
deleted file mode 100644
index 12108b0..0000000
--- a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactoryBase.kt
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * 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 9138b23..6d3fd50 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -42,6 +42,7 @@
 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;
@@ -64,6 +65,7 @@
     public static final String TAG = "SystemUIService";
     private static final boolean DEBUG = false;
 
+    private ContextComponentHelper mComponentHelper;
     private BootCompleteCacheImpl mBootCompleteCache;
     private DumpManager mDumpManager;
 
@@ -78,8 +80,8 @@
     private CoreStartable[] mServices;
     private boolean mServicesStarted;
     private SystemUIAppComponentFactory.ContextAvailableCallback mContextAvailableCallback;
+    private GlobalRootComponent mRootComponent;
     private SysUIComponent mSysUIComponent;
-    private SystemUIInitializer mInitializer;
 
     public SystemUIApplication() {
         super();
@@ -88,10 +90,6 @@
         ProtoLog.REQUIRE_PROTOLOGTOOL = false;
     }
 
-    protected GlobalRootComponent getRootComponent() {
-        return mInitializer.getRootComponent();
-    }
-
     @Override
     public void onCreate() {
         super.onCreate();
@@ -101,8 +99,10 @@
         TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
                 Trace.TRACE_TAG_APP);
         log.traceBegin("DependencyInjection");
-        mInitializer = mContextAvailableCallback.onContextAvailable(this);
-        mSysUIComponent = mInitializer.getSysUIComponent();
+        mContextAvailableCallback.onContextAvailable(this);
+        mRootComponent = SystemUIFactory.getInstance().getRootComponent();
+        mSysUIComponent = SystemUIFactory.getInstance().getSysUIComponent();
+        mComponentHelper = mSysUIComponent.getContextComponentHelper();
         mBootCompleteCache = mSysUIComponent.provideBootCacheImpl();
         log.traceEnd();
 
@@ -189,14 +189,15 @@
      */
 
     public void startServicesIfNeeded() {
-        final String vendorComponent = mInitializer.getVendorComponent(getResources());
+        final String vendorComponent = SystemUIFactory.getInstance()
+                .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(mSysUIComponent.getStartables());
-        sortedStartables.putAll(mSysUIComponent.getPerUserStartables());
+        sortedStartables.putAll(SystemUIFactory.getInstance().getStartableComponents());
+        sortedStartables.putAll(SystemUIFactory.getInstance().getStartableComponentsPerUser());
         startServicesIfNeeded(
                 sortedStartables, "StartServices", vendorComponent);
     }
@@ -211,7 +212,7 @@
         // Sort the startables so that we get a deterministic ordering.
         Map<Class<?>, Provider<CoreStartable>> sortedStartables = new TreeMap<>(
                 Comparator.comparing(Class::getName));
-        sortedStartables.putAll(mSysUIComponent.getPerUserStartables());
+        sortedStartables.putAll(SystemUIFactory.getInstance().getStartableComponentsPerUser());
         startServicesIfNeeded(
                 sortedStartables, "StartSecondaryServices", null);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
similarity index 76%
rename from packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java
rename to packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 5100c09..ca94b8c 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2016 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,6 +22,8 @@
 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;
@@ -29,47 +31,66 @@
 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;
+
 /**
- * Initializer that stands up SystemUI.
- *
- * Implementations should override {@link #getGlobalRootComponentBuilder()} to fill in their own
- * Dagger root component.
+ * Class factory to provide customizable SystemUI components.
  */
-public abstract class SystemUIInitializer {
+public class SystemUIFactory {
     private static final String TAG = "SystemUIFactory";
 
-    private final Context mContext;
-
+    static SystemUIFactory mFactory;
     private GlobalRootComponent mRootComponent;
     private WMComponent mWMComponent;
     private SysUIComponent mSysUIComponent;
     private InitializationChecker mInitializationChecker;
 
-    public SystemUIInitializer(Context context) {
-        mContext = context;
+    public static <T extends SystemUIFactory> T getInstance() {
+        return (T) mFactory;
     }
 
-    protected abstract GlobalRootComponent.Builder getGlobalRootComponentBuilder();
-
-    /**
-     * 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 static void createFromConfig(Context context) {
+        createFromConfig(context, false);
     }
 
-    /**
-     * Starts the initialization process. This stands up the Dagger graph.
-     */
-    public void init(boolean fromTest) throws ExecutionException, InterruptedException {
+    @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);
+        }
+    }
+
+    @VisibleForTesting
+    static void cleanup() {
+        mFactory = null;
+    }
+
+    public SystemUIFactory() {}
+
+    @VisibleForTesting
+    public void init(Context context, boolean fromTest)
+            throws ExecutionException, InterruptedException {
         mRootComponent = getGlobalRootComponentBuilder()
-                .context(mContext)
+                .context(context)
                 .instrumentationTest(fromTest)
                 .build();
 
@@ -77,7 +98,7 @@
         boolean initializeComponents = mInitializationChecker.initializeComponents();
 
         // Stand up WMComponent
-        setupWmComponent(mContext);
+        setupWmComponent(context);
         if (initializeComponents) {
             // Only initialize when not starting from tests since this currently initializes some
             // components that shouldn't be run in the test environment
@@ -167,6 +188,20 @@
         }
     }
 
+    /**
+     * 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;
     }
@@ -180,9 +215,23 @@
     }
 
     /**
+     * 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
deleted file mode 100644
index b9454e8..0000000
--- a/packages/SystemUI/src/com/android/systemui/SystemUIInitializerFactory.kt
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 8920c92..0000000
--- a/packages/SystemUI/src/com/android/systemui/SystemUIInitializerImpl.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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 550af7c..3a1b129 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.CoreStartable;
 import com.android.systemui.Dependency;
 import com.android.systemui.InitController;
-import com.android.systemui.SystemUIAppComponentFactoryBase;
+import com.android.systemui.SystemUIAppComponentFactory;
 import com.android.systemui.dagger.qualifiers.PerUser;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.keyguard.KeyguardSliceProvider;
@@ -241,7 +241,7 @@
     /**
      * Member injection into the supplied argument.
      */
-    void inject(SystemUIAppComponentFactoryBase factory);
+    void inject(SystemUIAppComponentFactory 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 8cc952d..137e288 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -26,6 +26,7 @@
 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;
@@ -197,6 +198,11 @@
     @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 f2f1798..1570a7e 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 androidx.annotation.Nullable;
 
-import com.android.systemui.SystemUIInitializerFactory;
+import com.android.systemui.SystemUIFactory;
 import com.android.systemui.tv.TvWMComponent;
 import com.android.wm.shell.ShellCommandHandler;
 import com.android.wm.shell.ShellInit;
@@ -52,7 +52,7 @@
 /**
  * Dagger Subcomponent for WindowManager.  This class explicitly describes the interfaces exported
  * from the WM component into the SysUI component (in
- * {@link SystemUIInitializerFactory#init(Context, boolean)}), and references the specific dependencies
+ * {@link SystemUIFactory#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 0ba077e..b55d86e 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleProvider.java
@@ -29,8 +29,7 @@
 import android.util.Log;
 import android.widget.RemoteViews;
 
-import com.android.systemui.SystemUIAppComponentFactoryBase.ContextAvailableCallback;
-import com.android.systemui.SystemUIAppComponentFactoryBase.ContextInitializer;
+import com.android.systemui.SystemUIAppComponentFactory;
 import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
 import com.android.systemui.shared.system.PeopleProviderUtils;
 
@@ -38,11 +37,11 @@
 
 /** API that returns a People Tile preview. */
 public class PeopleProvider extends ContentProvider implements
-        ContextInitializer {
+        SystemUIAppComponentFactory.ContextInitializer {
     private static final String TAG = "PeopleProvider";
     private static final boolean DEBUG = PeopleSpaceUtils.DEBUG;
     private static final String EMPTY_STRING = "";
-    private ContextAvailableCallback mCallback;
+    private SystemUIAppComponentFactory.ContextAvailableCallback mCallback;
 
     @Inject
     PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;
@@ -145,7 +144,7 @@
 
     @Override
     public void setContextAvailableCallback(
-            ContextAvailableCallback callback) {
+            SystemUIAppComponentFactory.ContextAvailableCallback callback) {
         mCallback = callback;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIInitializer.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIFactory.java
similarity index 73%
rename from packages/SystemUI/src/com/android/systemui/tv/TvSystemUIInitializer.java
rename to packages/SystemUI/src/com/android/systemui/tv/TvSystemUIFactory.java
index fabbb2c..0b5594b 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIInitializer.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIFactory.java
@@ -16,20 +16,14 @@
 
 package com.android.systemui.tv;
 
-import android.content.Context;
-
-import com.android.systemui.SystemUIInitializer;
+import com.android.systemui.SystemUIFactory;
 import com.android.systemui.dagger.GlobalRootComponent;
 
 /**
- * TV variant {@link SystemUIInitializer}, that substitutes default {@link GlobalRootComponent} for
+ * TV variant {@link SystemUIFactory}, that substitutes default {@link GlobalRootComponent} for
  * {@link TvGlobalRootComponent}
  */
-public class TvSystemUIInitializer extends SystemUIInitializer {
-    public TvSystemUIInitializer(Context context) {
-        super(context);
-    }
-
+public class TvSystemUIFactory extends SystemUIFactory {
     @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 a0fdc8f..5d8e435 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
@@ -26,8 +26,6 @@
 import org.junit.Assert;
 import org.junit.Test;
 
-import java.util.concurrent.ExecutionException;
-
 @SmallTest
 public class DependencyTest extends SysuiTestCase {
 
@@ -46,12 +44,10 @@
     }
 
     @Test
-    public void testInitDependency() throws ExecutionException, InterruptedException {
+    public void testInitDependency() {
         Dependency.clearDependencies();
-        SystemUIInitializer initializer =
-                SystemUIInitializerFactory.createFromConfigNoAssert(mContext);
-        initializer.init(true);
-        Dependency dependency = initializer.getSysUIComponent().createDependency();
+        Dependency dependency =
+                SystemUIFactory.getInstance().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 9179efc..8c20b24 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiBaseFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiBaseFragmentTest.java
@@ -34,8 +34,6 @@
 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;
@@ -56,11 +54,10 @@
     }
 
     @Before
-    public void sysuiSetup() throws ExecutionException, InterruptedException {
-        SystemUIInitializer initializer =
-                SystemUIInitializerFactory.createFromConfigNoAssert(mContext);
-        initializer.init(true);
-        mDependency = new TestableDependency(initializer.getSysUIComponent().createDependency());
+    public void SysuiSetup() {
+        SystemUIFactory.createFromConfig(mContext, true);
+        mDependency = new TestableDependency(
+                SystemUIFactory.getInstance().getSysUIComponent().createDependency());
         Dependency.setInstance(mDependency);
 
         // TODO: Figure out another way to give reference to a SysuiTestableContext.
@@ -80,6 +77,7 @@
     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 c52ea60f..8c79277 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -76,10 +76,9 @@
 
     @Before
     public void SysuiSetup() throws Exception {
-        SystemUIInitializer initializer =
-                SystemUIInitializerFactory.createFromConfigNoAssert(mContext);
-        initializer.init(true);
-        mDependency = new TestableDependency(initializer.getSysUIComponent().createDependency());
+        SystemUIFactory.createFromConfig(mContext, true);
+        mDependency = new TestableDependency(
+                SystemUIFactory.getInstance().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 23516c9..51c2580 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
@@ -45,7 +45,6 @@
 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;
@@ -101,7 +100,7 @@
         MockitoAnnotations.initMocks(this);
         mIsZenMode = false;
         mProvider = new TestableKeyguardSliceProvider();
-        mProvider.setContextAvailableCallback(context -> new SystemUIInitializerImpl(mContext));
+        mProvider.setContextAvailableCallback(context -> { });
         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 6f9e60f..3d03c47 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,7 +44,6 @@
 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;
@@ -113,7 +112,6 @@
     @Before
     public void setup() {
         injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
-        mDependency.injectMockDependency(DarkIconDispatcher.class);
     }
 
     @Test