From 2cf183d14c22bf2e5ea831f5d63ce3b4e2eb1205 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 6 Jun 2023 08:56:07 -0700 Subject: [PATCH] Adding some utility test rules > LasyActivityRule to be used by ActivityScenario > Utility rule to easily override feature flags Bug: 284202543 Test: Presubmit flag: N/A Change-Id: I95ae19bfb1d67a55941e7b8e5c47516a351b0d24 --- .../launcher3/util/rule/LazyActivityRule.java | 120 ++++++++++++++++++ .../launcher3/util/rule/WrapperRule.kt | 46 +++++++ 2 files changed, 166 insertions(+) create mode 100644 tests/src/com/android/launcher3/util/rule/LazyActivityRule.java create mode 100644 tests/src/com/android/launcher3/util/rule/WrapperRule.kt diff --git a/tests/src/com/android/launcher3/util/rule/LazyActivityRule.java b/tests/src/com/android/launcher3/util/rule/LazyActivityRule.java new file mode 100644 index 0000000000..6c300bbc87 --- /dev/null +++ b/tests/src/com/android/launcher3/util/rule/LazyActivityRule.java @@ -0,0 +1,120 @@ +/* + * 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.launcher3.util.rule; + +import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; +import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; +import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ResolveInfo; + +import androidx.annotation.Nullable; +import androidx.test.core.app.ActivityScenario; + +import com.android.launcher3.Launcher; + +import org.junit.rules.ExternalResource; + +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +/** + * Similar to {@code ActivityScenarioRule} but it creates the activity lazily when needed + */ +public class LazyActivityRule extends ExternalResource { + + private final Supplier> mScenarioSupplier; + + @Nullable private ActivityScenario mScenario; + + /** + * Constructs LazyActivityScenarioRule for a given scenario provider. + */ + public LazyActivityRule(Supplier> supplier) { + mScenarioSupplier = supplier; + } + + /** + * Resets the rule, such that the activity is in closed state + */ + public synchronized void reset() { + if (mScenario != null) { + try { + mScenario.close(); + } catch (AssertionError e) { + // Ignore errors during close + } + } + mScenario = null; + } + + @Override + protected synchronized void after() { + reset(); + } + + /** + * Returns the scenario, creating one if it doesn't exist + */ + public synchronized ActivityScenario getScenario() { + if (mScenario == null) { + mScenario = mScenarioSupplier.get(); + } + return mScenario; + } + + /** + * Executes the function {@code f} on the activities main thread and returns the result + */ + public T getFromActivity(Function f) { + AtomicReference result = new AtomicReference<>(); + getScenario().onActivity(a -> result.set(f.apply(a))); + return result.get(); + } + + /** + * Runs the provided function {@code f} on the activity if the scenario is already created + */ + public synchronized void runOnActivity(Consumer f) { + if (mScenario != null) { + mScenario.onActivity(f::accept); + } + } + + /** + * Returns a {@link LazyActivityRule} for the Launcher activity + */ + public static LazyActivityRule forLauncher() { + Context context = getInstrumentation().getTargetContext(); + // Create the activity after the model setup is done. + Intent homeIntent = new Intent(Intent.ACTION_MAIN) + .addCategory(Intent.CATEGORY_HOME) + .addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK + | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | FLAG_ACTIVITY_NO_ANIMATION); + ResolveInfo ri = context.getPackageManager().resolveActivity( + new Intent(homeIntent).setPackage(context.getPackageName()), 0); + homeIntent.setComponent(ri.getComponentInfo().getComponentName()); + return new LazyActivityRule<>(() -> ActivityScenario.launch(homeIntent)); + } +} diff --git a/tests/src/com/android/launcher3/util/rule/WrapperRule.kt b/tests/src/com/android/launcher3/util/rule/WrapperRule.kt new file mode 100644 index 0000000000..290cc450ec --- /dev/null +++ b/tests/src/com/android/launcher3/util/rule/WrapperRule.kt @@ -0,0 +1,46 @@ +/* + * 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.launcher3.util.rule + +import com.android.launcher3.config.FeatureFlags.BooleanFlag +import com.android.launcher3.config.FeatureFlags.IntFlag +import com.android.launcher3.util.SafeCloseable +import com.android.launcher3.util.TestUtil +import java.util.function.Supplier +import org.junit.rules.ExternalResource + +/** Simple rule which wraps any SafeCloseable object */ +class WrapperRule(private val overrideProvider: Supplier) : ExternalResource() { + + private lateinit var overrideClosable: SafeCloseable + + override fun before() { + overrideClosable = overrideProvider.get() + } + + override fun after() { + overrideClosable.close() + } + + companion object { + + fun BooleanFlag.overrideFlag(value: Boolean) = WrapperRule { + TestUtil.overrideFlag(this, value) + } + + fun IntFlag.overrideFlag(value: Int) = WrapperRule { TestUtil.overrideFlag(this, value) } + } +}