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