Wire the compose based widget picker in widget picker activity

- Uses new picker behind a flag.
- Includes appropriate implementation of picker module based on whether compose is enabled.

Bug: 408283627
Flag: EXEMPT independent module
Test: Upcoming in follow up cls
Change-Id: I13e69379bc89c6d2e6909f9d11937997affc6a58
This commit is contained in:
Shamali Patwa
2025-05-29 13:26:00 -07:00
parent 8e1ac2de44
commit e61df48651
10 changed files with 289 additions and 6 deletions

View File

@@ -47,8 +47,8 @@ filegroup {
filegroup {
name: "launcher-compose-enabled-src",
srcs: [
"compose/facade/enabled/*.kt",
"compose/facade/core/*.kt",
"compose/facade/enabled/**/*.kt",
"compose/facade/core/**/*.kt",
"compose/features/**/*.kt",
],
}
@@ -56,8 +56,8 @@ filegroup {
filegroup {
name: "launcher-compose-disabled-src",
srcs: [
"compose/facade/core/*.kt",
"compose/facade/disabled/*.kt",
"compose/facade/core/**/*.kt",
"compose/facade/disabled/**/*.kt",
],
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2025 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.launcher3.compose.core.widgetpicker
import dagger.Binds
import dagger.Module
/**
* A module that provides a no-op [WidgetPickerComposeWrapper] for dagger graph that doesn't
* involve widget picker e.g. launcher preview OR when compose is disabled via build flag.
*/
@Module
interface NoOpWidgetPickerModule {
@Binds
fun bindWidgetPickerWrapper(noOp: NoOpWidgetPickerComposeWrapper): WidgetPickerComposeWrapper
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (C) 2025 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.launcher3.compose.core.widgetpicker
import com.android.launcher3.widgetpicker.WidgetPickerActivity
import javax.inject.Inject
/**
* A wrapper for widget picker activity that is responsible for displaying the compose based
* widget picker in [WidgetPickerActivity] when compose is enabled via build flag.
*/
interface WidgetPickerComposeWrapper {
fun showAllWidgets(activity: WidgetPickerActivity)
}
/**
* A No-op [WidgetPickerComposeWrapper] that doesn't include widget picker in dagger graph that
* don't involve widget picker e.g. launcher preview OR when compose is disabled via build flag.
*/
class NoOpWidgetPickerComposeWrapper @Inject constructor() : WidgetPickerComposeWrapper {
override fun showAllWidgets(activity: WidgetPickerActivity) {
error("Widget picker with compose is not supported")
}
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright (C) 2025 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.launcher3.compose.widgetpicker
import com.android.launcher3.compose.core.widgetpicker.NoOpWidgetPickerModule
import dagger.Module
/**
* A no-op module that is used when compose is disabled in launcher.
*/
@Module(includes = [NoOpWidgetPickerModule::class])
class LauncherWidgetPickerModule

View File

@@ -0,0 +1,63 @@
/*
* Copyright (C) 2025 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.launcher3.compose.widgetpicker
import com.android.launcher3.compose.core.widgetpicker.WidgetPickerComposeWrapper
import com.android.launcher3.widgetpicker.WidgetPickerComponent
import com.android.launcher3.widgetpicker.WidgetPickerComposeWrapperImpl
import com.android.launcher3.widgetpicker.data.repository.WidgetAppIconsRepository
import com.android.launcher3.widgetpicker.data.repository.WidgetUsersRepository
import com.android.launcher3.widgetpicker.data.repository.WidgetsRepository
import com.android.launcher3.widgetpicker.datasource.ConfigResourceFeaturedWidgetsDataSource
import com.android.launcher3.widgetpicker.datasource.FeaturedWidgetsDataSource
import com.android.launcher3.widgetpicker.datasource.InMemoryWidgetSearchAlgorithm
import com.android.launcher3.widgetpicker.datasource.WidgetsSearchAlgorithm
import com.android.launcher3.widgetpicker.repository.WidgetsRepositoryImpl
import com.android.launcher3.widgetpicker.repository.WidgetAppIconsRepositoryImpl
import com.android.launcher3.widgetpicker.repository.WidgetUsersRepositoryImpl
import dagger.Binds
import dagger.Module
/**
* A module that installs widget picker for launcher.
*/
@Module(subcomponents = [WidgetPickerComponent::class])
interface LauncherWidgetPickerModule {
@Binds
fun bindWidgetPickerComposeWrapper(
impl: WidgetPickerComposeWrapperImpl
): WidgetPickerComposeWrapper
@Binds
fun bindWidgetUsersRepository(impl: WidgetUsersRepositoryImpl): WidgetUsersRepository
@Binds
fun bindWidgetsRepository(impl: WidgetsRepositoryImpl): WidgetsRepository
@Binds
fun bindWidgetAppIconsRepository(impl: WidgetAppIconsRepositoryImpl): WidgetAppIconsRepository
@Binds
fun bindFeaturedWidgetsDataSource(
impl: ConfigResourceFeaturedWidgetsDataSource
): FeaturedWidgetsDataSource
@Binds
fun bindWidgetsSearchAlgorithm(
impl: InMemoryWidgetSearchAlgorithm
): WidgetsSearchAlgorithm
}

View File

@@ -0,0 +1,119 @@
/*
* Copyright (C) 2025 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.launcher3.widgetpicker
import android.content.Context
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalView
import com.android.launcher3.R
import com.android.launcher3.widgetpicker.WidgetPickerActivity
import com.android.launcher3.compose.ComposeFacade
import com.android.launcher3.compose.core.widgetpicker.WidgetPickerComposeWrapper
import com.android.launcher3.concurrent.annotations.BackgroundContext
import com.android.launcher3.dagger.ApplicationContext
import com.android.launcher3.widgetpicker.WidgetPickerComponent
import com.android.launcher3.widgetpicker.WidgetPickerEventListeners
import com.android.launcher3.widgetpicker.data.repository.WidgetAppIconsRepository
import com.android.launcher3.widgetpicker.data.repository.WidgetUsersRepository
import com.android.launcher3.widgetpicker.data.repository.WidgetsRepository
import com.android.launcher3.widgetpicker.shared.model.WidgetHostInfo
import kotlinx.coroutines.launch
import javax.inject.Inject
import javax.inject.Provider
import kotlin.coroutines.CoroutineContext
/**
* An helper that bootstraps widget picker UI (from [WidgetPickerComponent]) in to
* [WidgetPickerActivity].
*
* Sets up the bindings necessary for widget picker component.
*/
class WidgetPickerComposeWrapperImpl @Inject constructor(
private val widgetPickerComponentProvider: Provider<WidgetPickerComponent.Factory>,
private val widgetsRepository: WidgetsRepository,
private val widgetUsersRepository: WidgetUsersRepository,
private val widgetAppIconsRepository: WidgetAppIconsRepository,
@BackgroundContext
private val backgroundContext: CoroutineContext,
@ApplicationContext
private val appContext: Context,
) : WidgetPickerComposeWrapper {
override fun showAllWidgets(
activity: WidgetPickerActivity,
) {
val widgetPickerComponent = newWidgetPickerComponent()
val callbacks = object : WidgetPickerEventListeners {
override fun onClose() {
activity.finish()
}
}
val fullWidgetsCatalog = widgetPickerComponent.getFullWidgetsCatalog()
val composeView = ComposeFacade.initComposeView(activity.asContext()) as ComposeView
composeView.apply {
setContent {
val scope = rememberCoroutineScope()
val view = LocalView.current
MaterialTheme { // TODO(b/408283627): Use launcher theme.
val eventListeners = remember { callbacks }
fullWidgetsCatalog.Content(eventListeners)
}
DisposableEffect(view) {
scope.launch {
initializeRepositories()
}
onDispose {
cleanUpRepositories()
}
}
}
}
activity.dragLayer?.addView(composeView)
}
private fun newWidgetPickerComponent(): WidgetPickerComponent =
widgetPickerComponentProvider.get()
.build(
widgetsRepository = widgetsRepository,
widgetUsersRepository = widgetUsersRepository,
widgetAppIconsRepository = widgetAppIconsRepository,
widgetHostInfo = WidgetHostInfo(
appContext.resources.getString(R.string.widget_button_text)
),
backgroundContext = backgroundContext
)
private fun initializeRepositories() {
widgetsRepository.initialize()
widgetUsersRepository.initialize()
widgetAppIconsRepository.initialize()
}
private fun cleanUpRepositories() {
widgetsRepository.cleanUp()
widgetUsersRepository.cleanUp()
widgetAppIconsRepository.cleanUp()
}
}

View File

@@ -16,6 +16,7 @@
package com.android.launcher3.dagger;
import com.android.launcher3.compose.widgetpicker.LauncherWidgetPickerModule;
import com.android.launcher3.concurrent.ExecutorsModule;
import com.android.launcher3.util.dagger.LauncherExecutorsModule;
@@ -33,6 +34,7 @@ import dagger.Module;
LauncherConcurrencyModule.class,
ExecutorsModule.class,
LauncherExecutorsModule.class,
LauncherWidgetPickerModule.class
},
subcomponents = ActivityContextComponent.class)
public class LauncherAppModule { }

View File

@@ -25,6 +25,7 @@ import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.RemoveAnimationSettingsTracker;
import com.android.launcher3.backuprestore.LauncherRestoreEventLogger;
import com.android.launcher3.compose.core.widgetpicker.WidgetPickerComposeWrapper;
import com.android.launcher3.folder.FolderNameSuggestionLoader;
import com.android.launcher3.graphics.GridCustomizationsProxy;
import com.android.launcher3.graphics.ThemeManager;
@@ -100,7 +101,9 @@ public interface LauncherBaseAppComponent {
InstantAppResolver getInstantAppResolver();
DumpManager getDumpManager();
StatsLogManager.StatsLogManagerFactory getStatsLogManagerFactory();
ActivityContextComponent.Builder getActivityContextComponentBuilder();
ActivityContextComponent.Builder getActivityContextComponentBuilder();
WidgetPickerComposeWrapper getWidgetPickerComposeWrapper();
/** Builder for LauncherBaseAppComponent. */
interface Builder {

View File

@@ -71,6 +71,7 @@ import com.android.launcher3.R;
import com.android.launcher3.WorkspaceLayoutManager;
import com.android.launcher3.celllayout.CellLayoutLayoutParams;
import com.android.launcher3.celllayout.CellPosMapper;
import com.android.launcher3.compose.core.widgetpicker.NoOpWidgetPickerModule;
import com.android.launcher3.concurrent.ExecutorsModule;
import com.android.launcher3.dagger.ApiWrapperModule;
import com.android.launcher3.dagger.AppModule;
@@ -546,6 +547,7 @@ public class LauncherPreviewRenderer extends BaseContext
LauncherConcurrencyModule.class,
ExecutorsModule.class,
LauncherExecutorsModule.class,
NoOpWidgetPickerModule.class
})
public interface PreviewAppComponent extends LauncherAppComponent {

View File

@@ -50,7 +50,7 @@ open class WidgetPickerActivity : BaseActivity() {
checkNotNull(_dragLayer).recreateControllers()
if (Flags.enableWidgetPickerRefactor() && isComposeAvailable()) {
// TODO(b/408283627): add compose picker here.
component.widgetPickerComposeWrapper.showAllWidgets(this)
}
}