diff options
5 files changed, 266 insertions, 0 deletions
diff --git a/tests/WindowInsetsTests/Android.bp b/tests/WindowInsetsTests/Android.bp new file mode 100644 index 000000000000..12395e70468d --- /dev/null +++ b/tests/WindowInsetsTests/Android.bp @@ -0,0 +1,22 @@ +// Copyright (C) 2020 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. + +android_test { + name: "WindowInsetsTests", + srcs: ["src/**/*.java"], + resource_dirs: ["res"], + certificate: "platform", + platform_apis: true, +} + diff --git a/tests/WindowInsetsTests/AndroidManifest.xml b/tests/WindowInsetsTests/AndroidManifest.xml new file mode 100644 index 000000000000..8d33f70c33a2 --- /dev/null +++ b/tests/WindowInsetsTests/AndroidManifest.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (018C) 2018 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 + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.google.android.test.windowinsetstests"> + + <application android:label="@string/activity_title"> + <activity android:name=".WindowInsetsActivity" + android:theme="@android:style/Theme.Material" + android:windowSoftInputMode="adjustResize"> + + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/tests/WindowInsetsTests/res/layout/window_inset_activity.xml b/tests/WindowInsetsTests/res/layout/window_inset_activity.xml new file mode 100644 index 000000000000..38e00298f49f --- /dev/null +++ b/tests/WindowInsetsTests/res/layout/window_inset_activity.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2018 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 + --> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="center" + android:id="@+id/root"> + + <Button + android:id="@+id/button" + android:layout_width="wrap_content" + android:layout_height="48dp" + android:text="Hello insets" /> + +</LinearLayout> + diff --git a/tests/WindowInsetsTests/res/values/strings.xml b/tests/WindowInsetsTests/res/values/strings.xml new file mode 100644 index 000000000000..242823d06fc8 --- /dev/null +++ b/tests/WindowInsetsTests/res/values/strings.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2018 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 + --> + +<resources> + <string name="activity_title">Window Insets Tests</string> +</resources> diff --git a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java new file mode 100644 index 000000000000..b8b2de5141a7 --- /dev/null +++ b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2018 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.google.android.test.windowinsetstests; + +import android.animation.ObjectAnimator; +import android.animation.TypeEvaluator; +import android.animation.ValueAnimator; +import android.app.Activity; +import android.graphics.Insets; +import android.os.Bundle; +import android.util.Property; +import android.view.View; +import android.view.WindowInsets; +import android.view.WindowInsets.Type; +import android.view.WindowInsetsAnimationCallback; +import android.view.WindowInsetsAnimationCallback.InsetsAnimation; +import android.view.WindowInsetsAnimationControlListener; +import android.view.WindowInsetsAnimationController; + +import com.google.android.test.windowinsetstests.R; + +public class WindowInsetsActivity extends Activity { + + private View mRoot; + private View mButton; + + private static class InsetsProperty extends Property<WindowInsetsAnimationController, Insets> { + + private final View mViewToAnimate; + private final Insets mShowingInsets; + + public InsetsProperty(View viewToAnimate, Insets showingInsets) { + super(Insets.class, "Insets"); + mViewToAnimate = viewToAnimate; + mShowingInsets = showingInsets; + } + + @Override + public Insets get(WindowInsetsAnimationController object) { + return object.getCurrentInsets(); + } + + @Override + public void set(WindowInsetsAnimationController object, Insets value) { + object.setInsetsAndAlpha(value, 1.0f, 0.5f); + if (mShowingInsets.bottom != 0) { + mViewToAnimate.setTranslationY(mShowingInsets.bottom - value.bottom); + } else if (mShowingInsets.right != 0) { + mViewToAnimate.setTranslationX(mShowingInsets.right - value.right); + } else if (mShowingInsets.left != 0) { + mViewToAnimate.setTranslationX(value.left - mShowingInsets.left); + } + } + }; + + float showY; + float hideY; + InsetsAnimation imeAnim; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.window_inset_activity); + mRoot = findViewById(R.id.root); + mButton = findViewById(R.id.button); + mButton.setOnClickListener(v -> { + if (!v.getRootWindowInsets().isVisible(Type.ime())) { + v.getWindowInsetsController().show(Type.ime()); + } else { + v.getWindowInsetsController().hide(Type.ime()); + } + }); + mRoot.getViewTreeObserver().addOnGlobalLayoutListener(() -> { + if (imeAnim == null) { + return; + } + if (mRoot.getRootWindowInsets().isVisible(Type.ime())) { + showY = mButton.getTop(); + } else { + hideY = mButton.getTop(); + } + }); + mRoot.setWindowInsetsAnimationCallback(new WindowInsetsAnimationCallback() { + + @Override + public void onPrepare(InsetsAnimation animation) { + if ((animation.getTypeMask() & Type.ime()) != 0) { + imeAnim = animation; + } + if (mRoot.getRootWindowInsets().isVisible(Type.ime())) { + showY = mButton.getTop(); + } else { + hideY = mButton.getTop(); + } + } + + @Override + public WindowInsets onProgress(WindowInsets insets) { + mButton.setY(hideY + (showY - hideY) * imeAnim.getInterpolatedFraction()); + return insets; + } + + @Override + public AnimationBounds onStart(InsetsAnimation animation, + AnimationBounds bounds) { + return bounds; + } + + @Override + public void onFinish(InsetsAnimation animation) { + imeAnim = null; + } + }); + } + + @Override + public void onAttachedToWindow() { + super.onAttachedToWindow(); + + TypeEvaluator<Insets> evaluator = (fraction, startValue, endValue) -> Insets.of( + (int)(startValue.left + fraction * (endValue.left - startValue.left)), + (int)(startValue.top + fraction * (endValue.top - startValue.top)), + (int)(startValue.right + fraction * (endValue.right - startValue.right)), + (int)(startValue.bottom + fraction * (endValue.bottom - startValue.bottom))); + + WindowInsetsAnimationControlListener listener = new WindowInsetsAnimationControlListener() { + @Override + public void onReady(WindowInsetsAnimationController controller, int types) { + ObjectAnimator animator = ObjectAnimator.ofObject(controller, + new InsetsProperty(findViewById(R.id.button), + controller.getShownStateInsets()), + evaluator, controller.getShownStateInsets(), + controller.getHiddenStateInsets()); + animator.setRepeatCount(ValueAnimator.INFINITE); + animator.setRepeatMode(ValueAnimator.REVERSE); + animator.start(); + } + + @Override + public void onCancelled() { + + } + }; + } +} |