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_0; 20 import static android.view.Surface.ROTATION_180; 21 import static android.view.Surface.ROTATION_270; 22 import static android.view.Surface.ROTATION_90; 23 24 import android.app.WindowConfiguration; 25 import android.content.Context; 26 import android.graphics.Rect; 27 import android.hardware.display.DisplayManagerGlobal; 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 35 /** 36 * Util class for both Sidecar and Extensions. 37 */ 38 public final class ExtensionHelper { 39 ExtensionHelper()40 private ExtensionHelper() { 41 // Util class, no instances should be created. 42 } 43 44 /** 45 * Rotates the input rectangle specified in default display orientation to the current display 46 * rotation. 47 */ rotateRectToDisplayRotation(int displayId, Rect inOutRect)48 public static void rotateRectToDisplayRotation(int displayId, Rect inOutRect) { 49 DisplayManagerGlobal dmGlobal = DisplayManagerGlobal.getInstance(); 50 DisplayInfo displayInfo = dmGlobal.getDisplayInfo(displayId); 51 int rotation = displayInfo.rotation; 52 53 boolean isSideRotation = rotation == ROTATION_90 || rotation == ROTATION_270; 54 int displayWidth = isSideRotation ? displayInfo.logicalHeight : displayInfo.logicalWidth; 55 int displayHeight = isSideRotation ? displayInfo.logicalWidth : displayInfo.logicalHeight; 56 57 inOutRect.intersect(0, 0, displayWidth, displayHeight); 58 59 rotateBounds(inOutRect, displayWidth, displayHeight, rotation); 60 } 61 62 /** 63 * Rotates the input rectangle within parent bounds for a given delta. 64 */ rotateBounds(Rect inOutRect, int parentWidth, int parentHeight, @Surface.Rotation int delta)65 private static void rotateBounds(Rect inOutRect, int parentWidth, int parentHeight, 66 @Surface.Rotation int delta) { 67 int origLeft = inOutRect.left; 68 switch (delta) { 69 case ROTATION_0: 70 return; 71 case ROTATION_90: 72 inOutRect.left = inOutRect.top; 73 inOutRect.top = parentWidth - inOutRect.right; 74 inOutRect.right = inOutRect.bottom; 75 inOutRect.bottom = parentWidth - origLeft; 76 return; 77 case ROTATION_180: 78 inOutRect.left = parentWidth - inOutRect.right; 79 inOutRect.right = parentWidth - origLeft; 80 return; 81 case ROTATION_270: 82 inOutRect.left = parentHeight - inOutRect.bottom; 83 inOutRect.bottom = inOutRect.right; 84 inOutRect.right = parentHeight - inOutRect.top; 85 inOutRect.top = origLeft; 86 return; 87 } 88 } 89 90 /** Transforms rectangle from absolute coordinate space to the window coordinate space. */ transformToWindowSpaceRect(@onNull @iContext Context context, Rect inOutRect)91 public static void transformToWindowSpaceRect(@NonNull @UiContext Context context, 92 Rect inOutRect) { 93 transformToWindowSpaceRect(getWindowBounds(context), inOutRect); 94 } 95 96 /** @see ExtensionHelper#transformToWindowSpaceRect(Context, Rect) */ transformToWindowSpaceRect(@onNull WindowConfiguration windowConfiguration, Rect inOutRect)97 public static void transformToWindowSpaceRect(@NonNull WindowConfiguration windowConfiguration, 98 Rect inOutRect) { 99 transformToWindowSpaceRect(windowConfiguration.getBounds(), inOutRect); 100 } 101 transformToWindowSpaceRect(@onNull Rect bounds, @NonNull Rect inOutRect)102 private static void transformToWindowSpaceRect(@NonNull Rect bounds, @NonNull Rect inOutRect) { 103 if (!inOutRect.intersect(bounds)) { 104 inOutRect.setEmpty(); 105 return; 106 } 107 inOutRect.offset(-bounds.left, -bounds.top); 108 } 109 110 /** 111 * Gets the current window bounds in absolute coordinates. 112 */ 113 @NonNull getWindowBounds(@onNull @iContext Context context)114 private static Rect getWindowBounds(@NonNull @UiContext Context context) { 115 return context.getSystemService(WindowManager.class).getCurrentWindowMetrics().getBounds(); 116 } 117 118 /** 119 * Checks if both dimensions of the given rect are zero at the same time. 120 */ isZero(@onNull Rect rect)121 public static boolean isZero(@NonNull Rect rect) { 122 return rect.height() == 0 && rect.width() == 0; 123 } 124 } 125