Add io settings macrobenchmark.

Bug: N/A
Test: "./gradlew
:compose:integration-tests:macrobenchmark:connectedCheck
-Pandroid.testInstrumentationRunnerArguments.class=androidx.compose.integration.macrobenchmark.IoSettingsStartupBenchmark"

Change-Id: If57f77f9cd113b0a25b920d00b114769f2681822
diff --git a/compose/integration-tests/macrobenchmark-target/src/main/AndroidManifest.xml b/compose/integration-tests/macrobenchmark-target/src/main/AndroidManifest.xml
index 532a2a4..35b0c0b 100644
--- a/compose/integration-tests/macrobenchmark-target/src/main/AndroidManifest.xml
+++ b/compose/integration-tests/macrobenchmark-target/src/main/AndroidManifest.xml
@@ -46,6 +46,18 @@
             </intent-filter>
         </activity>
         <activity
+            android:name=".IoSettingsActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="androidx.compose.integration.macrobenchmark.target.IO_SETTINGS_ACTIVITY" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+        <activity
             android:name=".LazyColumnActivity"
             android:exported="true">
             <intent-filter>
diff --git a/compose/integration-tests/macrobenchmark-target/src/main/java/androidx/compose/integration/macrobenchmark/target/IoSettingsActivity.kt b/compose/integration-tests/macrobenchmark-target/src/main/java/androidx/compose/integration/macrobenchmark/target/IoSettingsActivity.kt
new file mode 100644
index 0000000..589753f
--- /dev/null
+++ b/compose/integration-tests/macrobenchmark-target/src/main/java/androidx/compose/integration/macrobenchmark/target/IoSettingsActivity.kt
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2021 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 androidx.compose.integration.macrobenchmark.target
+
+import android.os.Bundle
+import android.util.Log
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.ColumnScope
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.sizeIn
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material.Divider
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.Surface
+import androidx.compose.material.Switch
+import androidx.compose.material.SwitchDefaults
+import androidx.compose.material.Text
+import androidx.compose.material.TextButton
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.SideEffect
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import androidx.core.os.LocaleListCompat
+
+val marginSmall: Dp = 10.dp
+val marginNormal: Dp = 20.dp
+val spacingNormal: Dp = 10.dp
+
+class IoSettingsActivity : ComponentActivity() {
+    // This is here to trick the compiler to recompose right after we change the model (otherwise
+    // it would skip recomposing).
+    val isLoading = mutableStateOf(true)
+    val switchesOn = mutableStateOf(false)
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContent {
+            MaterialTheme {
+                Surface {
+                    SettingsScreen(isLoading.value, switchesOn.value)
+                }
+            }
+
+            if (isLoading.value) {
+                // Forces another recomposition right after this one. Simulates a delayed ViewModel
+                // that kicks-in later on.
+                SideEffect {
+                    isLoading.value = false
+                    switchesOn.value = true
+                }
+            }
+        }
+    }
+}
+
+@Composable
+fun SettingsScreen(
+    isLoading: Boolean,
+    switchesOn: Boolean
+) {
+    Box(Modifier.fillMaxSize()) {
+        SettingsScreenContent(
+            isLoading = isLoading,
+            switchesOn = switchesOn,
+            openWebsiteLink = { url -> Log.d("IO", "Open $url") }
+        )
+    }
+}
+
+@Composable
+private fun SettingsScreenContent(
+    isLoading: Boolean,
+    switchesOn: Boolean,
+    openWebsiteLink: (String) -> Unit
+) {
+    if (isLoading) {
+        Box(Modifier.fillMaxWidth()) {}
+    } else {
+        Column(Modifier.padding(vertical = marginNormal).verticalScroll(rememberScrollState())) {
+            SettingsSection(switchesOn)
+            SettingsSection(switchesOn)
+            SettingsSection(switchesOn)
+            SettingsSection(switchesOn)
+
+            Divider(Modifier.fillMaxWidth())
+            Spacer(Modifier.height(spacingNormal))
+            AboutSection(openWebsiteLink)
+        }
+    }
+}
+
+@Composable
+private fun ColumnScope.SettingsSection(
+    switchesOn: Boolean
+) {
+    val switchModifier = Modifier
+        .padding(marginNormal)
+        .fillMaxWidth()
+    SwitchSetting(
+        text = stringResource(R.string.io_settings_time_zone_label),
+        checked = switchesOn,
+        onCheck = { Log.d("IO", "timezoneCheck") },
+        modifier = switchModifier
+    )
+    SwitchSetting(
+        text = stringResource(R.string.io_settings_enable_notifications),
+        checked = switchesOn,
+        onCheck = { Log.d("IO", "notifCheck") },
+        modifier = switchModifier
+    )
+    SwitchSetting(
+        text = stringResource(R.string.io_settings_send_anonymous_usage_statistics),
+        checked = switchesOn,
+        onCheck = { Log.d("IO", "usageCheck") },
+        modifier = switchModifier
+    )
+}
+
+@Composable
+private fun AboutSection(
+    openWebsiteLink: (String) -> Unit
+) {
+    Text(
+        text = stringResource(R.string.io_about_title).toUpperCase(
+            LocaleListCompat.getDefault().get(0)
+        ),
+        style = MaterialTheme.typography.body2,
+        fontWeight = FontWeight.SemiBold,
+        color = MaterialTheme.colors.onSurface.copy(alpha = 0.6f),
+        modifier = Modifier.padding(marginNormal)
+    )
+
+    val tosUrl = stringResource(R.string.io_tos_url)
+    TextButton(
+        modifier = Modifier.padding(marginSmall),
+        onClick = {
+            openWebsiteLink(tosUrl)
+        }
+    ) {
+        LinkText(stringResource(R.string.io_settings_tos))
+    }
+
+    val privacyPolicyUrl = stringResource(R.string.io_privacy_policy_url)
+    TextButton(
+        modifier = Modifier.padding(marginSmall),
+        onClick = {
+            openWebsiteLink(privacyPolicyUrl)
+        }
+    ) {
+        LinkText(stringResource(R.string.io_settings_privacy_policy))
+    }
+
+    TextButton(
+        modifier = Modifier.padding(marginSmall),
+        onClick = { Log.d("IO", "Click") }
+    ) {
+        LinkText(stringResource(R.string.io_settings_oss_licenses))
+    }
+
+    Text(
+        text = stringResource(R.string.io_version_name, "test"),
+        modifier = Modifier
+            .fillMaxWidth()
+            .sizeIn(minHeight = 48.dp)
+            .padding(marginNormal),
+        style = MaterialTheme.typography.body2,
+    )
+}
+
+@Composable
+private fun LinkText(text: String) {
+    Text(
+        text = text,
+        modifier = Modifier.fillMaxWidth(),
+        style = MaterialTheme.typography.body1
+    )
+}
+
+@Composable
+private fun SwitchSetting(
+    text: String,
+    checked: Boolean,
+    onCheck: (Boolean) -> Unit,
+    modifier: Modifier = Modifier
+) {
+    Row(modifier) {
+        Text(
+            text = text,
+            modifier = Modifier
+                .weight(1f)
+                .align(Alignment.CenterVertically),
+            style = MaterialTheme.typography.body2
+        )
+        Switch(
+            checked = checked,
+            onCheckedChange = onCheck,
+            colors = SwitchDefaults.colors(
+                checkedThumbColor = MaterialTheme.colors.primary
+            )
+        )
+    }
+}
diff --git a/compose/integration-tests/macrobenchmark-target/src/main/res/values/strings.xml b/compose/integration-tests/macrobenchmark-target/src/main/res/values/strings.xml
new file mode 100644
index 0000000..19b2ab5
--- /dev/null
+++ b/compose/integration-tests/macrobenchmark-target/src/main/res/values/strings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2021 Google LLC
+  ~
+  ~ 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
+  ~
+  ~     https://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.
+  -->
+
+<resources>
+    <string name="io_version_name" translation_description="Label for the app version name in Settings.">Version %s</string>
+    <string name="io_about_title" translation_description="Title for the 'About' tab that shows miscellaneous info.">About</string>
+    <string name="io_tos_url" translatable="false">https://policies.google.com/terms</string>
+    <string name="io_privacy_policy_url" translatable="false">https://policies.google.com/privacy</string>
+    <string name="io_settings_time_zone_label" translate_description="Set time zone in app to PST.">Events in Pacific Time Zone (UTC-8)</string>
+    <string name="io_settings_enable_notifications" translate_description="Turn on notifications.">Enable notifications</string>
+    <string name="io_settings_send_anonymous_usage_statistics" translation_description="Enable sending usage statistics.">Send anonymous usage statistics</string>
+    <string name="io_settings_tos" translation_description="Open link to terms of service.">Terms of service</string>
+    <string name="io_settings_privacy_policy" translation_description="Open link to privacy policy.">Privacy policy</string>
+    <string name="io_settings_oss_licenses" translation_description="Open link to open source licenses.">Open sources licenses</string>
+</resources>
diff --git a/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/IoSettingsStartupBenchmark.kt b/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/IoSettingsStartupBenchmark.kt
new file mode 100644
index 0000000..cc5e31f
--- /dev/null
+++ b/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/IoSettingsStartupBenchmark.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2021 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 androidx.compose.integration.macrobenchmark
+
+import androidx.benchmark.macro.CompilationMode
+import androidx.benchmark.macro.StartupMode
+import androidx.benchmark.macro.junit4.MacrobenchmarkRule
+import androidx.test.filters.LargeTest
+import androidx.testutils.createStartupCompilationParams
+import androidx.testutils.measureStartup
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@LargeTest
+@RunWith(Parameterized::class)
+class IoSettingsStartupBenchmark(
+    private val startupMode: StartupMode,
+    private val compilationMode: CompilationMode
+) {
+    @get:Rule
+    val benchmarkRule = MacrobenchmarkRule()
+
+    @Test
+    fun startup() = benchmarkRule.measureStartup(
+        compilationMode = compilationMode,
+        startupMode = startupMode,
+        packageName = "androidx.compose.integration.macrobenchmark.target"
+    ) {
+        action = "androidx.compose.integration.macrobenchmark.target.IO_SETTINGS_ACTIVITY"
+    }
+
+    companion object {
+        @Parameterized.Parameters(name = "startup={0},compilation={1}")
+        @JvmStatic
+        fun parameters() = createStartupCompilationParams()
+    }
+}