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 /** Returns the adjusted rotation if available. Otherwise the original rotation is returned. */ 155 @Surface.Rotation getRotation(@urface.Rotation int realRotation)156 public int getRotation(@Surface.Rotation int realRotation) { 157 final FixedRotationAdjustments rotationAdjustments = mFixedRotationAdjustments; 158 return rotationAdjustments != null ? rotationAdjustments.mRotation : realRotation; 159 } 160 161 @Override hashCode()162 public int hashCode() { 163 int hash = 17; 164 hash = hash * 31 + Objects.hashCode(mCompatInfo); 165 hash = hash * 31 + Objects.hashCode(mConfiguration); 166 hash = hash * 31 + Objects.hashCode(mFixedRotationAdjustments); 167 return hash; 168 } 169 170 @Override equals(Object o)171 public boolean equals(Object o) { 172 if (!(o instanceof DisplayAdjustments)) { 173 return false; 174 } 175 DisplayAdjustments daj = (DisplayAdjustments)o; 176 return Objects.equals(daj.mCompatInfo, mCompatInfo) 177 && Objects.equals(daj.mConfiguration, mConfiguration) 178 && Objects.equals(daj.mFixedRotationAdjustments, mFixedRotationAdjustments); 179 } 180 181 /** 182 * An application can be launched in different rotation than the real display. This class 183 * provides the information to adjust the values returned by {@link Display}. 184 * @hide 185 */ 186 public static class FixedRotationAdjustments implements Parcelable { 187 /** The application-based rotation. */ 188 @Surface.Rotation 189 final int mRotation; 190 191 /** 192 * The rotated {@link DisplayInfo#appWidth}. The value cannot be simply swapped according 193 * to rotation because it minus the region of screen decorations. 194 */ 195 final int mAppWidth; 196 197 /** The rotated {@link DisplayInfo#appHeight}. */ 198 final int mAppHeight; 199 200 /** Non-null if the device has cutout. */ 201 @Nullable 202 final DisplayCutout mRotatedDisplayCutout; 203 FixedRotationAdjustments(@urface.Rotation int rotation, int appWidth, int appHeight, DisplayCutout cutout)204 public FixedRotationAdjustments(@Surface.Rotation int rotation, int appWidth, int appHeight, 205 DisplayCutout cutout) { 206 mRotation = rotation; 207 mAppWidth = appWidth; 208 mAppHeight = appHeight; 209 mRotatedDisplayCutout = cutout; 210 } 211 212 @Override hashCode()213 public int hashCode() { 214 int hash = 17; 215 hash = hash * 31 + mRotation; 216 hash = hash * 31 + mAppWidth; 217 hash = hash * 31 + mAppHeight; 218 hash = hash * 31 + Objects.hashCode(mRotatedDisplayCutout); 219 return hash; 220 } 221 222 @Override equals(Object o)223 public boolean equals(Object o) { 224 if (!(o instanceof FixedRotationAdjustments)) { 225 return false; 226 } 227 final FixedRotationAdjustments other = (FixedRotationAdjustments) o; 228 return mRotation == other.mRotation 229 && mAppWidth == other.mAppWidth && mAppHeight == other.mAppHeight 230 && Objects.equals(mRotatedDisplayCutout, other.mRotatedDisplayCutout); 231 } 232 233 @Override toString()234 public String toString() { 235 return "FixedRotationAdjustments{rotation=" + Surface.rotationToString(mRotation) 236 + " appWidth=" + mAppWidth + " appHeight=" + mAppHeight 237 + " cutout=" + mRotatedDisplayCutout + "}"; 238 } 239 240 @Override describeContents()241 public int describeContents() { 242 return 0; 243 } 244 245 @Override writeToParcel(Parcel dest, int flags)246 public void writeToParcel(Parcel dest, int flags) { 247 dest.writeInt(mRotation); 248 dest.writeInt(mAppWidth); 249 dest.writeInt(mAppHeight); 250 dest.writeTypedObject( 251 new DisplayCutout.ParcelableWrapper(mRotatedDisplayCutout), flags); 252 } 253 FixedRotationAdjustments(Parcel in)254 private FixedRotationAdjustments(Parcel in) { 255 mRotation = in.readInt(); 256 mAppWidth = in.readInt(); 257 mAppHeight = in.readInt(); 258 final DisplayCutout.ParcelableWrapper cutoutWrapper = 259 in.readTypedObject(DisplayCutout.ParcelableWrapper.CREATOR); 260 mRotatedDisplayCutout = cutoutWrapper != null ? cutoutWrapper.get() : null; 261 } 262 263 public static final Creator<FixedRotationAdjustments> CREATOR = 264 new Creator<FixedRotationAdjustments>() { 265 public FixedRotationAdjustments createFromParcel(Parcel in) { 266 return new FixedRotationAdjustments(in); 267 } 268 269 public FixedRotationAdjustments[] newArray(int size) { 270 return new FixedRotationAdjustments[size]; 271 } 272 }; 273 } 274 } 275