| /* |
| * Copyright (C) 2017 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 android.view.inputmethod.cts.util; |
| |
| import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED; |
| |
| import android.app.Activity; |
| import android.content.Intent; |
| import android.os.Bundle; |
| import android.view.View; |
| import android.view.Window; |
| import android.view.WindowManager; |
| |
| import androidx.annotation.AnyThread; |
| import androidx.annotation.NonNull; |
| import androidx.annotation.UiThread; |
| import androidx.test.InstrumentationRegistry; |
| |
| import java.util.concurrent.atomic.AtomicBoolean; |
| import java.util.concurrent.atomic.AtomicReference; |
| import java.util.function.Function; |
| |
| public final class TestActivity extends Activity { |
| |
| private static final AtomicReference<Function<TestActivity, View>> sInitializer = |
| new AtomicReference<>(); |
| |
| private Function<TestActivity, View> mInitializer = null; |
| |
| private AtomicBoolean mIgnoreBackKey = new AtomicBoolean(); |
| |
| private long mOnBackPressedCallCount; |
| |
| /** |
| * Controls how {@link #onBackPressed()} behaves. |
| * |
| * <p>TODO: Use {@link android.app.AppComponentFactory} instead to customise the behavior of |
| * {@link TestActivity}.</p> |
| * |
| * @param ignore {@code true} when {@link TestActivity} should do nothing when |
| * {@link #onBackPressed()} is called |
| */ |
| @AnyThread |
| public void setIgnoreBackKey(boolean ignore) { |
| mIgnoreBackKey.set(ignore); |
| } |
| |
| @UiThread |
| public long getOnBackPressedCallCount() { |
| return mOnBackPressedCallCount; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| protected void onCreate(Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| if (mInitializer == null) { |
| mInitializer = sInitializer.get(); |
| } |
| // Currently SOFT_INPUT_STATE_UNSPECIFIED isn't appropriate for CTS test because there is no |
| // clear spec about how it behaves. In order to make our tests deterministic, currently we |
| // must use SOFT_INPUT_STATE_UNCHANGED. |
| // TODO(Bug 77152727): Remove the following code once we define how |
| // SOFT_INPUT_STATE_UNSPECIFIED actually behaves. |
| setSoftInputState(SOFT_INPUT_STATE_UNCHANGED); |
| setContentView(mInitializer.apply(this)); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public void onBackPressed() { |
| ++mOnBackPressedCallCount; |
| if (mIgnoreBackKey.get()) { |
| return; |
| } |
| super.onBackPressed(); |
| } |
| |
| /** |
| * Launches {@link TestActivity} with the given initialization logic for content view. |
| * |
| * <p>As long as you are using {@link androidx.test.runner.AndroidJUnitRunner}, the test |
| * runner automatically calls {@link Activity#finish()} for the {@link Activity} launched when |
| * the test finished. You do not need to explicitly call {@link Activity#finish()}.</p> |
| * |
| * @param activityInitializer initializer to supply {@link View} to be passed to |
| * {@link Activity#setContentView(View)} |
| * @return {@link TestActivity} launched |
| */ |
| public static TestActivity startSync( |
| @NonNull Function<TestActivity, View> activityInitializer) { |
| return startSync(activityInitializer, 0 /* noAnimation */); |
| } |
| |
| /** |
| * Launches {@link TestActivity} with the given initialization logic for content view. |
| * |
| * <p>As long as you are using {@link androidx.test.runner.AndroidJUnitRunner}, the test |
| * runner automatically calls {@link Activity#finish()} for the {@link Activity} launched when |
| * the test finished. You do not need to explicitly call {@link Activity#finish()}.</p> |
| * |
| * @param activityInitializer initializer to supply {@link View} to be passed to |
| * {@link Activity#setContentView(View)} |
| * @param additionalFlags flags to be set to {@link Intent#setFlags(int)} |
| * @return {@link TestActivity} launched |
| */ |
| public static TestActivity startSync( |
| @NonNull Function<TestActivity, View> activityInitializer, |
| int additionalFlags) { |
| sInitializer.set(activityInitializer); |
| final Intent intent = new Intent() |
| .setAction(Intent.ACTION_MAIN) |
| .setClass(InstrumentationRegistry.getContext(), TestActivity.class) |
| .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) |
| .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) |
| .addFlags(additionalFlags); |
| return (TestActivity) InstrumentationRegistry |
| .getInstrumentation().startActivitySync(intent); |
| } |
| |
| /** |
| * Updates {@link WindowManager.LayoutParams#softInputMode}. |
| * |
| * @param newState One of {@link WindowManager.LayoutParams#SOFT_INPUT_STATE_UNSPECIFIED}, |
| * {@link WindowManager.LayoutParams#SOFT_INPUT_STATE_UNCHANGED}, |
| * {@link WindowManager.LayoutParams#SOFT_INPUT_STATE_HIDDEN}, |
| * {@link WindowManager.LayoutParams#SOFT_INPUT_STATE_ALWAYS_HIDDEN}, |
| * {@link WindowManager.LayoutParams#SOFT_INPUT_STATE_VISIBLE}, |
| * {@link WindowManager.LayoutParams#SOFT_INPUT_STATE_ALWAYS_VISIBLE} |
| */ |
| private void setSoftInputState(int newState) { |
| final Window window = getWindow(); |
| final int currentSoftInputMode = window.getAttributes().softInputMode; |
| final int newSoftInputMode = |
| (currentSoftInputMode & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) |
| | newState; |
| window.setSoftInputMode(newSoftInputMode); |
| } |
| } |