1 /*
2  * Copyright (C) 2014 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 com.android.systemui.recents.views;
18 
19 import android.content.Context;
20 import android.view.View;
21 
22 import com.android.systemui.Interpolators;
23 import com.android.systemui.R;
24 import com.android.systemui.recents.LegacyRecentsImpl;
25 import com.android.systemui.recents.RecentsActivity;
26 import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
27 import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
28 import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
29 import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent;
30 import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent;
31 import com.android.systemui.recents.events.ui.dragndrop.DragEndCancelledEvent;
32 import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
33 import com.android.systemui.recents.utilities.AnimationProps;
34 
35 /** Manages the scrims for the various system bars. */
36 public class SystemBarScrimViews {
37 
38     private static final int DEFAULT_ANIMATION_DURATION = 150;
39 
40     private Context mContext;
41 
42     private View mNavBarScrimView;
43 
44     private boolean mHasNavBarScrim;
45     private boolean mShouldAnimateNavBarScrim;
46     private boolean mHasTransposedNavBar;
47     private boolean mHasDockedTasks;
48     private int mNavBarScrimEnterDuration;
49 
SystemBarScrimViews(RecentsActivity activity)50     public SystemBarScrimViews(RecentsActivity activity) {
51         mContext = activity;
52         mNavBarScrimView = activity.findViewById(R.id.nav_bar_scrim);
53         mNavBarScrimView.forceHasOverlappingRendering(false);
54         mNavBarScrimEnterDuration = activity.getResources().getInteger(
55                 R.integer.recents_nav_bar_scrim_enter_duration);
56         mHasNavBarScrim = LegacyRecentsImpl.getSystemServices().hasTransposedNavigationBar();
57         mHasDockedTasks = LegacyRecentsImpl.getSystemServices().hasDockedTask();
58     }
59 
60     /**
61      * Updates the nav bar scrim.
62      */
updateNavBarScrim(boolean animateNavBarScrim, boolean hasStackTasks, AnimationProps animation)63     public void updateNavBarScrim(boolean animateNavBarScrim, boolean hasStackTasks,
64             AnimationProps animation) {
65         prepareEnterRecentsAnimation(isNavBarScrimRequired(hasStackTasks), animateNavBarScrim);
66         if (animateNavBarScrim && animation != null) {
67             animateNavBarScrimVisibility(true, animation);
68         }
69     }
70 
71     /**
72      * Prepares the scrim views for animating when entering Recents. This will be called before
73      * the first draw, unless we are updating the scrim on configuration change.
74      */
prepareEnterRecentsAnimation(boolean hasNavBarScrim, boolean animateNavBarScrim)75     private void prepareEnterRecentsAnimation(boolean hasNavBarScrim, boolean animateNavBarScrim) {
76         mHasNavBarScrim = hasNavBarScrim;
77         mShouldAnimateNavBarScrim = animateNavBarScrim;
78 
79         mNavBarScrimView.setVisibility(mHasNavBarScrim && !mShouldAnimateNavBarScrim ?
80                 View.VISIBLE : View.INVISIBLE);
81     }
82 
83     /**
84      * Animates the nav bar scrim visibility.
85      */
animateNavBarScrimVisibility(boolean visible, AnimationProps animation)86     private void animateNavBarScrimVisibility(boolean visible, AnimationProps animation) {
87         int toY = 0;
88         if (visible) {
89             mNavBarScrimView.setVisibility(View.VISIBLE);
90             mNavBarScrimView.setTranslationY(mNavBarScrimView.getMeasuredHeight());
91         } else {
92             toY = mNavBarScrimView.getMeasuredHeight();
93         }
94         if (animation != AnimationProps.IMMEDIATE) {
95             mNavBarScrimView.animate()
96                     .translationY(toY)
97                     .setDuration(animation.getDuration(AnimationProps.BOUNDS))
98                     .setInterpolator(animation.getInterpolator(AnimationProps.BOUNDS))
99                     .start();
100         } else {
101             mNavBarScrimView.setTranslationY(toY);
102         }
103     }
104 
105     /**
106      * @return Whether to show the nav bar scrim.
107      */
isNavBarScrimRequired(boolean hasStackTasks)108     private boolean isNavBarScrimRequired(boolean hasStackTasks) {
109         return hasStackTasks && !mHasTransposedNavBar && !mHasDockedTasks;
110     }
111 
112     /**** EventBus events ****/
113 
114     /**
115      * Starts animating the scrim views when entering Recents.
116      */
onBusEvent(EnterRecentsWindowAnimationCompletedEvent event)117     public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) {
118         if (mHasNavBarScrim) {
119             AnimationProps animation = mShouldAnimateNavBarScrim
120                     ? new AnimationProps()
121                             .setDuration(AnimationProps.BOUNDS, mNavBarScrimEnterDuration)
122                             .setInterpolator(AnimationProps.BOUNDS, Interpolators.DECELERATE_QUINT)
123                     : AnimationProps.IMMEDIATE;
124             animateNavBarScrimVisibility(true, animation);
125         }
126     }
127 
128     /**
129      * Starts animating the scrim views when leaving Recents (either via launching a task, or
130      * going home).
131      */
onBusEvent(DismissRecentsToHomeAnimationStarted event)132     public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
133         if (mHasNavBarScrim) {
134             AnimationProps animation = createBoundsAnimation(
135                     TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION);
136             animateNavBarScrimVisibility(false, animation);
137         }
138     }
139 
onBusEvent(DismissAllTaskViewsEvent event)140     public final void onBusEvent(DismissAllTaskViewsEvent event) {
141         if (mHasNavBarScrim) {
142             AnimationProps animation = createBoundsAnimation(
143                     TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION);
144             animateNavBarScrimVisibility(false, animation);
145         }
146     }
147 
onBusEvent(ConfigurationChangedEvent event)148     public final void onBusEvent(ConfigurationChangedEvent event) {
149         if (event.fromDeviceOrientationChange) {
150             mHasNavBarScrim = LegacyRecentsImpl.getSystemServices().hasTransposedNavigationBar();
151         }
152         animateScrimToCurrentNavBarState(event.hasStackTasks);
153     }
154 
onBusEvent(MultiWindowStateChangedEvent event)155     public final void onBusEvent(MultiWindowStateChangedEvent event) {
156         mHasDockedTasks = event.inMultiWindow;
157         animateScrimToCurrentNavBarState(event.stack.getTaskCount() > 0);
158     }
159 
onBusEvent(final DragEndEvent event)160     public final void onBusEvent(final DragEndEvent event) {
161         // Hide the nav bar scrims once we drop to a dock region
162         if (event.dropTarget instanceof DockState) {
163             animateScrimToCurrentNavBarState(false /* hasStackTasks */);
164         }
165     }
166 
onBusEvent(final DragEndCancelledEvent event)167     public final void onBusEvent(final DragEndCancelledEvent event) {
168         // Restore the scrims to the normal state
169         animateScrimToCurrentNavBarState(event.stack.getTaskCount() > 0);
170     }
171 
172     /**
173      * Animates the scrim to match the state of the current nav bar.
174      */
animateScrimToCurrentNavBarState(boolean hasStackTasks)175     private void animateScrimToCurrentNavBarState(boolean hasStackTasks) {
176         boolean hasNavBarScrim = isNavBarScrimRequired(hasStackTasks);
177         if (mHasNavBarScrim != hasNavBarScrim) {
178             AnimationProps animation = hasNavBarScrim
179                     ? createBoundsAnimation(DEFAULT_ANIMATION_DURATION)
180                     : AnimationProps.IMMEDIATE;
181             animateNavBarScrimVisibility(hasNavBarScrim, animation);
182         }
183         mHasNavBarScrim = hasNavBarScrim;
184     }
185 
186     /**
187      * @return a default animation to aniamte the bounds of the scrim.
188      */
createBoundsAnimation(int duration)189     private AnimationProps createBoundsAnimation(int duration) {
190         return new AnimationProps()
191                 .setDuration(AnimationProps.BOUNDS, duration)
192                 .setInterpolator(AnimationProps.BOUNDS, Interpolators.FAST_OUT_SLOW_IN);
193     }
194 }
195