From 68e91829f8c26dfc91ef22f109694827e5d065b6 Mon Sep 17 00:00:00 2001 From: Jordan Demeulenaere Date: Fri, 16 Dec 2022 10:55:47 +0100 Subject: [PATCH 1/2] Add SystemUI build flag for Compose code (1/3) This CL adds a Soong build flag that enables Compose code when building SystemUI, or anything depending on SystemUI-core. The flag is disabled by default, and will be first used to measure the impact of Compose on our apk and system health. It will be turned on for one/many/all targets once agreed with the Android System Health & Performance team. To turn this flag on, one simply have to `export SYSTEMUI_USE_COMPOSE=true` before compiling. This flag is implemented such that: - When it is enabled, SystemUI-core depends on the SystemUIComposeCore library and compiles the source files of SystemUIComposeFeatures. In an ideal world, SystemUI-core would also just depend on SystemUIComposeFeatures instead of recompiling its sources, but given that the code in SystemUIComposeFeatures depends on code in SystemUI-core, this would lead to a cyclic dependency. Therefore, when this flag is enabled, we compile those files together. SystemUIComposeFeatures also contains a ComposeFacade object that is the bridge between SystemUI-core code and SystemUIComposeFeatures code. - When it is disabled, we only add another ComposeFacade object with the same API as the ComposeFacade object in SystemUIComposeFeatures, which throws when its functions are called (except for ComposeFacade#isComposeAvailable(), which returns false). This way, any code in SystemUI-core can check ComposeFacade#isComposeAvailable() first then call other functions to indirectly access Compose code. See http://ag/20759151 for an example. Bug: 242304109 Test: Builds Change-Id: Ibd895a73041c163816e779273ec0b6588aabef76 --- packages/SystemUI/Android.bp | 51 +++++++++++++++++++ .../android/systemui/compose/ComposeFacade.kt | 30 +++++++++++ .../android/systemui/compose/ComposeFacade.kt | 22 ++++++++ .../systemui/compose/BaseComposeFacade.kt | 34 +++++++++++++ 4 files changed, 137 insertions(+) create mode 100644 packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt create mode 100644 packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt create mode 100644 packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index 25fb24a3417fc..9515aa5d3f53c 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -31,6 +31,51 @@ license { ], } +// Opt-in configuration for code depending on Jetpack Compose. +soong_config_module_type { + name: "systemui_compose_java_defaults", + module_type: "java_defaults", + config_namespace: "ANDROID", + bool_variables: ["SYSTEMUI_USE_COMPOSE"], + properties: [ + "srcs", + "static_libs", + ], +} + +systemui_compose_java_defaults { + name: "SystemUI_compose_defaults", + soong_config_variables: { + SYSTEMUI_USE_COMPOSE: { + // Because files in compose/features/ depend on SystemUI + // code, we compile those files when compiling SystemUI-core. + // We also compile the ComposeFacade in + // compose/facade/enabled/. + srcs: [ + "compose/features/src/**/*.kt", + "compose/facade/enabled/src/**/*.kt", + ], + + // The dependencies needed by SystemUIComposeFeatures, + // except for SystemUI-core. + // Copied from compose/features/Android.bp. + static_libs: [ + "SystemUIComposeCore", + + "androidx.compose.runtime_runtime", + "androidx.compose.material3_material3", + ], + + // By default, Compose is disabled and we compile the ComposeFacade + // in compose/facade/disabled/. + conditions_default: { + srcs: ["compose/facade/disabled/src/**/*.kt"], + static_libs: [], + }, + }, + }, +} + java_library { name: "SystemUI-proto", @@ -68,6 +113,9 @@ filegroup { android_library { name: "SystemUI-core", + defaults: [ + "SystemUI_compose_defaults", + ], srcs: [ "src/**/*.kt", "src/**/*.java", @@ -227,6 +275,9 @@ android_library { android_library { name: "SystemUI-tests", + defaults: [ + "SystemUI_compose_defaults", + ], manifest: "tests/AndroidManifest-base.xml", additional_manifests: ["tests/AndroidManifest.xml"], srcs: [ diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt new file mode 100644 index 0000000000000..b3359070df8ca --- /dev/null +++ b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.android.systemui.compose + +/** The Compose facade, when Compose is *not* available. */ +object ComposeFacade : BaseComposeFacade { + override fun isComposeAvailable(): Boolean = false + + private fun throwComposeUnavailableError() { + error( + "Compose is not available. Make sure to check isComposeAvailable() before calling any" + + " other function on ComposeFacade." + ) + } +} diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt new file mode 100644 index 0000000000000..d950057404ca1 --- /dev/null +++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt @@ -0,0 +1,22 @@ +/* + * 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.compose + +/** The Compose facade, when Compose is available. */ +object ComposeFacade : BaseComposeFacade { + override fun isComposeAvailable(): Boolean = true +} diff --git a/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt b/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt new file mode 100644 index 0000000000000..859867a309ad4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt @@ -0,0 +1,34 @@ +/* + * 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.compose + +/** + * A facade to interact with Compose, when it is available. + * + * You should access this facade by calling the static methods on + * [com.android.systemui.compose.ComposeFacade] directly. + */ +interface BaseComposeFacade { + /** + * Whether Compose is currently available. This function should be checked before calling any + * other functions on this facade. + * + * This value will never change at runtime. + */ + fun isComposeAvailable(): Boolean +} From bf43b1d32d9e366371326a38df5f8a74daa7aa1b Mon Sep 17 00:00:00 2001 From: Jordan Demeulenaere Date: Fri, 16 Dec 2022 13:00:23 +0100 Subject: [PATCH 2/2] Show the Compose implementation of PeopleSpace when Compose is available Bug: 238993727 Test: Manual Change-Id: I41a6bae879e5a1f4e12f9ff998fb7f5d1320e135 --- packages/SystemUI/Android.bp | 1 + .../android/systemui/compose/ComposeFacade.kt | 11 +++++++++ .../android/systemui/compose/ComposeFacade.kt | 14 +++++++++++ packages/SystemUI/compose/features/Android.bp | 1 + .../systemui/compose/BaseComposeFacade.kt | 10 ++++++++ .../systemui/people/PeopleSpaceActivity.java | 23 +++++++++++++------ 6 files changed, 53 insertions(+), 7 deletions(-) diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index 9515aa5d3f53c..6b4d5ae86d1e9 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -64,6 +64,7 @@ systemui_compose_java_defaults { "androidx.compose.runtime_runtime", "androidx.compose.material3_material3", + "androidx.activity_activity-compose", ], // By default, Compose is disabled and we compile the ComposeFacade diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt index b3359070df8ca..6e728ce7248f1 100644 --- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt +++ b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt @@ -17,10 +17,21 @@ package com.android.systemui.compose +import androidx.activity.ComponentActivity +import com.android.systemui.people.ui.viewmodel.PeopleViewModel + /** The Compose facade, when Compose is *not* available. */ object ComposeFacade : BaseComposeFacade { override fun isComposeAvailable(): Boolean = false + override fun setPeopleSpaceActivityContent( + activity: ComponentActivity, + viewModel: PeopleViewModel, + onResult: (PeopleViewModel.Result) -> Unit, + ) { + throwComposeUnavailableError() + } + private fun throwComposeUnavailableError() { error( "Compose is not available. Make sure to check isComposeAvailable() before calling any" + diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt index d950057404ca1..16294d9c19772 100644 --- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt +++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt @@ -16,7 +16,21 @@ package com.android.systemui.compose +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import com.android.systemui.compose.theme.SystemUITheme +import com.android.systemui.people.ui.compose.PeopleScreen +import com.android.systemui.people.ui.viewmodel.PeopleViewModel + /** The Compose facade, when Compose is available. */ object ComposeFacade : BaseComposeFacade { override fun isComposeAvailable(): Boolean = true + + override fun setPeopleSpaceActivityContent( + activity: ComponentActivity, + viewModel: PeopleViewModel, + onResult: (PeopleViewModel.Result) -> Unit, + ) { + activity.setContent { SystemUITheme { PeopleScreen(viewModel, onResult) } } + } } diff --git a/packages/SystemUI/compose/features/Android.bp b/packages/SystemUI/compose/features/Android.bp index 325ede613de8e..4533330531180 100644 --- a/packages/SystemUI/compose/features/Android.bp +++ b/packages/SystemUI/compose/features/Android.bp @@ -35,6 +35,7 @@ android_library { "androidx.compose.runtime_runtime", "androidx.compose.material3_material3", + "androidx.activity_activity-compose", ], kotlincflags: ["-Xjvm-default=all"], diff --git a/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt b/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt index 859867a309ad4..e5ec727f04379 100644 --- a/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt +++ b/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt @@ -17,6 +17,9 @@ package com.android.systemui.compose +import androidx.activity.ComponentActivity +import com.android.systemui.people.ui.viewmodel.PeopleViewModel + /** * A facade to interact with Compose, when it is available. * @@ -31,4 +34,11 @@ interface BaseComposeFacade { * This value will never change at runtime. */ fun isComposeAvailable(): Boolean + + /** Bind the content of [activity] to [viewModel]. */ + fun setPeopleSpaceActivityContent( + activity: ComponentActivity, + viewModel: PeopleViewModel, + onResult: (PeopleViewModel.Result) -> Unit, + ) } diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java index 7cc95a158a140..fba5f63ea9c78 100644 --- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java +++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java @@ -27,11 +27,15 @@ import android.view.ViewGroup; import androidx.activity.ComponentActivity; import androidx.lifecycle.ViewModelProvider; +import com.android.systemui.compose.ComposeFacade; import com.android.systemui.people.ui.view.PeopleViewBinder; import com.android.systemui.people.ui.viewmodel.PeopleViewModel; import javax.inject.Inject; +import kotlin.Unit; +import kotlin.jvm.functions.Function1; + /** People Tile Widget configuration activity that shows the user their conversation tiles. */ public class PeopleSpaceActivity extends ComponentActivity { @@ -58,13 +62,18 @@ public class PeopleSpaceActivity extends ComponentActivity { int widgetId = getIntent().getIntExtra(EXTRA_APPWIDGET_ID, INVALID_APPWIDGET_ID); viewModel.onWidgetIdChanged(widgetId); - ViewGroup view = PeopleViewBinder.create(this); - PeopleViewBinder.bind(view, viewModel, /* lifecycleOwner= */ this, - (result) -> { - finishActivity(result); - return null; - }); - setContentView(view); + Function1 onResult = (result) -> { + finishActivity(result); + return null; + }; + + if (ComposeFacade.INSTANCE.isComposeAvailable()) { + ComposeFacade.INSTANCE.setPeopleSpaceActivityContent(this, viewModel, onResult); + } else { + ViewGroup view = PeopleViewBinder.create(this); + PeopleViewBinder.bind(view, viewModel, /* lifecycleOwner= */ this, onResult); + setContentView(view); + } } private void finishActivity(PeopleViewModel.Result result) {