Home | History | Annotate | Download | only in mockime
      1 /*
      2  * Copyright (C) 2017 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 com.android.cts.mockime;
     18 
     19 import android.graphics.Point;
     20 import android.graphics.Rect;
     21 import android.os.Bundle;
     22 import android.view.Display;
     23 import android.view.View;
     24 import android.view.WindowInsets;
     25 
     26 import androidx.annotation.NonNull;
     27 import androidx.annotation.Nullable;
     28 
     29 /**
     30  * A collection of layout-related information when
     31  * {@link View.OnLayoutChangeListener#onLayoutChange(View, int, int, int, int, int, int, int, int)}
     32  * is called back for the input view (the view returned from {@link MockIme#onCreateInputView()}).
     33  */
     34 public final class ImeLayoutInfo {
     35 
     36     private static final String NEW_LAYOUT_KEY = "newLayout";
     37     private static final String OLD_LAYOUT_KEY = "oldLayout";
     38     private static final String VIEW_ORIGIN_ON_SCREEN_KEY = "viewOriginOnScreen";
     39     private static final String DISPLAY_SIZE_KEY = "displaySize";
     40     private static final String SYSTEM_WINDOW_INSET_KEY = "systemWindowInset";
     41     private static final String STABLE_INSET_KEY = "stableInset";
     42 
     43     @NonNull
     44     private final Rect mNewLayout;
     45     @NonNull
     46     private final Rect mOldLayout;
     47     @Nullable
     48     private Point mViewOriginOnScreen;
     49     @Nullable
     50     private Point mDisplaySize;
     51     @Nullable
     52     private Rect mSystemWindowInset;
     53     @Nullable
     54     private Rect mStableInset;
     55 
     56     /**
     57      * Returns the bounding box of the {@link View} passed to
     58      * {@link android.inputmethodservice.InputMethodService#onCreateInputView()} in screen
     59      * coordinates.
     60      *
     61      * <p>Currently this method assumes that no {@link View} in the hierarchy uses
     62      * transformations such as {@link View#setRotation(float)}.</p>
     63      *
     64      * @return Region in screen coordinates.
     65      */
     66     @Nullable
     67     public Rect getInputViewBoundsInScreen() {
     68         return new Rect(
     69                 mViewOriginOnScreen.x, mViewOriginOnScreen.y,
     70                 mViewOriginOnScreen.x + mNewLayout.width(),
     71                 mViewOriginOnScreen.y + mNewLayout.height());
     72     }
     73 
     74     /**
     75      * Returns the screen area in screen coordinates that does not overlap with the system
     76      * window inset, which represents the area of a full-screen window that is partially or
     77      * fully obscured by the status bar, navigation bar, IME or other system windows.
     78      *
     79      * <p>May return {@code null} when this information is not yet ready.</p>
     80      *
     81      * @return Region in screen coordinates. {@code null} when it is not available
     82      *
     83      * @see WindowInsets#hasSystemWindowInsets()
     84      * @see WindowInsets#getSystemWindowInsetBottom()
     85      * @see WindowInsets#getSystemWindowInsetLeft()
     86      * @see WindowInsets#getSystemWindowInsetRight()
     87      * @see WindowInsets#getSystemWindowInsetTop()
     88      */
     89     @Nullable
     90     public Rect getScreenRectWithoutSystemWindowInset() {
     91         if (mDisplaySize == null) {
     92             return null;
     93         }
     94         if (mSystemWindowInset == null) {
     95             return new Rect(0, 0, mDisplaySize.x, mDisplaySize.y);
     96         }
     97         return new Rect(mSystemWindowInset.left, mSystemWindowInset.top,
     98                 mDisplaySize.x - mSystemWindowInset.right,
     99                 mDisplaySize.y - mSystemWindowInset.bottom);
    100     }
    101 
    102     /**
    103      * Returns the screen area in screen coordinates that does not overlap with the stable
    104      * inset, which represents the area of a full-screen window that <b>may</b> be partially or
    105      * fully obscured by the system UI elements.
    106      *
    107      * <p>May return {@code null} when this information is not yet ready.</p>
    108      *
    109      * @return Region in screen coordinates. {@code null} when it is not available
    110      *
    111      * @see WindowInsets#hasStableInsets()
    112      * @see WindowInsets#getStableInsetBottom()
    113      * @see WindowInsets#getStableInsetLeft()
    114      * @see WindowInsets#getStableInsetRight()
    115      * @see WindowInsets#getStableInsetTop()
    116      */
    117     @Nullable
    118     public Rect getScreenRectWithoutStableInset() {
    119         if (mDisplaySize == null) {
    120             return null;
    121         }
    122         if (mStableInset == null) {
    123             return new Rect(0, 0, mDisplaySize.x, mDisplaySize.y);
    124         }
    125         return new Rect(mStableInset.left, mStableInset.top,
    126                 mDisplaySize.x - mStableInset.right,
    127                 mDisplaySize.y - mStableInset.bottom);
    128     }
    129 
    130     ImeLayoutInfo(@NonNull Rect newLayout, @NonNull Rect oldLayout,
    131             @NonNull Point viewOriginOnScreen, @Nullable Point displaySize,
    132             @Nullable Rect systemWindowInset, @Nullable Rect stableInset) {
    133         mNewLayout = new Rect(newLayout);
    134         mOldLayout = new Rect(oldLayout);
    135         mViewOriginOnScreen = new Point(viewOriginOnScreen);
    136         mDisplaySize = new Point(displaySize);
    137         mSystemWindowInset = systemWindowInset;
    138         mStableInset = stableInset;
    139     }
    140 
    141     void writeToBundle(@NonNull Bundle bundle) {
    142         bundle.putParcelable(NEW_LAYOUT_KEY, mNewLayout);
    143         bundle.putParcelable(OLD_LAYOUT_KEY, mOldLayout);
    144         bundle.putParcelable(VIEW_ORIGIN_ON_SCREEN_KEY, mViewOriginOnScreen);
    145         bundle.putParcelable(DISPLAY_SIZE_KEY, mDisplaySize);
    146         bundle.putParcelable(SYSTEM_WINDOW_INSET_KEY, mSystemWindowInset);
    147         bundle.putParcelable(STABLE_INSET_KEY, mStableInset);
    148     }
    149 
    150     static ImeLayoutInfo readFromBundle(@NonNull Bundle bundle) {
    151         final Rect newLayout = bundle.getParcelable(NEW_LAYOUT_KEY);
    152         final Rect oldLayout = bundle.getParcelable(OLD_LAYOUT_KEY);
    153         final Point viewOrigin = bundle.getParcelable(VIEW_ORIGIN_ON_SCREEN_KEY);
    154         final Point displaySize = bundle.getParcelable(DISPLAY_SIZE_KEY);
    155         final Rect systemWindowInset = bundle.getParcelable(SYSTEM_WINDOW_INSET_KEY);
    156         final Rect stableInset = bundle.getParcelable(STABLE_INSET_KEY);
    157 
    158         return new ImeLayoutInfo(newLayout, oldLayout, viewOrigin, displaySize, systemWindowInset,
    159                 stableInset);
    160     }
    161 
    162     static ImeLayoutInfo fromLayoutListenerCallback(View v, int left, int top, int right,
    163             int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
    164         final Rect newLayout = new Rect(left, top, right, bottom);
    165         final Rect oldLayout = new Rect(oldLeft, oldTop, oldRight, oldBottom);
    166         final int[] viewOriginArray = new int[2];
    167         v.getLocationOnScreen(viewOriginArray);
    168         final Point viewOrigin = new Point(viewOriginArray[0], viewOriginArray[1]);
    169         final Display display = v.getDisplay();
    170         final Point displaySize;
    171         if (display != null) {
    172             displaySize = new Point();
    173             display.getRealSize(displaySize);
    174         } else {
    175             displaySize = null;
    176         }
    177         final WindowInsets windowInsets = v.getRootWindowInsets();
    178         final Rect systemWindowInset;
    179         if (windowInsets != null && windowInsets.hasSystemWindowInsets()) {
    180             systemWindowInset = new Rect(
    181                     windowInsets.getSystemWindowInsetLeft(), windowInsets.getSystemWindowInsetTop(),
    182                     windowInsets.getSystemWindowInsetRight(),
    183                     windowInsets.getSystemWindowInsetBottom());
    184         } else {
    185             systemWindowInset = null;
    186         }
    187         final Rect stableInset;
    188         if (windowInsets != null && windowInsets.hasStableInsets()) {
    189             stableInset = new Rect(
    190                     windowInsets.getStableInsetLeft(), windowInsets.getStableInsetTop(),
    191                     windowInsets.getStableInsetRight(), windowInsets.getStableInsetBottom());
    192         } else {
    193             stableInset = null;
    194         }
    195         return new ImeLayoutInfo(newLayout, oldLayout, viewOrigin, displaySize, systemWindowInset,
    196                 stableInset);
    197     }
    198 }
    199