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;
24 
25 import android.annotation.Nullable;
26 import android.graphics.Insets;
27 import android.graphics.Point;
28 import android.os.Parcel;
29 import android.os.Parcelable;
30 import android.util.proto.ProtoOutputStream;
31 import android.view.InsetsState.InternalInsetsType;
32 
33 import java.io.PrintWriter;
34 import java.util.function.Consumer;
35 
36 /**
37  * Represents a parcelable object to allow controlling a single {@link InsetsSource}.
38  * @hide
39  */
40 public class InsetsSourceControl implements Parcelable {
41 
42     private final @InternalInsetsType int mType;
43     private final @Nullable SurfaceControl mLeash;
44     private final Point mSurfacePosition;
45 
46     // This is used while playing an insets animation regardless of the relative frame. This would
47     // be the insets received by the bounds of its source window.
48     private Insets mInsetsHint;
49 
50     private boolean mSkipAnimationOnce;
51     private int mParcelableFlags;
52 
InsetsSourceControl(@nternalInsetsType int type, @Nullable SurfaceControl leash, Point surfacePosition, Insets insetsHint)53     public InsetsSourceControl(@InternalInsetsType int type, @Nullable SurfaceControl leash,
54             Point surfacePosition, Insets insetsHint) {
55         mType = type;
56         mLeash = leash;
57         mSurfacePosition = surfacePosition;
58         mInsetsHint = insetsHint;
59     }
60 
InsetsSourceControl(InsetsSourceControl other)61     public InsetsSourceControl(InsetsSourceControl other) {
62         mType = other.mType;
63         if (other.mLeash != null) {
64             mLeash = new SurfaceControl(other.mLeash, "InsetsSourceControl");
65         } else {
66             mLeash = null;
67         }
68         mSurfacePosition = new Point(other.mSurfacePosition);
69         mInsetsHint = other.mInsetsHint;
70         mSkipAnimationOnce = other.getAndClearSkipAnimationOnce();
71     }
72 
InsetsSourceControl(Parcel in)73     public InsetsSourceControl(Parcel in) {
74         mType = in.readInt();
75         mLeash = in.readTypedObject(SurfaceControl.CREATOR);
76         mSurfacePosition = in.readTypedObject(Point.CREATOR);
77         mInsetsHint = in.readTypedObject(Insets.CREATOR);
78         mSkipAnimationOnce = in.readBoolean();
79     }
80 
getType()81     public int getType() {
82         return mType;
83     }
84 
85     /**
86      * Gets the leash for controlling insets source. If the system is controlling the insets source,
87      * for example, transient bars, the client will receive fake controls without leash in it.
88      *
89      * @return the leash.
90      */
getLeash()91     public @Nullable SurfaceControl getLeash() {
92         return mLeash;
93     }
94 
setSurfacePosition(int left, int top)95     public boolean setSurfacePosition(int left, int top) {
96         if (mSurfacePosition.equals(left, top)) {
97             return false;
98         }
99         mSurfacePosition.set(left, top);
100         return true;
101     }
102 
getSurfacePosition()103     public Point getSurfacePosition() {
104         return mSurfacePosition;
105     }
106 
setInsetsHint(Insets insets)107     public void setInsetsHint(Insets insets) {
108         mInsetsHint = insets;
109     }
110 
setInsetsHint(int left, int top, int right, int bottom)111     public void setInsetsHint(int left, int top, int right, int bottom) {
112         mInsetsHint = Insets.of(left, top, right, bottom);
113     }
114 
getInsetsHint()115     public Insets getInsetsHint() {
116         return mInsetsHint;
117     }
118 
setSkipAnimationOnce(boolean skipAnimation)119     public void setSkipAnimationOnce(boolean skipAnimation) {
120         mSkipAnimationOnce = skipAnimation;
121     }
122 
123     /**
124      * Get the state whether the current control needs to skip animation or not.
125      *
126      * Note that this is a one-time check that the state is only valid and can be called when
127      * {@link InsetsController#applyAnimation} to check if the current control can skip animation
128      * at this time, and then will clear the state value.
129      */
getAndClearSkipAnimationOnce()130     public boolean getAndClearSkipAnimationOnce() {
131         final boolean result = mSkipAnimationOnce;
132         mSkipAnimationOnce = false;
133         return result;
134     }
135 
setParcelableFlags(int parcelableFlags)136     public void setParcelableFlags(int parcelableFlags) {
137         mParcelableFlags = parcelableFlags;
138     }
139 
140     @Override
describeContents()141     public int describeContents() {
142         return 0;
143     }
144 
145     @Override
writeToParcel(Parcel dest, int flags)146     public void writeToParcel(Parcel dest, int flags) {
147         dest.writeInt(mType);
148         dest.writeTypedObject(mLeash, mParcelableFlags);
149         dest.writeTypedObject(mSurfacePosition, mParcelableFlags);
150         dest.writeTypedObject(mInsetsHint, mParcelableFlags);
151         dest.writeBoolean(mSkipAnimationOnce);
152     }
153 
release(Consumer<SurfaceControl> surfaceReleaseConsumer)154     public void release(Consumer<SurfaceControl> surfaceReleaseConsumer) {
155         if (mLeash != null) {
156             surfaceReleaseConsumer.accept(mLeash);
157         }
158     }
159 
160     @Override
equals(@ullable Object o)161     public boolean equals(@Nullable Object o) {
162         if (this == o) {
163             return true;
164         }
165         if (o == null || getClass() != o.getClass()) {
166             return false;
167         }
168         final InsetsSourceControl that = (InsetsSourceControl) o;
169         final SurfaceControl thatLeash = that.mLeash;
170         return mType == that.mType
171                 && ((mLeash == thatLeash)
172                         || (mLeash != null && thatLeash != null && mLeash.isSameSurface(thatLeash)))
173                 && mSurfacePosition.equals(that.mSurfacePosition)
174                 && mInsetsHint.equals(that.mInsetsHint)
175                 && mSkipAnimationOnce == that.mSkipAnimationOnce;
176     }
177 
178     @Override
hashCode()179     public int hashCode() {
180         int result = mType;
181         result = 31 * result + (mLeash != null ? mLeash.hashCode() : 0);
182         result = 31 * result + mSurfacePosition.hashCode();
183         result = 31 * result + mInsetsHint.hashCode();
184         result = 31 * result + (mSkipAnimationOnce ? 1 : 0);
185         return result;
186     }
187 
188     @Override
toString()189     public String toString() {
190         return "InsetsSourceControl: {"
191                 + "type=" + InsetsState.typeToString(mType)
192                 + ", mSurfacePosition=" + mSurfacePosition
193                 + ", mInsetsHint=" + mInsetsHint
194                 + "}";
195     }
196 
dump(String prefix, PrintWriter pw)197     public void dump(String prefix, PrintWriter pw) {
198         pw.print(prefix);
199         pw.print("InsetsSourceControl type="); pw.print(InsetsState.typeToString(mType));
200         pw.print(" mLeash="); pw.print(mLeash);
201         pw.print(" mSurfacePosition="); pw.print(mSurfacePosition);
202         pw.print(" mInsetsHint="); pw.print(mInsetsHint);
203         pw.print(" mSkipAnimationOnce="); pw.print(mSkipAnimationOnce);
204         pw.println();
205     }
206 
207     public static final @android.annotation.NonNull Creator<InsetsSourceControl> CREATOR
208             = new Creator<InsetsSourceControl>() {
209         public InsetsSourceControl createFromParcel(Parcel in) {
210             return new InsetsSourceControl(in);
211         }
212 
213         public InsetsSourceControl[] newArray(int size) {
214             return new InsetsSourceControl[size];
215         }
216     };
217 
218     /**
219      * Export the state of {@link InsetsSourceControl} into a protocol buffer output stream.
220      *
221      * @param proto   Stream to write the state to
222      * @param fieldId FieldId of InsetsSource as defined in the parent message
223      */
dumpDebug(ProtoOutputStream proto, long fieldId)224     public void dumpDebug(ProtoOutputStream proto, long fieldId) {
225         final long token = proto.start(fieldId);
226         proto.write(TYPE, InsetsState.typeToString(mType));
227 
228         final long surfaceToken = proto.start(POSITION);
229         proto.write(X, mSurfacePosition.x);
230         proto.write(Y, mSurfacePosition.y);
231         proto.end(surfaceToken);
232 
233         if (mLeash != null) {
234             mLeash.dumpDebug(proto, LEASH);
235         }
236         proto.end(token);
237     }
238 }
239