/* * 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 android.server.wm; import static android.server.wm.LocationOnScreenTests.TestActivity.EXTRA_LAYOUT_PARAMS; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; import static androidx.test.InstrumentationRegistry.getInstrumentation; import static org.hamcrest.Matchers.is; import android.app.Activity; import android.content.Intent; import android.graphics.PixelFormat; import android.graphics.Point; import android.os.Bundle; import android.platform.test.annotations.Presubmit; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager.LayoutParams; import android.widget.FrameLayout; import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import androidx.test.rule.ActivityTestRule; import com.android.compatibility.common.util.PollingCheck; import org.hamcrest.Matcher; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ErrorCollector; import java.util.function.Supplier; @SmallTest @Presubmit public class LocationInWindowTests { @Rule public final ErrorCollector mErrorCollector = new ErrorCollector(); @Rule public final ActivityTestRule mActivity = new ActivityTestRule<>(TestActivity.class, false /* initialTouchMode */, false /* launchActivity */); private LayoutParams mLayoutParams; @Before public void setUp() { mLayoutParams = new LayoutParams(MATCH_PARENT, MATCH_PARENT, LayoutParams.TYPE_APPLICATION, LayoutParams.FLAG_LAYOUT_IN_SCREEN | LayoutParams.FLAG_LAYOUT_INSET_DECOR, PixelFormat.TRANSLUCENT); } @Test public void testLocationInWindow_appWindow() { runTest(mLayoutParams); } @Test public void testLocationInWindow_appWindow_fullscreen() { mLayoutParams.flags |= LayoutParams.FLAG_FULLSCREEN; runTest(mLayoutParams); } @Test public void testLocationInWindow_floatingWindow() { mLayoutParams.height = 100; mLayoutParams.width = 100; mLayoutParams.gravity = Gravity.CENTER; mLayoutParams.flags &= ~(FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR); runTest(mLayoutParams); } @Test public void testLocationInWindow_appWindow_displayCutoutNever() { mLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER; runTest(mLayoutParams); } @Test public void testLocationInWindow_appWindow_displayCutoutShortEdges() { mLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; runTest(mLayoutParams); } private void runTest(LayoutParams lp) { final TestActivity activity = launchAndWait(mActivity, lp); PollingCheck.waitFor(() -> getOnMainSync(activity::isEnterAnimationComplete)); runOnMainSync(() -> { assertThatViewGetLocationInWindowIsCorrect(activity.mView); }); } private void assertThatViewGetLocationInWindowIsCorrect(View v) { final float[] expected = new float[] {0, 0}; v.getMatrix().mapPoints(expected); expected[0] += v.getLeft(); expected[1] += v.getTop(); final View parent = (View)v.getParent(); expected[0] -= parent.getScrollX(); expected[1] -= parent.getScrollY(); final Point parentLocation = locationInWindowAsPoint(parent); expected[0] += parentLocation.x; expected[1] += parentLocation.y; Point actual = locationInWindowAsPoint(v); assertThat("getLocationInWindow returned wrong location", actual, is(new Point((int) expected[0], (int) expected[1]))); } private Point locationInWindowAsPoint(View v) { final int[] out = new int[2]; v.getLocationInWindow(out); return new Point(out[0], out[1]); } private void assertThat(String reason, T actual, Matcher matcher) { mErrorCollector.checkThat(reason, actual, matcher); } private R getOnMainSync(Supplier f) { final Object[] result = new Object[1]; runOnMainSync(() -> result[0] = f.get()); //noinspection unchecked return (R) result[0]; } private void runOnMainSync(Runnable runnable) { getInstrumentation().runOnMainSync(runnable); } private T launchAndWait(ActivityTestRule rule, LayoutParams lp) { final T activity = rule.launchActivity( new Intent().putExtra(EXTRA_LAYOUT_PARAMS, lp)); PollingCheck.waitFor(activity::hasWindowFocus); return activity; } public static class TestActivity extends Activity { static final String EXTRA_LAYOUT_PARAMS = "extra.layout_params"; private View mView; private boolean mEnterAnimationComplete; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().requestFeature(Window.FEATURE_NO_TITLE); FrameLayout frame = new FrameLayout(this); frame.setLayoutParams(new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); frame.setPadding(1, 2, 3, 4); setContentView(frame); mView = new View(this); final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(1, 1); lp.leftMargin = 6; lp.topMargin = 7; frame.addView(mView, lp); mView.setTranslationX(8); mView.setTranslationY(9); mView.setScrollX(10); mView.setScrollY(11); frame.setScrollX(12); frame.setScrollY(13); if (getIntent() != null && getIntent().getParcelableExtra(EXTRA_LAYOUT_PARAMS) != null) { getWindow().setAttributes(getIntent().getParcelableExtra(EXTRA_LAYOUT_PARAMS)); } } public boolean isEnterAnimationComplete() { return mEnterAnimationComplete; } @Override public void onEnterAnimationComplete() { super.onEnterAnimationComplete(); mEnterAnimationComplete = true; } } }