1 /* 2 * Copyright (C) 2020 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.sidecar; 18 19 import static android.view.Display.INVALID_DISPLAY; 20 import static android.view.Surface.ROTATION_0; 21 import static android.view.Surface.ROTATION_180; 22 import static android.view.Surface.ROTATION_270; 23 import static android.view.Surface.ROTATION_90; 24 25 import android.app.Activity; 26 import android.app.ActivityThread; 27 import android.graphics.Rect; 28 import android.hardware.display.DisplayManagerGlobal; 29 import android.os.IBinder; 30 import android.view.DisplayInfo; 31 import android.view.Surface; 32 33 import androidx.annotation.Nullable; 34 35 class SidecarHelper { 36 /** 37 * Rotate the input rectangle specified in default display orientation to the current display 38 * rotation. 39 */ rotateRectToDisplayRotation(Rect inOutRect, int displayId)40 static void rotateRectToDisplayRotation(Rect inOutRect, int displayId) { 41 DisplayManagerGlobal dmGlobal = DisplayManagerGlobal.getInstance(); 42 DisplayInfo displayInfo = dmGlobal.getDisplayInfo(displayId); 43 int rotation = displayInfo.rotation; 44 45 boolean isSideRotation = rotation == ROTATION_90 || rotation == ROTATION_270; 46 int displayWidth = isSideRotation ? displayInfo.logicalHeight : displayInfo.logicalWidth; 47 int displayHeight = isSideRotation ? displayInfo.logicalWidth : displayInfo.logicalHeight; 48 49 inOutRect.intersect(0, 0, displayWidth, displayHeight); 50 51 rotateBounds(inOutRect, displayWidth, displayHeight, rotation); 52 } 53 54 /** 55 * Rotate the input rectangle within parent bounds for a given delta. 56 */ rotateBounds(Rect inOutRect, int parentWidth, int parentHeight, @Surface.Rotation int delta)57 private static void rotateBounds(Rect inOutRect, int parentWidth, int parentHeight, 58 @Surface.Rotation int delta) { 59 int origLeft = inOutRect.left; 60 switch (delta) { 61 case ROTATION_0: 62 return; 63 case ROTATION_90: 64 inOutRect.left = inOutRect.top; 65 inOutRect.top = parentWidth - inOutRect.right; 66 inOutRect.right = inOutRect.bottom; 67 inOutRect.bottom = parentWidth - origLeft; 68 return; 69 case ROTATION_180: 70 inOutRect.left = parentWidth - inOutRect.right; 71 inOutRect.right = parentWidth - origLeft; 72 return; 73 case ROTATION_270: 74 inOutRect.left = parentHeight - inOutRect.bottom; 75 inOutRect.bottom = inOutRect.right; 76 inOutRect.right = parentHeight - inOutRect.top; 77 inOutRect.top = origLeft; 78 return; 79 } 80 } 81 82 /** Transform rectangle from absolute coordinate space to the window coordinate space. */ transformToWindowSpaceRect(Rect inOutRect, IBinder windowToken)83 static void transformToWindowSpaceRect(Rect inOutRect, IBinder windowToken) { 84 Rect windowRect = getWindowBounds(windowToken); 85 if (windowRect == null) { 86 inOutRect.setEmpty(); 87 return; 88 } 89 if (!Rect.intersects(inOutRect, windowRect)) { 90 inOutRect.setEmpty(); 91 return; 92 } 93 inOutRect.intersect(windowRect); 94 inOutRect.offset(-windowRect.left, -windowRect.top); 95 } 96 97 /** 98 * Get the current window bounds in absolute coordinates. 99 * NOTE: Only works with Activity windows. 100 */ 101 @Nullable getWindowBounds(IBinder windowToken)102 private static Rect getWindowBounds(IBinder windowToken) { 103 Activity activity = ActivityThread.currentActivityThread().getActivity(windowToken); 104 return activity != null 105 ? activity.getWindowManager().getCurrentWindowMetrics().getBounds() 106 : null; 107 } 108 109 /** 110 * Check if this window is an Activity window that is in multi-window mode. 111 */ isInMultiWindow(IBinder windowToken)112 static boolean isInMultiWindow(IBinder windowToken) { 113 Activity activity = ActivityThread.currentActivityThread().getActivity(windowToken); 114 return activity != null && activity.isInMultiWindowMode(); 115 } 116 117 /** 118 * Get the id of the parent display for the window. 119 * NOTE: Only works with Activity windows. 120 */ getWindowDisplay(IBinder windowToken)121 static int getWindowDisplay(IBinder windowToken) { 122 Activity activity = ActivityThread.currentActivityThread().getActivity(windowToken); 123 return activity != null 124 ? activity.getWindowManager().getDefaultDisplay().getDisplayId() : INVALID_DISPLAY; 125 } 126 } 127