1 /* 2 * Copyright (C) 2011 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.view; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.compat.annotation.UnsupportedAppUsage; 22 import android.content.res.CompatibilityInfo; 23 import android.content.res.Configuration; 24 import android.graphics.Point; 25 import android.os.Parcel; 26 import android.os.Parcelable; 27 import android.util.DisplayMetrics; 28 29 import java.util.Objects; 30 31 /** @hide */ 32 public class DisplayAdjustments { 33 public static final DisplayAdjustments DEFAULT_DISPLAY_ADJUSTMENTS = new DisplayAdjustments(); 34 35 private volatile CompatibilityInfo mCompatInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO; 36 private final Configuration mConfiguration = new Configuration(Configuration.EMPTY); 37 private FixedRotationAdjustments mFixedRotationAdjustments; 38 39 @UnsupportedAppUsage DisplayAdjustments()40 public DisplayAdjustments() { 41 } 42 DisplayAdjustments(@ullable Configuration configuration)43 public DisplayAdjustments(@Nullable Configuration configuration) { 44 if (configuration != null) { 45 mConfiguration.setTo(configuration); 46 } 47 } 48 DisplayAdjustments(@onNull DisplayAdjustments daj)49 public DisplayAdjustments(@NonNull DisplayAdjustments daj) { 50 setCompatibilityInfo(daj.mCompatInfo); 51 mConfiguration.setTo(daj.getConfiguration()); 52 mFixedRotationAdjustments = daj.mFixedRotationAdjustments; 53 } 54 55 @UnsupportedAppUsage setCompatibilityInfo(@ullable CompatibilityInfo compatInfo)56 public void setCompatibilityInfo(@Nullable CompatibilityInfo compatInfo) { 57 if (this == DEFAULT_DISPLAY_ADJUSTMENTS) { 58 throw new IllegalArgumentException( 59 "setCompatbilityInfo: Cannot modify DEFAULT_DISPLAY_ADJUSTMENTS"); 60 } 61 if (compatInfo != null && (compatInfo.isScalingRequired() 62 || !compatInfo.supportsScreen())) { 63 mCompatInfo = compatInfo; 64 } else { 65 mCompatInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO; 66 } 67 } 68 getCompatibilityInfo()69 public CompatibilityInfo getCompatibilityInfo() { 70 return mCompatInfo; 71 } 72 73 /** 74 * Updates the configuration for the DisplayAdjustments with new configuration. 75 * Default to EMPTY configuration if new configuration is {@code null} 76 * @param configuration new configuration 77 * @throws IllegalArgumentException if trying to modify DEFAULT_DISPLAY_ADJUSTMENTS 78 */ setConfiguration(@ullable Configuration configuration)79 public void setConfiguration(@Nullable Configuration configuration) { 80 if (this == DEFAULT_DISPLAY_ADJUSTMENTS) { 81 throw new IllegalArgumentException( 82 "setConfiguration: Cannot modify DEFAULT_DISPLAY_ADJUSTMENTS"); 83 } 84 mConfiguration.setTo(configuration != null ? configuration : Configuration.EMPTY); 85 } 86 87 @UnsupportedAppUsage 88 @NonNull getConfiguration()89 public Configuration getConfiguration() { 90 return mConfiguration; 91 } 92 setFixedRotationAdjustments(FixedRotationAdjustments fixedRotationAdjustments)93 public void setFixedRotationAdjustments(FixedRotationAdjustments fixedRotationAdjustments) { 94 mFixedRotationAdjustments = fixedRotationAdjustments; 95 } 96 getFixedRotationAdjustments()97 public FixedRotationAdjustments getFixedRotationAdjustments() { 98 return mFixedRotationAdjustments; 99 } 100 101 /** Returns {@code false} if the width and height of display should swap. */ noFlip(@urface.Rotation int realRotation)102 private boolean noFlip(@Surface.Rotation int realRotation) { 103 final FixedRotationAdjustments rotationAdjustments = mFixedRotationAdjustments; 104 if (rotationAdjustments == null) { 105 return true; 106 } 107 // Check if the delta is rotated by 90 degrees. 108 return (realRotation - rotationAdjustments.mRotation + 4) % 2 == 0; 109 } 110 111 /** Adjusts the given size if possible. */ adjustSize(@onNull Point size, @Surface.Rotation int realRotation)112 public void adjustSize(@NonNull Point size, @Surface.Rotation int realRotation) { 113 if (noFlip(realRotation)) { 114 return; 115 } 116 final int w = size.x; 117 size.x = size.y; 118 size.y = w; 119 } 120 121 /** Adjusts the given metrics if possible. */ adjustMetrics(@onNull DisplayMetrics metrics, @Surface.Rotation int realRotation)122 public void adjustMetrics(@NonNull DisplayMetrics metrics, @Surface.Rotation int realRotation) { 123 if (noFlip(realRotation)) { 124 return; 125 } 126 int w = metrics.widthPixels; 127 metrics.widthPixels = metrics.heightPixels; 128 metrics.heightPixels = w; 129 130 w = metrics.noncompatWidthPixels; 131 metrics.noncompatWidthPixels = metrics.noncompatHeightPixels; 132 metrics.noncompatHeightPixels = w; 133 } 134 135 /** Adjusts global display metrics that is available to applications. */ adjustGlobalAppMetrics(@onNull DisplayMetrics metrics)136 public void adjustGlobalAppMetrics(@NonNull DisplayMetrics metrics) { 137 final FixedRotationAdjustments rotationAdjustments = mFixedRotationAdjustments; 138 if (rotationAdjustments == null) { 139 return; 140 } 141 metrics.noncompatWidthPixels = metrics.widthPixels = rotationAdjustments.mAppWidth; 142 metrics.noncompatHeightPixels = metrics.heightPixels = rotationAdjustments.mAppHeight; 143 } 144 145 /** Returns the adjusted cutout if available. Otherwise the original cutout is returned. */ 146 @Nullable getDisplayCutout(@ullable DisplayCutout realCutout)147 public DisplayCutout getDisplayCutout(@Nullable DisplayCutout realCutout) { 148 final FixedRotationAdjustments rotationAdjustments = mFixedRotationAdjustments; 149 return rotationAdjustments != null && rotationAdjustments.mRotatedDisplayCutout != null 150 ? rotationAdjustments.mRotatedDisplayCutout 151 : realCutout; 152 } 153 154 /** 155 * Returns the adjusted {@link RoundedCorners} if available. Otherwise the original 156 * {@link RoundedCorners} is returned. 157 */ 158 @Nullable adjustRoundedCorner(@ullable RoundedCorners realRoundedCorners, @Surface.Rotation int realRotation, int displayWidth, int displayHeight)159 public RoundedCorners adjustRoundedCorner(@Nullable RoundedCorners realRoundedCorners, 160 @Surface.Rotation int realRotation, int displayWidth, int displayHeight) { 161 final FixedRotationAdjustments rotationAdjustments = mFixedRotationAdjustments; 162 if (realRoundedCorners == null || rotationAdjustments == null 163 || rotationAdjustments.mRotation == realRotation) { 164 return realRoundedCorners; 165 } 166 167 return realRoundedCorners.rotate( 168 rotationAdjustments.mRotation, displayWidth, displayHeight); 169 } 170 171 /** Returns the adjusted rotation if available. Otherwise the original rotation is returned. */ 172 @Surface.Rotation getRotation(@urface.Rotation int realRotation)173 public int getRotation(@Surface.Rotation int realRotation) { 174 final FixedRotationAdjustments rotationAdjustments = mFixedRotationAdjustments; 175 return rotationAdjustments != null ? rotationAdjustments.mRotation : realRotation; 176 } 177 178 @Override hashCode()179 public int hashCode() { 180 int hash = 17; 181 hash = hash * 31 + Objects.hashCode(mCompatInfo); 182 hash = hash * 31 + Objects.hashCode(mConfiguration); 183 hash = hash * 31 + Objects.hashCode(mFixedRotationAdjustments); 184 return hash; 185 } 186 187 @Override equals(@ullable Object o)188 public boolean equals(@Nullable Object o) { 189 if (!(o instanceof DisplayAdjustments)) { 190 return false; 191 } 192 DisplayAdjustments daj = (DisplayAdjustments)o; 193 return Objects.equals(daj.mCompatInfo, mCompatInfo) 194 && Objects.equals(daj.mConfiguration, mConfiguration) 195 && Objects.equals(daj.mFixedRotationAdjustments, mFixedRotationAdjustments); 196 } 197 198 /** 199 * An application can be launched in different rotation than the real display. This class 200 * provides the information to adjust the values returned by {@link Display}. 201 * @hide 202 */ 203 public static class FixedRotationAdjustments implements Parcelable { 204 /** The application-based rotation. */ 205 @Surface.Rotation 206 final int mRotation; 207 208 /** 209 * The rotated {@link DisplayInfo#appWidth}. The value cannot be simply swapped according 210 * to rotation because it minus the region of screen decorations. 211 */ 212 final int mAppWidth; 213 214 /** The rotated {@link DisplayInfo#appHeight}. */ 215 final int mAppHeight; 216 217 /** Non-null if the device has cutout. */ 218 @Nullable 219 final DisplayCutout mRotatedDisplayCutout; 220 FixedRotationAdjustments(@urface.Rotation int rotation, int appWidth, int appHeight, DisplayCutout cutout)221 public FixedRotationAdjustments(@Surface.Rotation int rotation, int appWidth, int appHeight, 222 DisplayCutout cutout) { 223 mRotation = rotation; 224 mAppWidth = appWidth; 225 mAppHeight = appHeight; 226 mRotatedDisplayCutout = cutout; 227 } 228 229 @Override hashCode()230 public int hashCode() { 231 int hash = 17; 232 hash = hash * 31 + mRotation; 233 hash = hash * 31 + mAppWidth; 234 hash = hash * 31 + mAppHeight; 235 hash = hash * 31 + Objects.hashCode(mRotatedDisplayCutout); 236 return hash; 237 } 238 239 @Override equals(@ullable Object o)240 public boolean equals(@Nullable Object o) { 241 if (!(o instanceof FixedRotationAdjustments)) { 242 return false; 243 } 244 final FixedRotationAdjustments other = (FixedRotationAdjustments) o; 245 return mRotation == other.mRotation 246 && mAppWidth == other.mAppWidth && mAppHeight == other.mAppHeight 247 && Objects.equals(mRotatedDisplayCutout, other.mRotatedDisplayCutout); 248 } 249 250 @Override toString()251 public String toString() { 252 return "FixedRotationAdjustments{rotation=" + Surface.rotationToString(mRotation) 253 + " appWidth=" + mAppWidth + " appHeight=" + mAppHeight 254 + " cutout=" + mRotatedDisplayCutout + "}"; 255 } 256 257 @Override describeContents()258 public int describeContents() { 259 return 0; 260 } 261 262 @Override writeToParcel(Parcel dest, int flags)263 public void writeToParcel(Parcel dest, int flags) { 264 dest.writeInt(mRotation); 265 dest.writeInt(mAppWidth); 266 dest.writeInt(mAppHeight); 267 dest.writeTypedObject( 268 new DisplayCutout.ParcelableWrapper(mRotatedDisplayCutout), flags); 269 } 270 FixedRotationAdjustments(Parcel in)271 private FixedRotationAdjustments(Parcel in) { 272 mRotation = in.readInt(); 273 mAppWidth = in.readInt(); 274 mAppHeight = in.readInt(); 275 final DisplayCutout.ParcelableWrapper cutoutWrapper = 276 in.readTypedObject(DisplayCutout.ParcelableWrapper.CREATOR); 277 mRotatedDisplayCutout = cutoutWrapper != null ? cutoutWrapper.get() : null; 278 } 279 280 public static final Creator<FixedRotationAdjustments> CREATOR = 281 new Creator<FixedRotationAdjustments>() { 282 public FixedRotationAdjustments createFromParcel(Parcel in) { 283 return new FixedRotationAdjustments(in); 284 } 285 286 public FixedRotationAdjustments[] newArray(int size) { 287 return new FixedRotationAdjustments[size]; 288 } 289 }; 290 } 291 } 292