1 /* 2 * Copyright (C) 2018 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 static android.graphics.PointProto.X; 20 import static android.graphics.PointProto.Y; 21 import static android.view.InsetsSourceControlProto.LEASH; 22 import static android.view.InsetsSourceControlProto.POSITION; 23 import static android.view.InsetsSourceControlProto.TYPE_NUMBER; 24 25 import android.annotation.NonNull; 26 import android.annotation.Nullable; 27 import android.graphics.Insets; 28 import android.graphics.Point; 29 import android.os.Parcel; 30 import android.os.Parcelable; 31 import android.util.proto.ProtoOutputStream; 32 import android.view.WindowInsets.Type.InsetsType; 33 34 import java.io.PrintWriter; 35 import java.util.Arrays; 36 import java.util.Objects; 37 import java.util.function.Consumer; 38 39 /** 40 * Represents a parcelable object to allow controlling a single {@link InsetsSource}. 41 * @hide 42 */ 43 public class InsetsSourceControl implements Parcelable { 44 45 private final int mId; 46 private final @InsetsType int mType; 47 private final @Nullable SurfaceControl mLeash; 48 private final boolean mInitiallyVisible; 49 private final Point mSurfacePosition; 50 51 // This is used while playing an insets animation regardless of the relative frame. This would 52 // be the insets received by the bounds of its source window. 53 private Insets mInsetsHint; 54 55 private boolean mSkipAnimationOnce; 56 private int mParcelableFlags; 57 InsetsSourceControl(int id, @InsetsType int type, @Nullable SurfaceControl leash, boolean initiallyVisible, Point surfacePosition, Insets insetsHint)58 public InsetsSourceControl(int id, @InsetsType int type, @Nullable SurfaceControl leash, 59 boolean initiallyVisible, Point surfacePosition, Insets insetsHint) { 60 mId = id; 61 mType = type; 62 mLeash = leash; 63 mInitiallyVisible = initiallyVisible; 64 mSurfacePosition = surfacePosition; 65 mInsetsHint = insetsHint; 66 } 67 InsetsSourceControl(InsetsSourceControl other)68 public InsetsSourceControl(InsetsSourceControl other) { 69 mId = other.mId; 70 mType = other.mType; 71 if (other.mLeash != null) { 72 mLeash = new SurfaceControl(other.mLeash, "InsetsSourceControl"); 73 } else { 74 mLeash = null; 75 } 76 mInitiallyVisible = other.mInitiallyVisible; 77 mSurfacePosition = new Point(other.mSurfacePosition); 78 mInsetsHint = other.mInsetsHint; 79 mSkipAnimationOnce = other.getAndClearSkipAnimationOnce(); 80 } 81 InsetsSourceControl(Parcel in)82 public InsetsSourceControl(Parcel in) { 83 mId = in.readInt(); 84 mType = in.readInt(); 85 mLeash = in.readTypedObject(SurfaceControl.CREATOR); 86 mInitiallyVisible = in.readBoolean(); 87 mSurfacePosition = in.readTypedObject(Point.CREATOR); 88 mInsetsHint = in.readTypedObject(Insets.CREATOR); 89 mSkipAnimationOnce = in.readBoolean(); 90 } 91 getId()92 public int getId() { 93 return mId; 94 } 95 getType()96 public int getType() { 97 return mType; 98 } 99 100 /** 101 * Gets the leash for controlling insets source. If the system is controlling the insets source, 102 * for example, transient bars, the client will receive fake controls without leash in it. 103 * 104 * @return the leash. 105 */ getLeash()106 public @Nullable SurfaceControl getLeash() { 107 return mLeash; 108 } 109 isInitiallyVisible()110 public boolean isInitiallyVisible() { 111 return mInitiallyVisible; 112 } 113 setSurfacePosition(int left, int top)114 public boolean setSurfacePosition(int left, int top) { 115 if (mSurfacePosition.equals(left, top)) { 116 return false; 117 } 118 mSurfacePosition.set(left, top); 119 return true; 120 } 121 getSurfacePosition()122 public Point getSurfacePosition() { 123 return mSurfacePosition; 124 } 125 setInsetsHint(Insets insets)126 public void setInsetsHint(Insets insets) { 127 mInsetsHint = insets; 128 } 129 setInsetsHint(int left, int top, int right, int bottom)130 public void setInsetsHint(int left, int top, int right, int bottom) { 131 mInsetsHint = Insets.of(left, top, right, bottom); 132 } 133 getInsetsHint()134 public Insets getInsetsHint() { 135 return mInsetsHint; 136 } 137 setSkipAnimationOnce(boolean skipAnimation)138 public void setSkipAnimationOnce(boolean skipAnimation) { 139 mSkipAnimationOnce = skipAnimation; 140 } 141 142 /** 143 * Get the state whether the current control needs to skip animation or not. 144 * 145 * Note that this is a one-time check that the state is only valid and can be called when 146 * {@link InsetsController#applyAnimation} to check if the current control can skip animation 147 * at this time, and then will clear the state value. 148 */ getAndClearSkipAnimationOnce()149 public boolean getAndClearSkipAnimationOnce() { 150 final boolean result = mSkipAnimationOnce; 151 mSkipAnimationOnce = false; 152 return result; 153 } 154 setParcelableFlags(int parcelableFlags)155 public void setParcelableFlags(int parcelableFlags) { 156 mParcelableFlags = parcelableFlags; 157 } 158 159 @Override describeContents()160 public int describeContents() { 161 return 0; 162 } 163 164 @Override writeToParcel(Parcel dest, int flags)165 public void writeToParcel(Parcel dest, int flags) { 166 dest.writeInt(mId); 167 dest.writeInt(mType); 168 dest.writeTypedObject(mLeash, mParcelableFlags); 169 dest.writeBoolean(mInitiallyVisible); 170 dest.writeTypedObject(mSurfacePosition, mParcelableFlags); 171 dest.writeTypedObject(mInsetsHint, mParcelableFlags); 172 dest.writeBoolean(mSkipAnimationOnce); 173 } 174 release(Consumer<SurfaceControl> surfaceReleaseConsumer)175 public void release(Consumer<SurfaceControl> surfaceReleaseConsumer) { 176 if (mLeash != null) { 177 surfaceReleaseConsumer.accept(mLeash); 178 } 179 } 180 181 @Override equals(@ullable Object o)182 public boolean equals(@Nullable Object o) { 183 if (this == o) { 184 return true; 185 } 186 if (o == null || getClass() != o.getClass()) { 187 return false; 188 } 189 final InsetsSourceControl that = (InsetsSourceControl) o; 190 final SurfaceControl thatLeash = that.mLeash; 191 return mId == that.mId 192 && mType == that.mType 193 && ((mLeash == thatLeash) 194 || (mLeash != null && thatLeash != null && mLeash.isSameSurface(thatLeash))) 195 && mInitiallyVisible == that.mInitiallyVisible 196 && mSurfacePosition.equals(that.mSurfacePosition) 197 && mInsetsHint.equals(that.mInsetsHint) 198 && mSkipAnimationOnce == that.mSkipAnimationOnce; 199 } 200 201 @Override hashCode()202 public int hashCode() { 203 return Objects.hash(mId, mType, mLeash, mInitiallyVisible, mSurfacePosition, mInsetsHint, 204 mSkipAnimationOnce); 205 } 206 207 @Override toString()208 public String toString() { 209 return "InsetsSourceControl: {" + Integer.toHexString(mId) 210 + " mType=" + WindowInsets.Type.toString(mType) 211 + (mInitiallyVisible ? " initiallyVisible" : "") 212 + " mSurfacePosition=" + mSurfacePosition 213 + " mInsetsHint=" + mInsetsHint 214 + (mSkipAnimationOnce ? " skipAnimationOnce" : "") 215 + "}"; 216 } 217 dump(String prefix, PrintWriter pw)218 public void dump(String prefix, PrintWriter pw) { 219 pw.print(prefix); 220 pw.print("InsetsSourceControl mId="); pw.print(Integer.toHexString(mId)); 221 pw.print(" mType="); pw.print(WindowInsets.Type.toString(mType)); 222 pw.print(" mLeash="); pw.print(mLeash); 223 pw.print(" mInitiallyVisible="); pw.print(mInitiallyVisible); 224 pw.print(" mSurfacePosition="); pw.print(mSurfacePosition); 225 pw.print(" mInsetsHint="); pw.print(mInsetsHint); 226 pw.print(" mSkipAnimationOnce="); pw.print(mSkipAnimationOnce); 227 pw.println(); 228 } 229 230 public static final @NonNull Creator<InsetsSourceControl> CREATOR = new Creator<>() { 231 public InsetsSourceControl createFromParcel(Parcel in) { 232 return new InsetsSourceControl(in); 233 } 234 235 public InsetsSourceControl[] newArray(int size) { 236 return new InsetsSourceControl[size]; 237 } 238 }; 239 240 /** 241 * Export the state of {@link InsetsSourceControl} into a protocol buffer output stream. 242 * 243 * @param proto Stream to write the state to 244 * @param fieldId FieldId of InsetsSource as defined in the parent message 245 */ dumpDebug(ProtoOutputStream proto, long fieldId)246 public void dumpDebug(ProtoOutputStream proto, long fieldId) { 247 final long token = proto.start(fieldId); 248 final long surfaceToken = proto.start(POSITION); 249 proto.write(X, mSurfacePosition.x); 250 proto.write(Y, mSurfacePosition.y); 251 proto.end(surfaceToken); 252 253 if (mLeash != null) { 254 mLeash.dumpDebug(proto, LEASH); 255 } 256 257 proto.write(TYPE_NUMBER, mType); 258 proto.end(token); 259 } 260 261 /** 262 * Used to obtain the array from the argument of a binder call. In this way, the length of the 263 * array can be dynamic. 264 */ 265 public static class Array implements Parcelable { 266 267 private @Nullable InsetsSourceControl[] mControls; 268 Array()269 public Array() { 270 } 271 272 /** 273 * @param copyControls whether or not to make a copy of the each {@link InsetsSourceControl} 274 */ Array(@onNull Array other, boolean copyControls)275 public Array(@NonNull Array other, boolean copyControls) { 276 setTo(other, copyControls); 277 } 278 Array(@onNull Parcel in)279 public Array(@NonNull Parcel in) { 280 readFromParcel(in); 281 } 282 283 /** Updates the current Array to the given Array. */ setTo(@onNull Array other, boolean copyControls)284 public void setTo(@NonNull Array other, boolean copyControls) { 285 set(other.mControls, copyControls); 286 } 287 288 /** Updates the current controls to the given controls. */ set(@ullable InsetsSourceControl[] controls, boolean copyControls)289 public void set(@Nullable InsetsSourceControl[] controls, boolean copyControls) { 290 if (controls == null || !copyControls) { 291 mControls = controls; 292 return; 293 } 294 // Make a copy of the array. 295 mControls = new InsetsSourceControl[controls.length]; 296 for (int i = mControls.length - 1; i >= 0; i--) { 297 if (controls[i] != null) { 298 mControls[i] = new InsetsSourceControl(controls[i]); 299 } 300 } 301 } 302 303 /** Gets the controls. */ get()304 public @Nullable InsetsSourceControl[] get() { 305 return mControls; 306 } 307 308 /** Cleanup {@link SurfaceControl} stored in controls to prevent leak. */ release()309 public void release() { 310 if (mControls == null) { 311 return; 312 } 313 for (InsetsSourceControl control : mControls) { 314 if (control != null) { 315 control.release(SurfaceControl::release); 316 } 317 } 318 } 319 320 /** Sets the given flags to all controls. */ setParcelableFlags(int parcelableFlags)321 public void setParcelableFlags(int parcelableFlags) { 322 if (mControls == null) { 323 return; 324 } 325 for (InsetsSourceControl control : mControls) { 326 if (control != null) { 327 control.setParcelableFlags(parcelableFlags); 328 } 329 } 330 } 331 332 @Override describeContents()333 public int describeContents() { 334 return 0; 335 } 336 readFromParcel(Parcel in)337 public void readFromParcel(Parcel in) { 338 mControls = in.createTypedArray(InsetsSourceControl.CREATOR); 339 } 340 341 @Override writeToParcel(Parcel out, int flags)342 public void writeToParcel(Parcel out, int flags) { 343 out.writeTypedArray(mControls, flags); 344 } 345 346 public static final @NonNull Creator<Array> CREATOR = new Creator<>() { 347 public Array createFromParcel(Parcel in) { 348 return new Array(in); 349 } 350 351 public Array[] newArray(int size) { 352 return new Array[size]; 353 } 354 }; 355 356 @Override equals(@ullable Object o)357 public boolean equals(@Nullable Object o) { 358 if (this == o) { 359 return true; 360 } 361 if (o == null || getClass() != o.getClass()) { 362 return false; 363 } 364 final InsetsSourceControl.Array other = (InsetsSourceControl.Array) o; 365 return Arrays.equals(mControls, other.mControls); 366 } 367 368 @Override hashCode()369 public int hashCode() { 370 return Arrays.hashCode(mControls); 371 } 372 } 373 } 374