1 /* 2 * Copyright (C) 2021 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 androidx.window.util; 18 19 import static android.view.Surface.ROTATION_270; 20 import static android.view.Surface.ROTATION_90; 21 22 import android.annotation.SuppressLint; 23 import android.app.WindowConfiguration; 24 import android.content.Context; 25 import android.graphics.Rect; 26 import android.hardware.display.DisplayManagerGlobal; 27 import android.util.RotationUtils; 28 import android.view.DisplayInfo; 29 import android.view.Surface; 30 import android.view.WindowManager; 31 32 import androidx.annotation.NonNull; 33 import androidx.annotation.UiContext; 34 import androidx.annotation.VisibleForTesting; 35 36 /** 37 * Util class for both Sidecar and Extensions. 38 */ 39 public final class ExtensionHelper { 40 ExtensionHelper()41 private ExtensionHelper() { 42 // Util class, no instances should be created. 43 } 44 45 /** 46 * Rotates the input rectangle specified in default display orientation to the current display 47 * rotation. 48 * 49 * @param displayId the display id. 50 * @param rotation the target rotation relative to the default display orientation. 51 * @param inOutRect the input/output Rect as specified in the default display orientation. 52 */ rotateRectToDisplayRotation( int displayId, @Surface.Rotation int rotation, @NonNull Rect inOutRect)53 public static void rotateRectToDisplayRotation( 54 int displayId, @Surface.Rotation int rotation, @NonNull Rect inOutRect) { 55 final DisplayManagerGlobal dmGlobal = DisplayManagerGlobal.getInstance(); 56 final DisplayInfo displayInfo = dmGlobal.getDisplayInfo(displayId); 57 58 rotateRectToDisplayRotation(displayInfo, rotation, inOutRect); 59 } 60 61 // We suppress the Lint error CheckResult for Rect#intersect because in case the displayInfo and 62 // folding features are out of sync, e.g. when a foldable devices is unfolding, it is acceptable 63 // to provide the original folding feature Rect even if they don't intersect. 64 @SuppressLint("RectIntersectReturnValueIgnored") 65 @VisibleForTesting rotateRectToDisplayRotation(@onNull DisplayInfo displayInfo, @Surface.Rotation int rotation, @NonNull Rect inOutRect)66 static void rotateRectToDisplayRotation(@NonNull DisplayInfo displayInfo, 67 @Surface.Rotation int rotation, @NonNull Rect inOutRect) { 68 // The inOutRect is specified in the default display orientation, so here we need to get 69 // the display width and height in the default orientation to perform the intersection and 70 // rotation. 71 final boolean isSideRotation = 72 displayInfo.rotation == ROTATION_90 || displayInfo.rotation == ROTATION_270; 73 final int baseDisplayWidth = 74 isSideRotation ? displayInfo.logicalHeight : displayInfo.logicalWidth; 75 final int baseDisplayHeight = 76 isSideRotation ? displayInfo.logicalWidth : displayInfo.logicalHeight; 77 78 inOutRect.intersect(0, 0, baseDisplayWidth, baseDisplayHeight); 79 80 RotationUtils.rotateBounds(inOutRect, baseDisplayWidth, baseDisplayHeight, rotation); 81 } 82 83 /** Transforms rectangle from absolute coordinate space to the window coordinate space. */ transformToWindowSpaceRect(@onNull @iContext Context context, Rect inOutRect)84 public static void transformToWindowSpaceRect(@NonNull @UiContext Context context, 85 Rect inOutRect) { 86 transformToWindowSpaceRect(getWindowBounds(context), inOutRect); 87 } 88 89 /** @see ExtensionHelper#transformToWindowSpaceRect(Context, Rect) */ transformToWindowSpaceRect(@onNull WindowConfiguration windowConfiguration, Rect inOutRect)90 public static void transformToWindowSpaceRect(@NonNull WindowConfiguration windowConfiguration, 91 Rect inOutRect) { 92 transformToWindowSpaceRect(windowConfiguration.getBounds(), inOutRect); 93 } 94 transformToWindowSpaceRect(@onNull Rect bounds, @NonNull Rect inOutRect)95 private static void transformToWindowSpaceRect(@NonNull Rect bounds, @NonNull Rect inOutRect) { 96 if (!inOutRect.intersect(bounds)) { 97 inOutRect.setEmpty(); 98 return; 99 } 100 inOutRect.offset(-bounds.left, -bounds.top); 101 } 102 103 /** 104 * Gets the current window bounds in absolute coordinates. 105 */ 106 @NonNull getWindowBounds(@onNull @iContext Context context)107 private static Rect getWindowBounds(@NonNull @UiContext Context context) { 108 return context.getSystemService(WindowManager.class).getCurrentWindowMetrics().getBounds(); 109 } 110 111 /** 112 * Checks if both dimensions of the given rect are zero at the same time. 113 */ isZero(@onNull Rect rect)114 public static boolean isZero(@NonNull Rect rect) { 115 return rect.height() == 0 && rect.width() == 0; 116 } 117 } 118