Home | History | Annotate | Download | only in wm
      1 /*
      2  * Copyright (C) 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.server.wm;
     18 
     19 import static android.server.wm.LocationOnScreenTests.TestActivity.EXTRA_LAYOUT_PARAMS;
     20 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
     21 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
     22 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
     23 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
     24 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
     25 
     26 import static androidx.test.InstrumentationRegistry.getInstrumentation;
     27 
     28 import static org.hamcrest.Matchers.is;
     29 
     30 import android.app.Activity;
     31 import android.content.Intent;
     32 import android.graphics.PixelFormat;
     33 import android.graphics.Point;
     34 import android.os.Bundle;
     35 import android.platform.test.annotations.Presubmit;
     36 import android.view.Gravity;
     37 import android.view.View;
     38 import android.view.ViewGroup;
     39 import android.view.Window;
     40 import android.view.WindowManager.LayoutParams;
     41 import android.widget.FrameLayout;
     42 
     43 import androidx.test.filters.FlakyTest;
     44 import androidx.test.filters.SmallTest;
     45 import androidx.test.rule.ActivityTestRule;
     46 
     47 import com.android.compatibility.common.util.PollingCheck;
     48 
     49 import org.hamcrest.Matcher;
     50 import org.junit.Before;
     51 import org.junit.Rule;
     52 import org.junit.Test;
     53 import org.junit.rules.ErrorCollector;
     54 
     55 import java.util.function.Supplier;
     56 
     57 @SmallTest
     58 @Presubmit
     59 public class LocationInWindowTests {
     60 
     61     @Rule
     62     public final ErrorCollector mErrorCollector = new ErrorCollector();
     63 
     64     @Rule
     65     public final ActivityTestRule<TestActivity> mActivity =
     66             new ActivityTestRule<>(TestActivity.class, false /* initialTouchMode */,
     67                     false /* launchActivity */);
     68 
     69     private LayoutParams mLayoutParams;
     70 
     71     @Before
     72     public void setUp() {
     73         mLayoutParams = new LayoutParams(MATCH_PARENT, MATCH_PARENT, LayoutParams.TYPE_APPLICATION,
     74                 LayoutParams.FLAG_LAYOUT_IN_SCREEN | LayoutParams.FLAG_LAYOUT_INSET_DECOR,
     75                 PixelFormat.TRANSLUCENT);
     76     }
     77 
     78     @Test
     79     public void testLocationInWindow_appWindow() {
     80         runTest(mLayoutParams);
     81     }
     82 
     83     @Test
     84     public void testLocationInWindow_appWindow_fullscreen() {
     85         mLayoutParams.flags |= LayoutParams.FLAG_FULLSCREEN;
     86         runTest(mLayoutParams);
     87     }
     88 
     89     @Test
     90     public void testLocationInWindow_floatingWindow() {
     91         mLayoutParams.height = 100;
     92         mLayoutParams.width = 100;
     93         mLayoutParams.gravity = Gravity.CENTER;
     94         mLayoutParams.flags &= ~(FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR);
     95         runTest(mLayoutParams);
     96     }
     97 
     98     @Test
     99     public void testLocationInWindow_appWindow_displayCutoutNever() {
    100         mLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
    101         runTest(mLayoutParams);
    102     }
    103 
    104     @Test
    105     public void testLocationInWindow_appWindow_displayCutoutShortEdges() {
    106         mLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
    107         runTest(mLayoutParams);
    108     }
    109 
    110     private void runTest(LayoutParams lp) {
    111         final TestActivity activity = launchAndWait(mActivity, lp);
    112         PollingCheck.waitFor(() -> getOnMainSync(activity::isEnterAnimationComplete));
    113 
    114         runOnMainSync(() -> {
    115             assertThatViewGetLocationInWindowIsCorrect(activity.mView);
    116         });
    117     }
    118 
    119     private void assertThatViewGetLocationInWindowIsCorrect(View v) {
    120         final float[] expected = new float[] {0, 0};
    121 
    122         v.getMatrix().mapPoints(expected);
    123         expected[0] += v.getLeft();
    124         expected[1] += v.getTop();
    125 
    126         final View parent = (View)v.getParent();
    127         expected[0] -= parent.getScrollX();
    128         expected[1] -= parent.getScrollY();
    129 
    130         final Point parentLocation = locationInWindowAsPoint(parent);
    131         expected[0] += parentLocation.x;
    132         expected[1] += parentLocation.y;
    133 
    134         Point actual = locationInWindowAsPoint(v);
    135 
    136         assertThat("getLocationInWindow returned wrong location",
    137                 actual, is(new Point((int) expected[0], (int) expected[1])));
    138     }
    139 
    140     private Point locationInWindowAsPoint(View v) {
    141         final int[] out = new int[2];
    142         v.getLocationInWindow(out);
    143         return new Point(out[0], out[1]);
    144     }
    145 
    146     private <T> void assertThat(String reason, T actual, Matcher<? super T> matcher) {
    147         mErrorCollector.checkThat(reason, actual, matcher);
    148     }
    149 
    150     private <R> R getOnMainSync(Supplier<R> f) {
    151         final Object[] result = new Object[1];
    152         runOnMainSync(() -> result[0] = f.get());
    153         //noinspection unchecked
    154         return (R) result[0];
    155     }
    156 
    157     private void runOnMainSync(Runnable runnable) {
    158         getInstrumentation().runOnMainSync(runnable);
    159     }
    160 
    161     private <T extends Activity> T launchAndWait(ActivityTestRule<T> rule,
    162             LayoutParams lp) {
    163         final T activity = rule.launchActivity(
    164                 new Intent().putExtra(EXTRA_LAYOUT_PARAMS, lp));
    165         PollingCheck.waitFor(activity::hasWindowFocus);
    166         return activity;
    167     }
    168 
    169     public static class TestActivity extends Activity {
    170 
    171         static final String EXTRA_LAYOUT_PARAMS = "extra.layout_params";
    172         private View mView;
    173         private boolean mEnterAnimationComplete;
    174 
    175         @Override
    176         protected void onCreate(Bundle savedInstanceState) {
    177             super.onCreate(savedInstanceState);
    178             getWindow().requestFeature(Window.FEATURE_NO_TITLE);
    179 
    180             FrameLayout frame = new FrameLayout(this);
    181             frame.setLayoutParams(new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
    182             frame.setPadding(1, 2, 3, 4);
    183             setContentView(frame);
    184 
    185             mView = new View(this);
    186             final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(1, 1);
    187             lp.leftMargin = 6;
    188             lp.topMargin = 7;
    189             frame.addView(mView, lp);
    190             mView.setTranslationX(8);
    191             mView.setTranslationY(9);
    192             mView.setScrollX(10);
    193             mView.setScrollY(11);
    194             frame.setScrollX(12);
    195             frame.setScrollY(13);
    196 
    197             if (getIntent() != null
    198                     && getIntent().getParcelableExtra(EXTRA_LAYOUT_PARAMS) != null) {
    199                 getWindow().setAttributes(getIntent().getParcelableExtra(EXTRA_LAYOUT_PARAMS));
    200             }
    201         }
    202 
    203         public boolean isEnterAnimationComplete() {
    204             return mEnterAnimationComplete;
    205         }
    206 
    207         @Override
    208         public void onEnterAnimationComplete() {
    209             super.onEnterAnimationComplete();
    210             mEnterAnimationComplete = true;
    211         }
    212     }
    213 }
    214