1 /* 2 * Copyright (C) 2024 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 package androidx.window.sidecar; 17 18 import static android.view.Display.DEFAULT_DISPLAY; 19 20 import static androidx.window.common.ExtensionHelper.rotateRectToDisplayRotation; 21 import static androidx.window.common.ExtensionHelper.transformToWindowSpaceRect; 22 23 import android.annotation.NonNull; 24 import android.app.Activity; 25 import android.app.ActivityThread; 26 import android.graphics.Rect; 27 import android.hardware.display.DisplayManagerGlobal; 28 import android.os.IBinder; 29 import android.view.DisplayInfo; 30 31 import androidx.window.common.layout.CommonFoldingFeature; 32 33 import java.util.ArrayList; 34 import java.util.Collections; 35 import java.util.List; 36 37 /** 38 * A utility class for transforming between Sidecar and Extensions features. 39 */ 40 class SidecarHelper { 41 SidecarHelper()42 private SidecarHelper() {} 43 44 /** 45 * Returns the {@link SidecarDeviceState} posture that is calculated for the first fold in 46 * the feature list. Sidecar devices only have one fold so we only pick the first one to 47 * determine the state. 48 * @param featureList the {@link CommonFoldingFeature} that are currently active. 49 * @return the {@link SidecarDeviceState} calculated from the {@link List} of 50 * {@link CommonFoldingFeature}. 51 */ 52 @SuppressWarnings("deprecation") deviceStateFromFeatureList(@onNull List<CommonFoldingFeature> featureList)53 private static int deviceStateFromFeatureList(@NonNull List<CommonFoldingFeature> featureList) { 54 for (int i = 0; i < featureList.size(); i++) { 55 final CommonFoldingFeature feature = featureList.get(i); 56 final int state = feature.getState(); 57 switch (state) { 58 case CommonFoldingFeature.COMMON_STATE_FLAT: 59 return SidecarDeviceState.POSTURE_OPENED; 60 case CommonFoldingFeature.COMMON_STATE_HALF_OPENED: 61 return SidecarDeviceState.POSTURE_HALF_OPENED; 62 case CommonFoldingFeature.COMMON_STATE_UNKNOWN: 63 return SidecarDeviceState.POSTURE_UNKNOWN; 64 case CommonFoldingFeature.COMMON_STATE_NO_FOLDING_FEATURES: 65 return SidecarDeviceState.POSTURE_UNKNOWN; 66 case CommonFoldingFeature.COMMON_STATE_USE_BASE_STATE: 67 return SidecarDeviceState.POSTURE_UNKNOWN; 68 } 69 } 70 return SidecarDeviceState.POSTURE_UNKNOWN; 71 } 72 73 /** 74 * Returns a {@link SidecarDeviceState} calculated from a {@link List} of 75 * {@link CommonFoldingFeature}s. 76 */ 77 @SuppressWarnings("deprecation") calculateDeviceState( @onNull List<CommonFoldingFeature> featureList)78 static SidecarDeviceState calculateDeviceState( 79 @NonNull List<CommonFoldingFeature> featureList) { 80 final SidecarDeviceState deviceState = new SidecarDeviceState(); 81 deviceState.posture = deviceStateFromFeatureList(featureList); 82 return deviceState; 83 } 84 85 @SuppressWarnings("deprecation") calculateDisplayFeatures( @onNull Activity activity, @NonNull List<CommonFoldingFeature> featureList )86 private static List<SidecarDisplayFeature> calculateDisplayFeatures( 87 @NonNull Activity activity, 88 @NonNull List<CommonFoldingFeature> featureList 89 ) { 90 final int displayId = activity.getDisplay().getDisplayId(); 91 if (displayId != DEFAULT_DISPLAY) { 92 return Collections.emptyList(); 93 } 94 95 if (activity.isInMultiWindowMode()) { 96 // It is recommended not to report any display features in multi-window mode, since it 97 // won't be possible to synchronize the display feature positions with window movement. 98 return Collections.emptyList(); 99 } 100 101 // We will transform the feature bounds to the Activity window, so using the rotation 102 // from the same source (WindowConfiguration) to make sure they are synchronized. 103 final int rotation = activity.getResources().getConfiguration().windowConfiguration 104 .getDisplayRotation(); 105 final DisplayInfo displayInfo = 106 DisplayManagerGlobal.getInstance().getDisplayInfo(displayId); 107 108 final List<SidecarDisplayFeature> features = new ArrayList<>(); 109 for (CommonFoldingFeature baseFeature : featureList) { 110 final SidecarDisplayFeature feature = new SidecarDisplayFeature(); 111 final Rect featureRect = baseFeature.getRect(); 112 rotateRectToDisplayRotation(displayInfo, rotation, featureRect); 113 transformToWindowSpaceRect(activity, featureRect); 114 feature.setRect(featureRect); 115 feature.setType(baseFeature.getType()); 116 features.add(feature); 117 } 118 return Collections.unmodifiableList(features); 119 } 120 121 /** 122 * Returns a {@link SidecarWindowLayoutInfo} calculated from the {@link List} of 123 * {@link CommonFoldingFeature}. 124 */ 125 @SuppressWarnings("deprecation") calculateWindowLayoutInfo(@onNull IBinder windowToken, @NonNull List<CommonFoldingFeature> featureList)126 static SidecarWindowLayoutInfo calculateWindowLayoutInfo(@NonNull IBinder windowToken, 127 @NonNull List<CommonFoldingFeature> featureList) { 128 final Activity activity = ActivityThread.currentActivityThread().getActivity(windowToken); 129 final SidecarWindowLayoutInfo windowLayoutInfo = new SidecarWindowLayoutInfo(); 130 if (activity == null) { 131 return windowLayoutInfo; 132 } 133 windowLayoutInfo.displayFeatures = calculateDisplayFeatures(activity, featureList); 134 return windowLayoutInfo; 135 } 136 } 137