diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml index db5ff199ab..3ae2b89da4 100644 --- a/quickstep/res/values/config.xml +++ b/quickstep/res/values/config.xml @@ -38,7 +38,6 @@ - com.android.launcher3.uioverrides.SystemApiWrapper diff --git a/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt b/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt index f542b8c0b3..374db6ae6f 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt +++ b/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt @@ -41,15 +41,20 @@ import com.android.launcher3.Flags.privateSpaceAppInstallerButton import com.android.launcher3.Flags.privateSpaceSysAppsSeparation import com.android.launcher3.R import com.android.launcher3.Utilities +import com.android.launcher3.dagger.ApplicationContext +import com.android.launcher3.dagger.LauncherAppSingleton import com.android.launcher3.proxy.ProxyActivityStarter import com.android.launcher3.util.ApiWrapper import com.android.launcher3.util.Executors import com.android.launcher3.util.StartActivityParams import com.android.launcher3.util.UserIconInfo import com.android.quickstep.util.FadeOutRemoteTransition +import javax.inject.Inject /** A wrapper for the hidden API calls */ -open class SystemApiWrapper(context: Context?) : ApiWrapper(context) { +@LauncherAppSingleton +open class SystemApiWrapper @Inject constructor(@ApplicationContext context: Context?) : + ApiWrapper(context) { override fun getPersons(si: ShortcutInfo) = si.persons ?: Utilities.EMPTY_PERSON_ARRAY diff --git a/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java b/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java index ab77a7f62c..3870b9b4c4 100644 --- a/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java +++ b/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java @@ -15,7 +15,9 @@ */ package com.android.quickstep.dagger; +import com.android.launcher3.uioverrides.SystemApiWrapper; import com.android.launcher3.uioverrides.plugins.PluginManagerWrapperImpl; +import com.android.launcher3.util.ApiWrapper; import com.android.launcher3.util.PluginManagerWrapper; import dagger.Binds; @@ -25,4 +27,5 @@ import dagger.Module; public abstract class QuickStepModule { @Binds abstract PluginManagerWrapper bindPluginManagerWrapper(PluginManagerWrapperImpl impl); + @Binds abstract ApiWrapper bindApiWrapper(SystemApiWrapper systemApiWrapper); } diff --git a/res/values/config.xml b/res/values/config.xml index 504218b78e..b0b7aa2d0a 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -79,7 +79,6 @@ - diff --git a/src/com/android/launcher3/LauncherApplication.java b/src/com/android/launcher3/LauncherApplication.java index 4c82e5676f..678901b5b2 100644 --- a/src/com/android/launcher3/LauncherApplication.java +++ b/src/com/android/launcher3/LauncherApplication.java @@ -26,15 +26,25 @@ import com.android.launcher3.dagger.LauncherBaseAppComponent; */ public class LauncherApplication extends Application { - private LauncherBaseAppComponent mAppComponent; + private volatile LauncherBaseAppComponent mAppComponent; @Override public void onCreate() { super.onCreate(); MainProcessInitializer.initialize(this); - initDagger(); } public LauncherAppComponent getAppComponent() { + if (mAppComponent == null) { + synchronized (this) { + // Check for null again, as it may have been assigned on a different thread. This + // avoids holding synchronization locks everytime. + if (mAppComponent == null) { + // Initialize the dagger component on demand as content providers can get + // accessed before the Launcher application (b/36917845#comment4) + initDaggerComponent(DaggerLauncherAppComponent.builder()); + } + } + } // Since supertype setters will return a supertype.builder and @Component.Builder types // must not have any generic types. // We need to cast mAppComponent to {@link LauncherAppComponent} since appContext() @@ -42,7 +52,10 @@ public class LauncherApplication extends Application { return (LauncherAppComponent) mAppComponent; } - protected void initDagger() { - mAppComponent = DaggerLauncherAppComponent.builder().appContext(this).build(); + /** + * Init with the desired dagger component. + */ + public void initDaggerComponent(LauncherAppComponent.Builder componentBuilder) { + mAppComponent = componentBuilder.appContext(this).build(); } } diff --git a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java index 4da7c2716a..e7403b2d7a 100644 --- a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java +++ b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java @@ -19,6 +19,7 @@ package com.android.launcher3.dagger; import android.content.Context; import com.android.launcher3.pm.InstallSessionHelper; +import com.android.launcher3.util.ApiWrapper; import com.android.launcher3.util.DaggerSingletonTracker; import com.android.launcher3.util.PluginManagerWrapper; import com.android.launcher3.util.ScreenOnTracker; @@ -38,6 +39,7 @@ import dagger.BindsInstance; public interface LauncherBaseAppComponent { DaggerSingletonTracker getDaggerSingletonTracker(); InstallSessionHelper getInstallSessionHelper(); + ApiWrapper getApiWrapper(); ScreenOnTracker getScreenOnTracker(); SettingsCache getSettingsCache(); CustomWidgetManager getCustomWidgetManager(); diff --git a/src/com/android/launcher3/util/ApiWrapper.java b/src/com/android/launcher3/util/ApiWrapper.java index 21f91acdae..467a7ec54f 100644 --- a/src/com/android/launcher3/util/ApiWrapper.java +++ b/src/com/android/launcher3/util/ApiWrapper.java @@ -17,7 +17,6 @@ package com.android.launcher3.util; import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_HOME_ROLE; -import static com.android.launcher3.util.MainThreadInitializedObject.forOverride; import android.app.ActivityOptions; import android.app.Person; @@ -38,24 +37,30 @@ import androidx.annotation.Nullable; import com.android.launcher3.BuildConfig; import com.android.launcher3.Launcher; -import com.android.launcher3.R; import com.android.launcher3.Utilities; +import com.android.launcher3.dagger.ApplicationContext; +import com.android.launcher3.dagger.LauncherAppComponent; +import com.android.launcher3.dagger.LauncherAppSingleton; import java.util.Collections; import java.util.List; import java.util.Map; +import javax.inject.Inject; + /** * A wrapper for the hidden API calls */ -public class ApiWrapper implements ResourceBasedOverride, SafeCloseable { +@LauncherAppSingleton +public class ApiWrapper { - public static final MainThreadInitializedObject INSTANCE = - forOverride(ApiWrapper.class, R.string.api_wrapper_class); + public static final DaggerSingletonObject INSTANCE = new DaggerSingletonObject<>( + LauncherAppComponent::getApiWrapper); protected final Context mContext; - public ApiWrapper(Context context) { + @Inject + public ApiWrapper(@ApplicationContext Context context) { mContext = context; } @@ -166,9 +171,6 @@ public class ApiWrapper implements ResourceBasedOverride, SafeCloseable { return appInfo.sourceDir; } - @Override - public void close() { } - private static class NoopDrawable extends ColorDrawable { @Override public int getIntrinsicHeight() { diff --git a/src/com/android/launcher3/util/MainThreadInitializedObject.java b/src/com/android/launcher3/util/MainThreadInitializedObject.java index 9a70298a5b..356a5517e2 100644 --- a/src/com/android/launcher3/util/MainThreadInitializedObject.java +++ b/src/com/android/launcher3/util/MainThreadInitializedObject.java @@ -150,7 +150,6 @@ public class MainThreadInitializedObject { public SandboxContext(Context base) { attachBaseContext(base); - initDagger(); } @Override diff --git a/tests/Android.bp b/tests/Android.bp index 96672778fa..35a227523b 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -148,6 +148,7 @@ android_test { platform_apis: true, test_config: "Launcher3Tests.xml", data: [":Launcher3"], + plugins: ["dagger2-compiler"], test_suites: ["general-tests"], } @@ -237,6 +238,7 @@ android_robolectric_test { "truth", ], instrumentation_for: "Launcher3", + plugins: ["dagger2-compiler"], upstream: true, strict_mode: false, } diff --git a/tests/multivalentTests/src/com/android/launcher3/AutoInstallsLayoutTest.kt b/tests/multivalentTests/src/com/android/launcher3/AutoInstallsLayoutTest.kt index b04bccaa86..f73a9d39f4 100644 --- a/tests/multivalentTests/src/com/android/launcher3/AutoInstallsLayoutTest.kt +++ b/tests/multivalentTests/src/com/android/launcher3/AutoInstallsLayoutTest.kt @@ -41,6 +41,8 @@ import com.android.launcher3.LauncherSettings.Favorites.PROFILE_ID import com.android.launcher3.LauncherSettings.Favorites.SPANX import com.android.launcher3.LauncherSettings.Favorites.SPANY import com.android.launcher3.LauncherSettings.Favorites._ID +import com.android.launcher3.dagger.LauncherAppComponent +import com.android.launcher3.dagger.LauncherAppSingleton import com.android.launcher3.model.data.AppInfo import com.android.launcher3.pm.UserCache import com.android.launcher3.util.ApiWrapper @@ -54,6 +56,8 @@ import com.android.launcher3.util.UserIconInfo.TYPE_MAIN import com.android.launcher3.util.UserIconInfo.TYPE_WORK import com.android.launcher3.widget.LauncherWidgetHolder import com.google.common.truth.Truth.assertThat +import dagger.BindsInstance +import dagger.Component import java.io.StringReader import org.junit.After import org.junit.Before @@ -162,7 +166,9 @@ class AutoInstallsLayoutTest { @Test fun work_item_added_to_home() { val apiWrapperMock = spy(ApiWrapper.INSTANCE[targetContext]) - targetContext.putObject(ApiWrapper.INSTANCE, apiWrapperMock) + targetContext.initDaggerComponent( + DaggerAutoInstallsLayoutTestComponent.builder().bindApiWrapper(apiWrapperMock) + ) doReturn( mapOf( myUserHandle() to UserIconInfo(myUserHandle(), TYPE_MAIN, 0), @@ -198,7 +204,7 @@ class AutoInstallsLayoutTest { callback, SourceResources.wrap(targetContext.resources), { Xml.newPullParser().also { it.setInput(StringReader(build())) } }, - TAG_WORKSPACE + TAG_WORKSPACE, ) class MyCallback : LayoutParserCallback { @@ -214,3 +220,14 @@ class AutoInstallsLayoutTest { } } } + +@LauncherAppSingleton +@Component +interface AutoInstallsLayoutTestComponent : LauncherAppComponent { + @Component.Builder + interface Builder : LauncherAppComponent.Builder { + @BindsInstance fun bindApiWrapper(wrapper: ApiWrapper): Builder + + override fun build(): AutoInstallsLayoutTestComponent + } +} diff --git a/tests/src/com/android/launcher3/popup/SystemShortcutTest.java b/tests/src/com/android/launcher3/popup/SystemShortcutTest.java index f54668cd04..ae54e95209 100644 --- a/tests/src/com/android/launcher3/popup/SystemShortcutTest.java +++ b/tests/src/com/android/launcher3/popup/SystemShortcutTest.java @@ -62,6 +62,8 @@ import androidx.test.platform.app.InstrumentationRegistry; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.R; import com.android.launcher3.allapps.PrivateProfileManager; +import com.android.launcher3.dagger.LauncherAppComponent; +import com.android.launcher3.dagger.LauncherAppSingleton; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.logging.StatsLogManager.StatsLogger; import com.android.launcher3.model.data.AppInfo; @@ -79,6 +81,9 @@ import com.android.launcher3.views.Snackbar; import com.android.launcher3.widget.picker.model.WidgetPickerDataProvider; import com.android.launcher3.widget.picker.model.data.WidgetPickerData; +import dagger.BindsInstance; +import dagger.Component; + import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -115,8 +120,10 @@ public class SystemShortcutTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); + mSandboxContext.initDaggerComponent( + DaggerSystemShortcutTest_TestComponent.builder().bindApiWrapper( + ApiWrapper.INSTANCE.get(mSandboxContext))); mSandboxContext.putObject(UserCache.INSTANCE, mUserCache); - mSandboxContext.putObject(ApiWrapper.INSTANCE, mApiWrapper); mTestContext = new TestSandboxModelContextWrapper(mSandboxContext) { @Override public StatsLogManager getStatsLogManager() { @@ -405,4 +412,16 @@ public class SystemShortcutTest { systemShortcut.onClick(mView); verify(mSandboxContext).startActivity(any()); } + + @LauncherAppSingleton + @Component + interface TestComponent extends LauncherAppComponent { + @Component.Builder + interface Builder extends LauncherAppComponent.Builder { + @BindsInstance Builder bindApiWrapper(ApiWrapper wrapper); + + @Override + TestComponent build(); + } + } }