1 /*
2  * Copyright (C) 2021 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.window;
18 
19 import android.annotation.AnimRes;
20 import android.annotation.ColorInt;
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.TestApi;
25 import android.graphics.Color;
26 import android.graphics.Rect;
27 import android.os.Bundle;
28 import android.os.Parcel;
29 import android.os.Parcelable;
30 import android.os.RemoteCallback;
31 
32 import java.lang.annotation.Retention;
33 import java.lang.annotation.RetentionPolicy;
34 
35 /**
36  * Information to be sent to SysUI about a back event.
37  *
38  * @hide
39  */
40 @TestApi
41 public final class BackNavigationInfo implements Parcelable {
42 
43     /**
44      * The target of the back navigation is undefined.
45      */
46     public static final int TYPE_UNDEFINED = -1;
47 
48     /**
49      * Navigating back will close the currently visible dialog
50      */
51     public static final int TYPE_DIALOG_CLOSE = 0;
52 
53     /**
54      * Navigating back will bring the user back to the home screen
55      */
56     public static final int TYPE_RETURN_TO_HOME = 1;
57 
58     /**
59      * Navigating back will bring the user to the previous activity in the same Task
60      */
61     public static final int TYPE_CROSS_ACTIVITY = 2;
62 
63     /**
64      * Navigating back will bring the user to the previous activity in the previous Task
65      */
66     public static final int TYPE_CROSS_TASK = 3;
67 
68     /**
69      * A {@link OnBackInvokedCallback} is available and needs to be called.
70      * <p>
71      */
72     public static final int TYPE_CALLBACK = 4;
73 
74     /**
75      * Key to access the boolean value passed in {#mOnBackNavigationDone} result bundle
76      * that represents if back navigation has been triggered.
77      * @hide
78      */
79     public static final String KEY_NAVIGATION_FINISHED = "NavigationFinished";
80 
81     /**
82      * Key to access the boolean value passed in {#mOnBackNavigationDone} result bundle
83      * that represents if back gesture has been triggered.
84      * @hide
85      */
86     public static final String KEY_GESTURE_FINISHED = "GestureFinished";
87 
88 
89     /**
90      * Defines the type of back destinations a back even can lead to. This is used to define the
91      * type of animation that need to be run on SystemUI.
92      * @hide
93      */
94     @IntDef(prefix = "TYPE_", value = {
95             TYPE_UNDEFINED,
96             TYPE_DIALOG_CLOSE,
97             TYPE_RETURN_TO_HOME,
98             TYPE_CROSS_ACTIVITY,
99             TYPE_CROSS_TASK,
100             TYPE_CALLBACK
101     })
102     @Retention(RetentionPolicy.SOURCE)
103     public @interface BackTargetType {
104     }
105 
106     private final int mType;
107     @Nullable
108     private final RemoteCallback mOnBackNavigationDone;
109     @Nullable
110     private final IOnBackInvokedCallback mOnBackInvokedCallback;
111     private final boolean mPrepareRemoteAnimation;
112     private final boolean mAnimationCallback;
113     @Nullable
114     private final CustomAnimationInfo mCustomAnimationInfo;
115 
116     private final int mLetterboxColor;
117     @NonNull
118     private final Rect mTouchableRegion;
119 
120     private final boolean mAppProgressGenerationAllowed;
121 
122     /**
123      * Create a new {@link BackNavigationInfo} instance.
124      *
125      * @param type                  The {@link BackTargetType} of the destination (what will be
126      * @param onBackNavigationDone  The callback to be called once the client is done with the
127      *                              back preview.
128      * @param onBackInvokedCallback The back callback registered by the current top level window.
129      */
BackNavigationInfo(@ackTargetType int type, @Nullable RemoteCallback onBackNavigationDone, @Nullable IOnBackInvokedCallback onBackInvokedCallback, boolean isPrepareRemoteAnimation, boolean isAnimationCallback, @Nullable CustomAnimationInfo customAnimationInfo, int letterboxColor, @Nullable Rect touchableRegion, boolean appProgressGenerationAllowed)130     private BackNavigationInfo(@BackTargetType int type,
131             @Nullable RemoteCallback onBackNavigationDone,
132             @Nullable IOnBackInvokedCallback onBackInvokedCallback,
133             boolean isPrepareRemoteAnimation,
134             boolean isAnimationCallback,
135             @Nullable CustomAnimationInfo customAnimationInfo,
136             int letterboxColor,
137             @Nullable Rect touchableRegion,
138             boolean appProgressGenerationAllowed) {
139         mType = type;
140         mOnBackNavigationDone = onBackNavigationDone;
141         mOnBackInvokedCallback = onBackInvokedCallback;
142         mPrepareRemoteAnimation = isPrepareRemoteAnimation;
143         mAnimationCallback = isAnimationCallback;
144         mCustomAnimationInfo = customAnimationInfo;
145         mLetterboxColor = letterboxColor;
146         mTouchableRegion = new Rect(touchableRegion);
147         mAppProgressGenerationAllowed = appProgressGenerationAllowed;
148     }
149 
BackNavigationInfo(@onNull Parcel in)150     private BackNavigationInfo(@NonNull Parcel in) {
151         mType = in.readInt();
152         mOnBackNavigationDone = in.readTypedObject(RemoteCallback.CREATOR);
153         mOnBackInvokedCallback = IOnBackInvokedCallback.Stub.asInterface(in.readStrongBinder());
154         mPrepareRemoteAnimation = in.readBoolean();
155         mAnimationCallback = in.readBoolean();
156         mCustomAnimationInfo = in.readTypedObject(CustomAnimationInfo.CREATOR);
157         mLetterboxColor = in.readInt();
158         mTouchableRegion = in.readTypedObject(Rect.CREATOR);
159         mAppProgressGenerationAllowed = in.readBoolean();
160     }
161 
162     /** @hide */
163     @Override
writeToParcel(@onNull Parcel dest, int flags)164     public void writeToParcel(@NonNull Parcel dest, int flags) {
165         dest.writeInt(mType);
166         dest.writeTypedObject(mOnBackNavigationDone, flags);
167         dest.writeStrongInterface(mOnBackInvokedCallback);
168         dest.writeBoolean(mPrepareRemoteAnimation);
169         dest.writeBoolean(mAnimationCallback);
170         dest.writeTypedObject(mCustomAnimationInfo, flags);
171         dest.writeInt(mLetterboxColor);
172         dest.writeTypedObject(mTouchableRegion, flags);
173         dest.writeBoolean(mAppProgressGenerationAllowed);
174     }
175 
176     /**
177      * Returns the type of back navigation that is about to happen.
178      * @hide
179      * @see BackTargetType
180      */
getType()181     public @BackTargetType int getType() {
182         return mType;
183     }
184 
185     /**
186      * Returns the {@link OnBackInvokedCallback} of the top level window or null if
187      * the client didn't register a callback.
188      * <p>
189      * This is never null when {@link #getType} returns {@link #TYPE_CALLBACK}.
190      * @hide
191      * @see OnBackInvokedCallback
192      * @see OnBackInvokedDispatcher
193      */
194     @Nullable
getOnBackInvokedCallback()195     public IOnBackInvokedCallback getOnBackInvokedCallback() {
196         return mOnBackInvokedCallback;
197     }
198 
199     /**
200      * Return true if the core is preparing a back gesture animation.
201      * @hide
202      */
isPrepareRemoteAnimation()203     public boolean isPrepareRemoteAnimation() {
204         return mPrepareRemoteAnimation;
205     }
206 
207     /**
208      * Return true if the callback is {@link OnBackAnimationCallback}.
209      * @hide
210      */
isAnimationCallback()211     public boolean isAnimationCallback() {
212         return mAnimationCallback;
213     }
214 
215     /**
216      * @return Letterbox color
217      * @hide
218      */
getLetterboxColor()219     public int getLetterboxColor() {
220         return mLetterboxColor;
221     }
222 
223     /**
224      * @return The app window region where the client can handle touch event.
225      * @hide
226      */
227     @NonNull
getTouchableRegion()228     public Rect getTouchableRegion() {
229         return mTouchableRegion;
230     }
231 
232     /**
233      * @return The client side view is able to intercept back progress event.
234      * @hide
235      */
isAppProgressGenerationAllowed()236     public boolean isAppProgressGenerationAllowed() {
237         return mAppProgressGenerationAllowed;
238     }
239 
240     /**
241      * Callback to be called when the back preview is finished in order to notify the server that
242      * it can clean up the resources created for the animation.
243      * @hide
244      * @param triggerBack Boolean indicating if back navigation has been triggered.
245      */
onBackNavigationFinished(boolean triggerBack)246     public void onBackNavigationFinished(boolean triggerBack) {
247         if (mOnBackNavigationDone != null) {
248             Bundle result = new Bundle();
249             result.putBoolean(KEY_NAVIGATION_FINISHED, triggerBack);
250             mOnBackNavigationDone.sendResult(result);
251         }
252     }
253 
254     /**
255      * Callback to be called when the back gesture is finished in order to notify the server that
256      * it can ask app to start rendering.
257      * @hide
258      * @param triggerBack Boolean indicating if back gesture has been triggered.
259      */
onBackGestureFinished(boolean triggerBack)260     public void onBackGestureFinished(boolean triggerBack) {
261         if (mOnBackNavigationDone != null) {
262             Bundle result = new Bundle();
263             result.putBoolean(KEY_GESTURE_FINISHED, triggerBack);
264             mOnBackNavigationDone.sendResult(result);
265         }
266     }
267 
268     /**
269      * Get customize animation info.
270      * @hide
271      */
272     @Nullable
getCustomAnimationInfo()273     public CustomAnimationInfo getCustomAnimationInfo() {
274         return mCustomAnimationInfo;
275     }
276 
277     /** @hide */
278     @Override
describeContents()279     public int describeContents() {
280         return 0;
281     }
282 
283     @NonNull
284     public static final Creator<BackNavigationInfo> CREATOR = new Creator<BackNavigationInfo>() {
285         @Override
286         public BackNavigationInfo createFromParcel(Parcel in) {
287             return new BackNavigationInfo(in);
288         }
289 
290         @Override
291         public BackNavigationInfo[] newArray(int size) {
292             return new BackNavigationInfo[size];
293         }
294     };
295 
296     @Override
toString()297     public String toString() {
298         return "BackNavigationInfo{"
299                 + "mType=" + typeToString(mType) + " (" + mType + ")"
300                 + ", mOnBackNavigationDone=" + mOnBackNavigationDone
301                 + ", mOnBackInvokedCallback=" + mOnBackInvokedCallback
302                 + ", mPrepareRemoteAnimation=" + mPrepareRemoteAnimation
303                 + ", mAnimationCallback=" + mAnimationCallback
304                 + ", mCustomizeAnimationInfo=" + mCustomAnimationInfo
305                 + '}';
306     }
307 
308     /**
309      * Translates the {@link BackNavigationInfo} integer type to its String representation
310      */
311     @NonNull
typeToString(@ackTargetType int type)312     public static String typeToString(@BackTargetType int type) {
313         switch (type) {
314             case TYPE_UNDEFINED:
315                 return "TYPE_UNDEFINED";
316             case TYPE_DIALOG_CLOSE:
317                 return "TYPE_DIALOG_CLOSE";
318             case TYPE_RETURN_TO_HOME:
319                 return "TYPE_RETURN_TO_HOME";
320             case TYPE_CROSS_ACTIVITY:
321                 return "TYPE_CROSS_ACTIVITY";
322             case TYPE_CROSS_TASK:
323                 return "TYPE_CROSS_TASK";
324             case TYPE_CALLBACK:
325                 return "TYPE_CALLBACK";
326         }
327         return String.valueOf(type);
328     }
329 
330     /**
331      * Information for customize back animation.
332      * @hide
333      */
334     public static final class CustomAnimationInfo implements Parcelable {
335         private final String mPackageName;
336         private int mWindowAnimations;
337         @AnimRes private int mCustomExitAnim;
338         @AnimRes private int mCustomEnterAnim;
339         @ColorInt private int mCustomBackground;
340 
341         /**
342          * The package name of the windowAnimations.
343          */
344         @NonNull
getPackageName()345         public String getPackageName() {
346             return mPackageName;
347         }
348 
349         /**
350          * The resource Id of window animations.
351          */
getWindowAnimations()352         public int getWindowAnimations() {
353             return mWindowAnimations;
354         }
355 
356         /**
357          * The exit animation resource Id of customize activity transition.
358          */
getCustomExitAnim()359         public int getCustomExitAnim() {
360             return mCustomExitAnim;
361         }
362 
363         /**
364          * The entering animation resource Id of customize activity transition.
365          */
getCustomEnterAnim()366         public int getCustomEnterAnim() {
367             return mCustomEnterAnim;
368         }
369 
370         /**
371          * The background color of customize activity transition.
372          */
getCustomBackground()373         public int getCustomBackground() {
374             return mCustomBackground;
375         }
376 
CustomAnimationInfo(@onNull String packageName)377         public CustomAnimationInfo(@NonNull String packageName) {
378             this.mPackageName = packageName;
379         }
380 
381         @Override
describeContents()382         public int describeContents() {
383             return 0;
384         }
385 
386         @Override
writeToParcel(@onNull Parcel dest, int flags)387         public void writeToParcel(@NonNull Parcel dest, int flags) {
388             dest.writeString8(mPackageName);
389             dest.writeInt(mWindowAnimations);
390             dest.writeInt(mCustomEnterAnim);
391             dest.writeInt(mCustomExitAnim);
392             dest.writeInt(mCustomBackground);
393         }
394 
CustomAnimationInfo(@onNull Parcel in)395         private CustomAnimationInfo(@NonNull Parcel in) {
396             mPackageName = in.readString8();
397             mWindowAnimations = in.readInt();
398             mCustomEnterAnim = in.readInt();
399             mCustomExitAnim = in.readInt();
400             mCustomBackground = in.readInt();
401         }
402 
403         @Override
toString()404         public String toString() {
405             return "CustomAnimationInfo, package name= " + mPackageName;
406         }
407 
408         @NonNull
409         public static final Creator<CustomAnimationInfo> CREATOR = new Creator<>() {
410             @Override
411             public CustomAnimationInfo createFromParcel(Parcel in) {
412                 return new CustomAnimationInfo(in);
413             }
414 
415             @Override
416             public CustomAnimationInfo[] newArray(int size) {
417                 return new CustomAnimationInfo[size];
418             }
419         };
420     }
421     /**
422      * @hide
423      */
424     @SuppressWarnings("UnusedReturnValue") // Builder pattern
425     public static class Builder {
426         private int mType = TYPE_UNDEFINED;
427         @Nullable
428         private RemoteCallback mOnBackNavigationDone = null;
429         @Nullable
430         private IOnBackInvokedCallback mOnBackInvokedCallback = null;
431         private boolean mPrepareRemoteAnimation;
432         private CustomAnimationInfo mCustomAnimationInfo;
433         private boolean mAnimationCallback = false;
434 
435         private int mLetterboxColor = Color.TRANSPARENT;
436         private Rect mTouchableRegion;
437         private boolean mAppProgressGenerationAllowed;
438 
439         /**
440          * @see BackNavigationInfo#getType()
441          */
setType(@ackTargetType int type)442         public Builder setType(@BackTargetType int type) {
443             mType = type;
444             return this;
445         }
446 
447         /**
448          * @see BackNavigationInfo#onBackNavigationFinished(boolean)
449          */
setOnBackNavigationDone(@ullable RemoteCallback onBackNavigationDone)450         public Builder setOnBackNavigationDone(@Nullable RemoteCallback onBackNavigationDone) {
451             mOnBackNavigationDone = onBackNavigationDone;
452             return this;
453         }
454 
455         /**
456          * @see BackNavigationInfo#getOnBackInvokedCallback
457          */
setOnBackInvokedCallback( @ullable IOnBackInvokedCallback onBackInvokedCallback)458         public Builder setOnBackInvokedCallback(
459                 @Nullable IOnBackInvokedCallback onBackInvokedCallback) {
460             mOnBackInvokedCallback = onBackInvokedCallback;
461             return this;
462         }
463 
464         /**
465          * @param prepareRemoteAnimation Whether core prepare animation for shell.
466          */
setPrepareRemoteAnimation(boolean prepareRemoteAnimation)467         public Builder setPrepareRemoteAnimation(boolean prepareRemoteAnimation) {
468             mPrepareRemoteAnimation = prepareRemoteAnimation;
469             return this;
470         }
471 
472         /**
473          * Set windowAnimations for customize animation.
474          */
setWindowAnimations(String packageName, int windowAnimations)475         public Builder setWindowAnimations(String packageName, int windowAnimations) {
476             if (mCustomAnimationInfo == null) {
477                 mCustomAnimationInfo = new CustomAnimationInfo(packageName);
478             }
479             mCustomAnimationInfo.mWindowAnimations = windowAnimations;
480             return this;
481         }
482 
483         /**
484          * Set resources ids for customize activity animation.
485          */
setCustomAnimation(String packageName, @AnimRes int enterResId, @AnimRes int exitResId, @ColorInt int backgroundColor)486         public Builder setCustomAnimation(String packageName, @AnimRes int enterResId,
487                 @AnimRes int exitResId, @ColorInt int backgroundColor) {
488             if (mCustomAnimationInfo == null) {
489                 mCustomAnimationInfo = new CustomAnimationInfo(packageName);
490             }
491             mCustomAnimationInfo.mCustomExitAnim = exitResId;
492             mCustomAnimationInfo.mCustomEnterAnim = enterResId;
493             mCustomAnimationInfo.mCustomBackground = backgroundColor;
494             return this;
495         }
496 
497         /**
498          * @param isAnimationCallback whether the callback is {@link OnBackAnimationCallback}
499          */
setAnimationCallback(boolean isAnimationCallback)500         public Builder setAnimationCallback(boolean isAnimationCallback) {
501             mAnimationCallback = isAnimationCallback;
502             return this;
503         }
504 
505         /**
506          * @param color Non-transparent if there contain letterbox color.
507          */
setLetterboxColor(int color)508         public Builder setLetterboxColor(int color) {
509             mLetterboxColor = color;
510             return this;
511         }
512 
513         /**
514          * @param rect Non-empty for frame of current focus window.
515          */
setTouchableRegion(Rect rect)516         public Builder setTouchableRegion(Rect rect) {
517             mTouchableRegion = new Rect(rect);
518             return this;
519         }
520 
521         /**
522          * @param allowed Whether client side view able to intercept back progress event.
523          */
setAppProgressAllowed(boolean allowed)524         public Builder setAppProgressAllowed(boolean allowed) {
525             mAppProgressGenerationAllowed = allowed;
526             return this;
527         }
528 
529         /**
530          * Builds and returns an instance of {@link BackNavigationInfo}
531          */
build()532         public BackNavigationInfo build() {
533             return new BackNavigationInfo(mType, mOnBackNavigationDone,
534                     mOnBackInvokedCallback,
535                     mPrepareRemoteAnimation,
536                     mAnimationCallback,
537                     mCustomAnimationInfo,
538                     mLetterboxColor,
539                     mTouchableRegion,
540                     mAppProgressGenerationAllowed);
541         }
542     }
543 }
544