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 android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 
25 import java.lang.annotation.Retention;
26 import java.lang.annotation.RetentionPolicy;
27 
28 /**
29  * Stores Camera Compat information about a particular Task.
30  * @hide
31  */
32 public class CameraCompatTaskInfo implements Parcelable {
33     /**
34      * Camera compat control isn't shown because it's not requested by heuristics.
35      */
36     public static final int CAMERA_COMPAT_CONTROL_HIDDEN = 0;
37 
38     /**
39      * Camera compat control is shown with the treatment suggested.
40      */
41     public static final int CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED = 1;
42 
43     /**
44      * Camera compat control is shown to allow reverting the applied treatment.
45      */
46     public static final int CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED = 2;
47 
48     /**
49      * Camera compat control is dismissed by user.
50      */
51     public static final int CAMERA_COMPAT_CONTROL_DISMISSED = 3;
52 
53     /**
54      * Enum for the Camera app compat control states.
55      */
56     @Retention(RetentionPolicy.SOURCE)
57     @IntDef(prefix = { "CAMERA_COMPAT_CONTROL_" }, value = {
58             CAMERA_COMPAT_CONTROL_HIDDEN,
59             CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED,
60             CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED,
61             CAMERA_COMPAT_CONTROL_DISMISSED,
62     })
63     public @interface CameraCompatControlState {}
64 
65     /**
66      * State of the Camera app compat control which is used to correct stretched viewfinder
67      * in apps that don't handle all possible configurations and changes between them correctly.
68      */
69     @CameraCompatControlState
70     public int cameraCompatControlState = CAMERA_COMPAT_CONTROL_HIDDEN;
71 
72     /**
73      * The value to use when no camera compat treatment should be applied to a windowed task.
74      */
75     public static final int CAMERA_COMPAT_FREEFORM_NONE = 0;
76 
77     /**
78      * The value to use when portrait camera compat treatment should be applied to a windowed task.
79      */
80     public static final int CAMERA_COMPAT_FREEFORM_PORTRAIT = 1;
81 
82     /**
83      * The value to use when landscape camera compat treatment should be applied to a windowed task.
84      */
85     public static final int CAMERA_COMPAT_FREEFORM_LANDSCAPE = 2;
86 
87     @Retention(RetentionPolicy.SOURCE)
88     @IntDef(prefix = { "CAMERA_COMPAT_FREEFORM_" }, value = {
89             CAMERA_COMPAT_FREEFORM_NONE,
90             CAMERA_COMPAT_FREEFORM_PORTRAIT,
91             CAMERA_COMPAT_FREEFORM_LANDSCAPE,
92     })
93     public @interface FreeformCameraCompatMode {}
94 
95     /**
96      * Whether the camera activity is letterboxed in freeform windowing mode to emulate expected
97      * aspect ratio for fixed-orientation apps.
98      *
99      * <p>This field is used by the WM and the camera framework, to coordinate camera compat mode
100      * setup.
101      */
102     @FreeformCameraCompatMode
103     public int freeformCameraCompatMode;
104 
CameraCompatTaskInfo()105     private CameraCompatTaskInfo() {
106         // Do nothing
107     }
108 
109     @NonNull
create()110     static CameraCompatTaskInfo create() {
111         return new CameraCompatTaskInfo();
112     }
113 
CameraCompatTaskInfo(Parcel source)114     private CameraCompatTaskInfo(Parcel source) {
115         readFromParcel(source);
116     }
117 
118     @Override
describeContents()119     public int describeContents() {
120         return 0;
121     }
122 
123     public static final Creator<CameraCompatTaskInfo> CREATOR =
124             new Creator<>() {
125                 @Override
126                 public CameraCompatTaskInfo createFromParcel(Parcel in) {
127                     return new CameraCompatTaskInfo(in);
128                 }
129 
130                 @Override
131                 public CameraCompatTaskInfo[] newArray(int size) {
132                     return new CameraCompatTaskInfo[size];
133                 }
134             };
135 
136     /**
137      * Reads the CameraCompatTaskInfo from a parcel.
138      */
readFromParcel(Parcel source)139     void readFromParcel(Parcel source) {
140         cameraCompatControlState = source.readInt();
141         freeformCameraCompatMode = source.readInt();
142     }
143 
144     /**
145      * Writes the CameraCompatTaskInfo to a parcel.
146      */
147     @Override
writeToParcel(Parcel dest, int flags)148     public void writeToParcel(Parcel dest, int flags) {
149         dest.writeInt(cameraCompatControlState);
150         dest.writeInt(freeformCameraCompatMode);
151     }
152 
153     /**
154      * @return {@value true} if the task has camera compat controls.
155      */
hasCameraCompatControl()156     public boolean hasCameraCompatControl() {
157         return cameraCompatControlState != CAMERA_COMPAT_CONTROL_HIDDEN
158                 && cameraCompatControlState != CAMERA_COMPAT_CONTROL_DISMISSED;
159     }
160 
161     /**
162      * @return {@value true} if the task has some compat ui.
163      */
hasCameraCompatUI()164     public boolean hasCameraCompatUI() {
165         return hasCameraCompatControl();
166     }
167 
168     /**
169      * @return  {@code true} if the camera compat parameters that are important for task organizers
170      * are equal.
171      */
equalsForTaskOrganizer(@ullable CameraCompatTaskInfo that)172     public boolean equalsForTaskOrganizer(@Nullable CameraCompatTaskInfo that) {
173         if (that == null) {
174             return false;
175         }
176         return freeformCameraCompatMode == that.freeformCameraCompatMode;
177     }
178 
179     /**
180      * @return {@code true} if parameters that are important for size compat have changed.
181      */
equalsForCompatUi(@ullable CameraCompatTaskInfo that)182     public boolean equalsForCompatUi(@Nullable CameraCompatTaskInfo that) {
183         if (that == null) {
184             return false;
185         }
186         return cameraCompatControlState == that.cameraCompatControlState
187                 && freeformCameraCompatMode == that.freeformCameraCompatMode;
188     }
189 
190     @Override
toString()191     public String toString() {
192         return "CameraCompatTaskInfo { cameraCompatControlState="
193                 + cameraCompatControlStateToString(cameraCompatControlState)
194                 + " freeformCameraCompatMode="
195                 + freeformCameraCompatModeToString(freeformCameraCompatMode)
196                 + "}";
197     }
198 
199     /** Human readable version of the camera control state. */
200     @NonNull
cameraCompatControlStateToString( @ameraCompatControlState int cameraCompatControlState)201     public static String cameraCompatControlStateToString(
202             @CameraCompatControlState int cameraCompatControlState) {
203         return switch (cameraCompatControlState) {
204             case CAMERA_COMPAT_CONTROL_HIDDEN -> "hidden";
205             case CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED -> "treatment-suggested";
206             case CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED -> "treatment-applied";
207             case CAMERA_COMPAT_CONTROL_DISMISSED -> "dismissed";
208             default -> throw new AssertionError(
209                     "Unexpected camera compat control state: " + cameraCompatControlState);
210         };
211     }
212 
213     /** Human readable version of the freeform camera compat mode. */
214     @NonNull
freeformCameraCompatModeToString( @reeformCameraCompatMode int freeformCameraCompatMode)215     public static String freeformCameraCompatModeToString(
216             @FreeformCameraCompatMode int freeformCameraCompatMode) {
217         return switch (freeformCameraCompatMode) {
218             case CAMERA_COMPAT_FREEFORM_NONE -> "inactive";
219             case CAMERA_COMPAT_FREEFORM_PORTRAIT -> "portrait";
220             case CAMERA_COMPAT_FREEFORM_LANDSCAPE -> "landscape";
221             default -> throw new AssertionError(
222                     "Unexpected camera compat mode: " + freeformCameraCompatMode);
223         };
224     }
225 }
226