diff options
9 files changed, 252 insertions, 296 deletions
diff --git a/packages/SystemUI/docs/dagger.md b/packages/SystemUI/docs/dagger.md index 9b4c21efb27f..4a6240b56081 100644 --- a/packages/SystemUI/docs/dagger.md +++ b/packages/SystemUI/docs/dagger.md @@ -108,20 +108,13 @@ You can then include your module in one of three places:  ### Using injection with Fragments -Fragments are created as part of the FragmentManager, so they need to be -setup so the manager knows how to create them. To do that, add a method -to com.android.systemui.fragments.FragmentService$FragmentCreator that -returns your fragment class. That is all that is required, once the method -exists, FragmentService will automatically pick it up and use injection -whenever your fragment needs to be created. +Fragments are created as part of the FragmentManager, so injectable Fragments need to be registered +so the manager knows how to create them. This is done via +[FragmentService#addFragmentInstantiationProvider](../src/com/android/systemui/fragments/FragmentService.java). +Pass it the class of your fragment and a `Provider` for your fragment at some time before your +Fragment is accessed. -```java -public interface FragmentCreator { -    NavigationBarFragment createNavigationBar(); -} -``` - -If you need to create your fragment (i.e. for the add or replace transaction), +When you need to create your fragment (i.e. for the add or replace transaction),  then the FragmentHostManager can do this for you.  ```java diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags index 10bb00cad1a0..a8ed84393cfb 100644 --- a/packages/SystemUI/proguard.flags +++ b/packages/SystemUI/proguard.flags @@ -1,156 +1,13 @@ -# Preserve line number information for debugging stack traces. --keepattributes SourceFile,LineNumberTable +-include proguard_common.flags -# Preserve relationship information that can impact simple class naming. --keepattributes EnclosingMethod,InnerClasses - --keep class com.android.systemui.recents.OverviewProxyRecentsImpl --keep class com.android.systemui.statusbar.car.CarStatusBar --keep class com.android.systemui.statusbar.phone.CentralSurfaces  -keep class com.android.systemui.statusbar.tv.TvStatusBar --keep class ** extends com.android.systemui.SystemUIInitializer { +-keep class com.android.systemui.SystemUIInitializerImpl {      *;  } --keep class * extends com.android.systemui.CoreStartable --keep class * implements com.android.systemui.CoreStartable$Injector - -# Needed for builds to properly initialize KeyFrames from xml scene --keepclassmembers class * extends androidx.constraintlayout.motion.widget.Key { -  public <init>(); -} -# Needed to ensure callback field references are kept in their respective -# owning classes when the downstream callback registrars only store weak refs. -# TODO(b/264686688): Handle these cases with more targeted annotations. --keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** { -  private com.android.keyguard.KeyguardUpdateMonitorCallback *; -  private com.android.systemui.privacy.PrivacyConfig$Callback *; -  private com.android.systemui.privacy.PrivacyItemController$Callback *; -  private com.android.systemui.settings.UserTracker$Callback *; -  private com.android.systemui.statusbar.phone.StatusBarWindowCallback *; -  private com.android.systemui.util.service.Observer$Callback *; -  private com.android.systemui.util.service.ObservableServiceConnection$Callback *; -} -# Note that these rules are temporary companions to the above rules, required -# for cases like Kotlin where fields with anonymous types use the anonymous type -# rather than the supertype. --if class * extends com.android.keyguard.KeyguardUpdateMonitorCallback --keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** { -  <1> *; -} --if class * extends com.android.systemui.privacy.PrivacyConfig$Callback --keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** { -  <1> *; -} --if class * extends com.android.systemui.privacy.PrivacyItemController$Callback --keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** { -  <1> *; -} --if class * extends com.android.systemui.settings.UserTracker$Callback --keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** { -  <1> *; -} --if class * extends com.android.systemui.statusbar.phone.StatusBarWindowCallback --keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** { -  <1> *; -} --if class * extends com.android.systemui.util.service.Observer$Callback --keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** { -  <1> *; -} --if class * extends com.android.systemui.util.service.ObservableServiceConnection$Callback --keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** { -  <1> *; -} - --keepclasseswithmembers class * { -    public <init>(android.content.Context, android.util.AttributeSet); -} - --keep class ** extends androidx.preference.PreferenceFragment --keep class com.android.systemui.tuner.* - -# The plugins subpackage acts as a shared library that might be referenced in -# dynamically-loaded plugin APKs. --keep class com.android.systemui.plugins.** { -    *; -} --keep class com.android.systemui.fragments.FragmentService$FragmentCreator { +-keep class com.android.systemui.tv.TvSystemUIInitializer {      *;  } --keep class androidx.core.app.CoreComponentFactory --keep public class * extends com.android.systemui.CoreStartable { -    public <init>(android.content.Context); -} - -# Keep the wm shell lib --keep class com.android.wm.shell.* -# Keep the protolog group methods that are called by the generated code --keepclassmembers class com.android.wm.shell.protolog.ShellProtoLogGroup { -    *; -} - --keep,allowoptimization,allowaccessmodification class com.android.systemui.dagger.GlobalRootComponent { !synthetic *; } --keep,allowoptimization,allowaccessmodification class com.android.systemui.dagger.GlobalRootComponent$SysUIComponentImpl { !synthetic *; } --keep,allowoptimization,allowaccessmodification class com.android.systemui.dagger.Dagger** { !synthetic *; } --keep,allowoptimization,allowaccessmodification class com.android.systemui.tv.Dagger** { !synthetic *; } - -# Prevent optimization or access modification of any referenced code that may -# conflict with code in the bootclasspath. -# TODO(b/222468116): Resolve such collisions in the build system. --keepnames class android.**.nano.** { *; } --keepnames class com.android.**.nano.** { *; } --keepnames class com.android.internal.protolog.** { *; } --keepnames class android.hardware.common.** { *; } - -# Allows proguard to make private and protected methods and fields public as -# part of optimization. This lets proguard inline trivial getter/setter methods. --allowaccessmodification - -# Removes runtime checks added through Kotlin to JVM code genereration to -# avoid linear growth as more Kotlin code is converted / added to the codebase. -# These checks are generally applied to Java platform types (values returned -# from Java code that don't have nullness annotations), but we remove them to -# avoid code size increases. -# -# See also https://kotlinlang.org/docs/reference/java-interop.html -# -# TODO(b/199941987): Consider standardizing these rules in a central place as -# Kotlin gains adoption with other platform targets. --assumenosideeffects class kotlin.jvm.internal.Intrinsics { -    # Remove check for method parameters being null -    static void checkParameterIsNotNull(java.lang.Object, java.lang.String); - -    # When a Java platform type is returned and passed to Kotlin NonNull method, -    # remove the null check -    static void checkExpressionValueIsNotNull(java.lang.Object, java.lang.String); -    static void checkNotNullExpressionValue(java.lang.Object, java.lang.String); - -    # Remove check that final value returned from method is null, if passing -    # back Java platform type. -    static void checkReturnedValueIsNotNull(java.lang.Object, java.lang.String, java.lang.String); -    static void checkReturnedValueIsNotNull(java.lang.Object, java.lang.String); - -    # Null check for accessing a field from a parent class written in Java. -    static void checkFieldIsNotNull(java.lang.Object, java.lang.String, java.lang.String); -    static void checkFieldIsNotNull(java.lang.Object, java.lang.String); - -    # Removes code generated from !! operator which converts Nullable type to -    # NonNull type. These would throw an NPE immediate after on access. -    static void checkNotNull(java.lang.Object, java.lang.String); -    static void checkNotNullParameter(java.lang.Object, java.lang.String); - -    # Removes lateinit var check being used before being set. Check is applied -    # on every field access without this. -    static void throwUninitializedPropertyAccessException(java.lang.String); -} -# Strip verbose logs. --assumenosideeffects class android.util.Log { -  static *** v(...); -  static *** isLoggable(...); -} --assumenosideeffects class android.util.Slog { -  static *** v(...); -} --maximumremovedandroidloglevel 2 +-keep,allowoptimization,allowaccessmodification class com.android.systemui.dagger.DaggerReferenceGlobalRootComponent** { !synthetic *; } +-keep,allowoptimization,allowaccessmodification class com.android.systemui.tv.DaggerTvGlobalRootComponent** { !synthetic *; }
\ No newline at end of file diff --git a/packages/SystemUI/proguard_common.flags b/packages/SystemUI/proguard_common.flags new file mode 100644 index 000000000000..1d008cf57ea7 --- /dev/null +++ b/packages/SystemUI/proguard_common.flags @@ -0,0 +1,141 @@ +# Preserve line number information for debugging stack traces. +-keepattributes SourceFile,LineNumberTable + +-keep class com.android.systemui.VendorServices + +# the `#inject` methods are accessed via reflection to work on ContentProviders +-keepclassmembers class * extends com.android.systemui.dagger.SysUIComponent { void inject(***); } + +# Needed for builds to properly initialize KeyFrames from xml scene +-keepclassmembers class * extends androidx.constraintlayout.motion.widget.Key { +  public <init>(); +} + +# Needed to ensure callback field references are kept in their respective +# owning classes when the downstream callback registrars only store weak refs. +# TODO(b/264686688): Handle these cases with more targeted annotations. +-keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** { +  private com.android.keyguard.KeyguardUpdateMonitorCallback *; +  private com.android.systemui.privacy.PrivacyConfig$Callback *; +  private com.android.systemui.privacy.PrivacyItemController$Callback *; +  private com.android.systemui.settings.UserTracker$Callback *; +  private com.android.systemui.statusbar.phone.StatusBarWindowCallback *; +  private com.android.systemui.util.service.Observer$Callback *; +  private com.android.systemui.util.service.ObservableServiceConnection$Callback *; +} +# Note that these rules are temporary companions to the above rules, required +# for cases like Kotlin where fields with anonymous types use the anonymous type +# rather than the supertype. +-if class * extends com.android.keyguard.KeyguardUpdateMonitorCallback +-keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** { +  <1> *; +} +-if class * extends com.android.systemui.privacy.PrivacyConfig$Callback +-keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** { +  <1> *; +} +-if class * extends com.android.systemui.privacy.PrivacyItemController$Callback +-keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** { +  <1> *; +} +-if class * extends com.android.systemui.settings.UserTracker$Callback +-keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** { +  <1> *; +} +-if class * extends com.android.systemui.statusbar.phone.StatusBarWindowCallback +-keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** { +  <1> *; +} +-if class * extends com.android.systemui.util.service.Observer$Callback +-keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** { +  <1> *; +} +-if class * extends com.android.systemui.util.service.ObservableServiceConnection$Callback +-keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** { +  <1> *; +} + +-keepclasseswithmembers class * { +    public <init>(android.content.Context, android.util.AttributeSet); +} + +-keep class ** extends androidx.preference.PreferenceFragment +-keep class com.android.systemui.tuner.* + +# The plugins subpackage acts as a shared library that might be referenced in +# dynamically-loaded plugin APKs. +-keep class com.android.systemui.plugins.** { +    *; +} +-keep class com.android.systemui.fragments.FragmentService$FragmentCreator { +    *; +} +-keep class androidx.core.app.CoreComponentFactory + +# Keep the wm shell lib +-keep class com.android.wm.shell.* +# Keep the protolog group methods that are called by the generated code +-keepclassmembers class com.android.wm.shell.protolog.ShellProtoLogGroup { +    *; +} + +# Prevent optimization or access modification of any referenced code that may +# conflict with code in the bootclasspath. +# TODO(b/222468116): Resolve such collisions in the build system. +-keepnames class android.**.nano.** { *; } +-keepnames class com.android.**.nano.** { *; } +-keepnames class com.android.internal.protolog.** { *; } +-keepnames class android.hardware.common.** { *; } + +# Allows proguard to make private and protected methods and fields public as +# part of optimization. This lets proguard inline trivial getter/setter methods. +-allowaccessmodification + +# Removes runtime checks added through Kotlin to JVM code genereration to +# avoid linear growth as more Kotlin code is converted / added to the codebase. +# These checks are generally applied to Java platform types (values returned +# from Java code that don't have nullness annotations), but we remove them to +# avoid code size increases. +# +# See also https://kotlinlang.org/docs/reference/java-interop.html +# +# TODO(b/199941987): Consider standardizing these rules in a central place as +# Kotlin gains adoption with other platform targets. +-assumenosideeffects class kotlin.jvm.internal.Intrinsics { +    # Remove check for method parameters being null +    static void checkParameterIsNotNull(java.lang.Object, java.lang.String); + +    # When a Java platform type is returned and passed to Kotlin NonNull method, +    # remove the null check +    static void checkExpressionValueIsNotNull(java.lang.Object, java.lang.String); +    static void checkNotNullExpressionValue(java.lang.Object, java.lang.String); + +    # Remove check that final value returned from method is null, if passing +    # back Java platform type. +    static void checkReturnedValueIsNotNull(java.lang.Object, java.lang.String, java.lang.String); +    static void checkReturnedValueIsNotNull(java.lang.Object, java.lang.String); + +    # Null check for accessing a field from a parent class written in Java. +    static void checkFieldIsNotNull(java.lang.Object, java.lang.String, java.lang.String); +    static void checkFieldIsNotNull(java.lang.Object, java.lang.String); + +    # Removes code generated from !! operator which converts Nullable type to +    # NonNull type. These would throw an NPE immediate after on access. +    static void checkNotNull(java.lang.Object, java.lang.String); +    static void checkNotNullParameter(java.lang.Object, java.lang.String); + +    # Removes lateinit var check being used before being set. Check is applied +    # on every field access without this. +    static void throwUninitializedPropertyAccessException(java.lang.String); +} + + +# Strip verbose logs. +-assumenosideeffects class android.util.Log { +  static *** v(...); +  static *** isLoggable(...); +} +-assumenosideeffects class android.util.Slog { +  static *** v(...); +} +-maximumremovedandroidloglevel 2 diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index 63a4fd2189d8..3b38870d6e1f 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -47,7 +47,6 @@ import com.android.systemui.dreams.dagger.DreamModule;  import com.android.systemui.dump.DumpManager;  import com.android.systemui.flags.FeatureFlags;  import com.android.systemui.flags.FlagsModule; -import com.android.systemui.fragments.FragmentService;  import com.android.systemui.keyboard.KeyboardModule;  import com.android.systemui.keyguard.data.BouncerViewModule;  import com.android.systemui.log.dagger.LogModule; @@ -63,6 +62,7 @@ import com.android.systemui.privacy.PrivacyModule;  import com.android.systemui.qrcodescanner.dagger.QRCodeScannerModule;  import com.android.systemui.qs.FgsManagerController;  import com.android.systemui.qs.FgsManagerControllerImpl; +import com.android.systemui.qs.QSFragmentStartableModule;  import com.android.systemui.qs.footer.dagger.FooterActionsModule;  import com.android.systemui.recents.Recents;  import com.android.systemui.screenrecord.ScreenRecordModule; @@ -116,16 +116,16 @@ import com.android.systemui.wallet.dagger.WalletModule;  import com.android.systemui.wmshell.BubblesManager;  import com.android.wm.shell.bubbles.Bubbles; -import java.util.Optional; -import java.util.concurrent.Executor; - -import javax.inject.Named; -  import dagger.Binds;  import dagger.BindsOptionalOf;  import dagger.Module;  import dagger.Provides; +import java.util.Optional; +import java.util.concurrent.Executor; + +import javax.inject.Named; +  /**   * A dagger module for injecting components of System UI that are required by System UI.   * @@ -165,6 +165,7 @@ import dagger.Provides;              PolicyModule.class,              PrivacyModule.class,              QRCodeScannerModule.class, +            QSFragmentStartableModule.class,              ScreenshotModule.class,              SensorModule.class,              SecurityRepositoryModule.class, @@ -194,8 +195,7 @@ import dagger.Provides;              DozeComponent.class,              ExpandableNotificationRowComponent.class,              KeyguardBouncerComponent.class, -            NotificationShelfComponent.class, -            FragmentService.FragmentCreator.class +            NotificationShelfComponent.class          })  public abstract class SystemUIModule { diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java index 6a27ee7c0c89..81a520661cfe 100644 --- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java +++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java @@ -39,15 +39,16 @@ import com.android.settingslib.applications.InterestingConfigChanges;  import com.android.systemui.plugins.Plugin;  import com.android.systemui.util.leak.LeakDetector; +import dagger.assisted.Assisted; +import dagger.assisted.AssistedFactory; +import dagger.assisted.AssistedInject; +  import java.io.FileDescriptor;  import java.io.PrintWriter; -import java.lang.reflect.InvocationTargetException;  import java.util.ArrayList;  import java.util.HashMap; -import dagger.assisted.Assisted; -import dagger.assisted.AssistedFactory; -import dagger.assisted.AssistedInject; +import javax.inject.Provider;  public class FragmentHostManager { @@ -322,25 +323,17 @@ public class FragmentHostManager {              return instantiateWithInjections(context, className, arguments);          } -        private Fragment instantiateWithInjections( -                Context context, String className, Bundle args) { -            FragmentService.FragmentInstantiationInfo fragmentInstantiationInfo = +        private Fragment instantiateWithInjections(Context context, String className, Bundle args) { +            Provider<? extends Fragment> fragmentProvider =                      mManager.getInjectionMap().get(className); -            if (fragmentInstantiationInfo != null) { -                try { -                    Fragment f = (Fragment) fragmentInstantiationInfo -                            .mMethod -                            .invoke(fragmentInstantiationInfo.mDaggerComponent); -                    // Setup the args, taken from Fragment#instantiate. -                    if (args != null) { -                        args.setClassLoader(f.getClass().getClassLoader()); -                        f.setArguments(args); -                    } -                    return f; -                } catch (IllegalAccessException | InvocationTargetException e) { -                    throw new Fragment.InstantiationException("Unable to instantiate " + className, -                            e); +            if (fragmentProvider != null) { +                Fragment f = fragmentProvider.get(); +                // Setup the args, taken from Fragment#instantiate. +                if (args != null) { +                    args.setClassLoader(f.getClass().getClassLoader()); +                    f.setArguments(args);                  } +                return f;              }              return Fragment.instantiate(context, className, args);          } diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java index d302b13a68b6..a75c056c5c71 100644 --- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java +++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java @@ -24,16 +24,12 @@ import android.view.View;  import com.android.systemui.Dumpable;  import com.android.systemui.dagger.SysUISingleton;  import com.android.systemui.dump.DumpManager; -import com.android.systemui.qs.QSFragment;  import com.android.systemui.statusbar.policy.ConfigurationController;  import java.io.PrintWriter; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier;  import javax.inject.Inject; - -import dagger.Subcomponent; +import javax.inject.Provider;  /**   * Holds a map of root views to FragmentHostStates and generates them as needed. @@ -49,9 +45,9 @@ public class FragmentService implements Dumpable {       * A map with the means to create fragments via Dagger injection.       *       * key: the fragment class name. -     * value: see {@link FragmentInstantiationInfo}. +     * value: A {@link Provider} for the Fragment       */ -    private final ArrayMap<String, FragmentInstantiationInfo> mInjectionMap = new ArrayMap<>(); +    private final ArrayMap<String, Provider<? extends Fragment>> mInjectionMap = new ArrayMap<>();      private final Handler mHandler = new Handler();      private final FragmentHostManager.Factory mFragmentHostManagerFactory; @@ -67,38 +63,31 @@ public class FragmentService implements Dumpable {      @Inject      public FragmentService( -            FragmentCreator.Factory fragmentCreatorFactory,              FragmentHostManager.Factory fragmentHostManagerFactory,              ConfigurationController configurationController,              DumpManager dumpManager) {          mFragmentHostManagerFactory = fragmentHostManagerFactory; -        addFragmentInstantiationProvider(fragmentCreatorFactory.build());          configurationController.addCallback(mConfigurationListener); -        dumpManager.registerDumpable(getClass().getSimpleName(), this); +        dumpManager.registerNormalDumpable(this);      } -    ArrayMap<String, FragmentInstantiationInfo> getInjectionMap() { +    ArrayMap<String, Provider<? extends Fragment>> getInjectionMap() {          return mInjectionMap;      }      /**       * Adds a new Dagger component object that provides method(s) to create fragments via injection.       */ -    public void addFragmentInstantiationProvider(Object daggerComponent) { -        for (Method method : daggerComponent.getClass().getDeclaredMethods()) { -            if (Fragment.class.isAssignableFrom(method.getReturnType()) -                    && (method.getModifiers() & Modifier.PUBLIC) != 0) { -                String fragmentName = method.getReturnType().getName(); -                if (mInjectionMap.containsKey(fragmentName)) { -                    Log.w(TAG, "Fragment " + fragmentName + " is already provided by different" -                            + " Dagger component; Not adding method"); -                    continue; -                } -                mInjectionMap.put( -                        fragmentName, new FragmentInstantiationInfo(method, daggerComponent)); -            } +    public void addFragmentInstantiationProvider( +            Class<?> fragmentCls, Provider<? extends Fragment> provider) { +        String fragmentName = fragmentCls.getName(); +        if (mInjectionMap.containsKey(fragmentName)) { +            Log.w(TAG, "Fragment " + fragmentName + " is already provided by different" +                    + " Dagger component; Not adding method"); +            return;          } +        mInjectionMap.put(fragmentName, provider);      }      public FragmentHostManager getFragmentHostManager(View view) { @@ -132,22 +121,6 @@ public class FragmentService implements Dumpable {          }      } -    /** -     * The subcomponent of dagger that holds all fragments that need injection. -     */ -    @Subcomponent -    public interface FragmentCreator { -        /** Factory for creating a FragmentCreator. */ -        @Subcomponent.Factory -        interface Factory { -            FragmentCreator build(); -        } -        /** -         * Inject a QSFragment. -         */ -        QSFragment createQSFragment(); -    } -      private class FragmentHostState {          private final View mView; @@ -170,16 +143,4 @@ public class FragmentService implements Dumpable {              mFragmentHostManager.onConfigurationChanged(newConfig);          }      } - -    /** An object containing the information needed to instantiate a fragment. */ -    static class FragmentInstantiationInfo { -        /** The method that returns a newly-created fragment of the given class. */ -        final Method mMethod; -        /** The Dagger component that the method should be invoked on. */ -        final Object mDaggerComponent; -        FragmentInstantiationInfo(Method method, Object daggerComponent) { -            this.mMethod = method; -            this.mDaggerComponent = daggerComponent; -        } -    }  } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragmentStartable.kt b/packages/SystemUI/src/com/android/systemui/qs/QSFragmentStartable.kt new file mode 100644 index 000000000000..253560b93f1a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragmentStartable.kt @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2023 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.qs + +import com.android.systemui.CoreStartable +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.fragments.FragmentService +import dagger.Binds +import dagger.Module +import dagger.multibindings.ClassKey +import dagger.multibindings.IntoMap +import javax.inject.Inject +import javax.inject.Provider + +@SysUISingleton +class QSFragmentStartable +@Inject +constructor( +    private val fragmentService: FragmentService, +    private val qsFragmentProvider: Provider<QSFragment> +) : CoreStartable { +    override fun start() { +        fragmentService.addFragmentInstantiationProvider(QSFragment::class.java, qsFragmentProvider) +    } +} + +@Module +interface QSFragmentStartableModule { +    @Binds +    @IntoMap +    @ClassKey(QSFragmentStartable::class) +    fun bindsQSFragmentStartable(startable: QSFragmentStartable): CoreStartable +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index 00519b95172e..209c377af5a8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -228,6 +228,7 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll  import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;  import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;  import com.android.systemui.statusbar.phone.dagger.StatusBarPhoneModule; +import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;  import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;  import com.android.systemui.statusbar.policy.BatteryController;  import com.android.systemui.statusbar.policy.BrightnessMirrorController; @@ -1613,7 +1614,9 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {              }          }          mCentralSurfacesComponent = mCentralSurfacesComponentFactory.create(); -        mFragmentService.addFragmentInstantiationProvider(mCentralSurfacesComponent); +        mFragmentService.addFragmentInstantiationProvider( +                CollapsedStatusBarFragment.class, +                mCentralSurfacesComponent::createCollapsedStatusBarFragment);          mNotificationShadeWindowView = mCentralSurfacesComponent.getNotificationShadeWindowView();          mNotificationShadeWindowViewController = mCentralSurfacesComponent diff --git a/packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt index a2dc1eb606ed..4ba1bc6dfbbb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt @@ -5,7 +5,6 @@ import android.os.Looper  import android.test.suitebuilder.annotation.SmallTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.dump.DumpManager -import com.android.systemui.qs.QSFragment  import com.android.systemui.util.mockito.mock  import com.google.common.truth.Truth.assertThat  import org.junit.Before @@ -13,9 +12,7 @@ import org.junit.Test  @SmallTest  class FragmentServiceTest : SysuiTestCase() { -    private val fragmentCreator = TestFragmentCreator() -    private val fragmenetHostManagerFactory: FragmentHostManager.Factory = mock() -    private val fragmentCreatorFactory = FragmentService.FragmentCreator.Factory { fragmentCreator } +    private val fragmentHostManagerFactory: FragmentHostManager.Factory = mock()      private lateinit var fragmentService: FragmentService @@ -25,65 +22,29 @@ class FragmentServiceTest : SysuiTestCase() {              Looper.prepare()          } -        fragmentService = -            FragmentService( -                fragmentCreatorFactory, -                fragmenetHostManagerFactory, -                mock(), -                DumpManager() -            ) -    } - -    @Test -    fun constructor_addsFragmentCreatorMethodsToMap() { -        val map = fragmentService.injectionMap -        assertThat(map).hasSize(2) -        assertThat(map.keys).contains(QSFragment::class.java.name) -        assertThat(map.keys).contains(TestFragmentInCreator::class.java.name) +        fragmentService = FragmentService(fragmentHostManagerFactory, mock(), DumpManager())      }      @Test      fun addFragmentInstantiationProvider_objectHasNoFragmentMethods_nothingAdded() { -        fragmentService.addFragmentInstantiationProvider(Object()) - -        assertThat(fragmentService.injectionMap).hasSize(2) -    } - -    @Test -    fun addFragmentInstantiationProvider_objectHasFragmentMethods_methodsAdded() { -        fragmentService.addFragmentInstantiationProvider( -            @Suppress("unused") -            object : Any() { -                fun createTestFragment2() = TestFragment2() -                fun createTestFragment3() = TestFragment3() -            } -        ) +        fragmentService.addFragmentInstantiationProvider(TestFragment::class.java) { +            TestFragment() +        } -        val map = fragmentService.injectionMap -        assertThat(map).hasSize(4) -        assertThat(map.keys).contains(TestFragment2::class.java.name) -        assertThat(map.keys).contains(TestFragment3::class.java.name) +        assertThat(fragmentService.injectionMap).hasSize(1)      }      @Test      fun addFragmentInstantiationProvider_objectFragmentMethodsAlreadyProvided_nothingAdded() { -        fragmentService.addFragmentInstantiationProvider( -            @Suppress("unused") -            object : Any() { -                fun createTestFragment() = TestFragmentInCreator() -            } -        ) - -        assertThat(fragmentService.injectionMap).hasSize(2) -    } +        fragmentService.addFragmentInstantiationProvider(TestFragment::class.java) { +            TestFragment() +        } +        fragmentService.addFragmentInstantiationProvider(TestFragment::class.java) { +            TestFragment() +        } -    class TestFragmentCreator : FragmentService.FragmentCreator { -        override fun createQSFragment(): QSFragment = mock() -        @Suppress("unused") -        fun createTestFragment(): TestFragmentInCreator = TestFragmentInCreator() +        assertThat(fragmentService.injectionMap).hasSize(1)      } -    class TestFragmentInCreator : Fragment() -    class TestFragment2 : Fragment() -    class TestFragment3 : Fragment() +    class TestFragment : Fragment()  }  |