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 17 package android.app; 18 19 import static android.app.WindowConfiguration.ROTATION_UNDEFINED; 20 import static android.view.Surface.ROTATION_0; 21 import static android.view.Surface.ROTATION_90; 22 23 import android.annotation.IntDef; 24 import android.annotation.NonNull; 25 import android.annotation.Nullable; 26 import android.os.Parcel; 27 import android.os.Parcelable; 28 import android.view.Surface; 29 30 import java.lang.annotation.Retention; 31 import java.lang.annotation.RetentionPolicy; 32 33 /** 34 * Stores Camera Compat information about a particular Task. 35 * @hide 36 */ 37 public class CameraCompatTaskInfo implements Parcelable { 38 /** 39 * Undefined camera compat mode. 40 */ 41 public static final int CAMERA_COMPAT_FREEFORM_UNSPECIFIED = 0; 42 43 /** 44 * The value to use when no camera compat treatment should be applied to a windowed task. 45 */ 46 public static final int CAMERA_COMPAT_FREEFORM_NONE = 1; 47 48 /** 49 * The value to use when camera compat treatment should be applied to an activity requesting 50 * portrait orientation, while a device is in landscape. Applies only to freeform tasks. 51 */ 52 public static final int CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE = 2; 53 54 /** 55 * The value to use when camera compat treatment should be applied to an activity requesting 56 * landscape orientation, while a device is in landscape. Applies only to freeform tasks. 57 */ 58 public static final int CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_LANDSCAPE = 3; 59 60 /** 61 * The value to use when camera compat treatment should be applied to an activity requesting 62 * portrait orientation, while a device is in portrait. Applies only to freeform tasks. 63 */ 64 public static final int CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_PORTRAIT = 4; 65 66 /** 67 * The value to use when camera compat treatment should be applied to an activity requesting 68 * landscape orientation, while a device is in portrait. Applies only to freeform tasks. 69 */ 70 public static final int CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_PORTRAIT = 5; 71 72 @Retention(RetentionPolicy.SOURCE) 73 @IntDef(prefix = { "CAMERA_COMPAT_FREEFORM_" }, value = { 74 CAMERA_COMPAT_FREEFORM_UNSPECIFIED, 75 CAMERA_COMPAT_FREEFORM_NONE, 76 CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE, 77 CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_LANDSCAPE, 78 CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_PORTRAIT, 79 CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_PORTRAIT, 80 }) 81 public @interface FreeformCameraCompatMode {} 82 83 /** 84 * Whether the camera activity is letterboxed in freeform windowing mode to emulate expected 85 * aspect ratio for fixed-orientation apps. 86 * 87 * <p>This field is used by the WM and the camera framework, to coordinate camera compat mode 88 * setup. 89 */ 90 @FreeformCameraCompatMode 91 public int freeformCameraCompatMode; 92 CameraCompatTaskInfo()93 private CameraCompatTaskInfo() { 94 // Do nothing 95 } 96 97 @NonNull create()98 static CameraCompatTaskInfo create() { 99 return new CameraCompatTaskInfo(); 100 } 101 CameraCompatTaskInfo(Parcel source)102 private CameraCompatTaskInfo(Parcel source) { 103 readFromParcel(source); 104 } 105 106 @Override describeContents()107 public int describeContents() { 108 return 0; 109 } 110 111 public static final Creator<CameraCompatTaskInfo> CREATOR = 112 new Creator<>() { 113 @Override 114 public CameraCompatTaskInfo createFromParcel(Parcel in) { 115 return new CameraCompatTaskInfo(in); 116 } 117 118 @Override 119 public CameraCompatTaskInfo[] newArray(int size) { 120 return new CameraCompatTaskInfo[size]; 121 } 122 }; 123 124 /** 125 * Reads the CameraCompatTaskInfo from a parcel. 126 */ readFromParcel(Parcel source)127 void readFromParcel(Parcel source) { 128 freeformCameraCompatMode = source.readInt(); 129 } 130 131 /** 132 * Writes the CameraCompatTaskInfo to a parcel. 133 */ 134 @Override writeToParcel(Parcel dest, int flags)135 public void writeToParcel(Parcel dest, int flags) { 136 dest.writeInt(freeformCameraCompatMode); 137 } 138 139 /** 140 * @return {@code true} if the camera compat parameters that are important for task organizers 141 * are equal. 142 */ equalsForTaskOrganizer(@ullable CameraCompatTaskInfo that)143 public boolean equalsForTaskOrganizer(@Nullable CameraCompatTaskInfo that) { 144 if (that == null) { 145 return false; 146 } 147 return freeformCameraCompatMode == that.freeformCameraCompatMode; 148 } 149 150 /** 151 * @return {@code true} if parameters that are important for size compat have changed. 152 */ equalsForCompatUi(@ullable CameraCompatTaskInfo that)153 public boolean equalsForCompatUi(@Nullable CameraCompatTaskInfo that) { 154 if (that == null) { 155 return false; 156 } 157 return freeformCameraCompatMode == that.freeformCameraCompatMode; 158 } 159 160 @Override toString()161 public String toString() { 162 return "CameraCompatTaskInfo { freeformCameraCompatMode=" 163 + freeformCameraCompatModeToString(freeformCameraCompatMode) 164 + "}"; 165 } 166 167 /** 168 * Returns the sandboxed display rotation based on the given {@code cameraCompatMode}. 169 * 170 * <p>This will be what the app likely expects in its requested orientation while running on a 171 * device with portrait natural orientation: `CAMERA_COMPAT_FREEFORM_PORTRAIT_*` is 0, and 172 * `CAMERA_COMPAT_FREEFORM_LANDSCAPE_*` is 90. 173 * 174 * @return {@link WindowConfiguration#ROTATION_UNDEFINED} if not in camera compat mode. 175 */ 176 @Surface.Rotation getDisplayRotationFromCameraCompatMode(@reeformCameraCompatMode int cameraCompatMode)177 public static int getDisplayRotationFromCameraCompatMode(@FreeformCameraCompatMode int 178 cameraCompatMode) { 179 return switch (cameraCompatMode) { 180 case CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE, 181 CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_PORTRAIT -> ROTATION_0; 182 case CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_LANDSCAPE, 183 CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_PORTRAIT -> ROTATION_90; 184 default -> ROTATION_UNDEFINED; 185 }; 186 } 187 188 /** Human readable version of the freeform camera compat mode. */ 189 @NonNull freeformCameraCompatModeToString( @reeformCameraCompatMode int freeformCameraCompatMode)190 public static String freeformCameraCompatModeToString( 191 @FreeformCameraCompatMode int freeformCameraCompatMode) { 192 return switch (freeformCameraCompatMode) { 193 case CAMERA_COMPAT_FREEFORM_UNSPECIFIED -> "undefined"; 194 case CAMERA_COMPAT_FREEFORM_NONE -> "inactive"; 195 case CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE -> 196 "app-portrait-device-landscape"; 197 case CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_LANDSCAPE -> 198 "app-landscape-device-landscape"; 199 case CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_PORTRAIT -> 200 "app-portrait-device-portrait"; 201 case CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_PORTRAIT -> 202 "app-landscape-device-portrait"; 203 default -> throw new AssertionError( 204 "Unexpected camera compat mode: " + freeformCameraCompatMode); 205 }; 206 } 207 } 208