Home | History | Annotate | Download | only in recent
      1 /*
      2  * Copyright (C) 2011 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.recent;
     18 
     19 import android.animation.Animator;
     20 import android.animation.AnimatorSet;
     21 import android.animation.AnimatorSet.Builder;
     22 import android.animation.ObjectAnimator;
     23 import android.content.res.Resources;
     24 import android.graphics.drawable.ColorDrawable;
     25 import android.graphics.drawable.Drawable;
     26 import android.util.Slog;
     27 import android.view.View;
     28 import android.view.ViewRootImpl;
     29 
     30 import com.android.systemui.R;
     31 
     32 /* package */ class Choreographer implements Animator.AnimatorListener {
     33     // should group this into a multi-property animation
     34     private static final int OPEN_DURATION = 136;
     35     private static final int CLOSE_DURATION = 230;
     36     private static final int SCRIM_DURATION = 400;
     37     private static final String TAG = RecentsPanelView.TAG;
     38     private static final boolean DEBUG = RecentsPanelView.DEBUG;
     39 
     40     boolean mVisible;
     41     int mPanelHeight;
     42     RecentsPanelView mRootView;
     43     View mScrimView;
     44     View mContentView;
     45     View mNoRecentAppsView;
     46     AnimatorSet mContentAnim;
     47     Animator.AnimatorListener mListener;
     48 
     49     // the panel will start to appear this many px from the end
     50     final int HYPERSPACE_OFFRAMP = 200;
     51 
     52     public Choreographer(RecentsPanelView root, View scrim, View content,
     53             View noRecentApps, Animator.AnimatorListener listener) {
     54         mRootView = root;
     55         mScrimView = scrim;
     56         mContentView = content;
     57         mListener = listener;
     58         mNoRecentAppsView = noRecentApps;
     59     }
     60 
     61     void createAnimation(boolean appearing) {
     62         float start, end;
     63 
     64         // 0: on-screen
     65         // height: off-screen
     66         float y = mContentView.getTranslationY();
     67         if (appearing) {
     68             // we want to go from near-the-top to the top, unless we're half-open in the right
     69             // general vicinity
     70             start = (y < HYPERSPACE_OFFRAMP) ? y : HYPERSPACE_OFFRAMP;
     71             end = 0;
     72         } else {
     73             start = y;
     74             end = y;
     75         }
     76 
     77         Animator posAnim = ObjectAnimator.ofFloat(mContentView, "translationY",
     78                 start, end);
     79         posAnim.setInterpolator(appearing
     80                 ? new android.view.animation.DecelerateInterpolator(2.5f)
     81                 : new android.view.animation.AccelerateInterpolator(2.5f));
     82         posAnim.setDuration(appearing ? OPEN_DURATION : CLOSE_DURATION);
     83 
     84         Animator fadeAnim = ObjectAnimator.ofFloat(mContentView, "alpha",
     85                 mContentView.getAlpha(), appearing ? 1.0f : 0.0f);
     86         fadeAnim.setInterpolator(appearing
     87                 ? new android.view.animation.AccelerateInterpolator(1.0f)
     88                 : new android.view.animation.AccelerateInterpolator(2.5f));
     89         fadeAnim.setDuration(appearing ? OPEN_DURATION : CLOSE_DURATION);
     90 
     91         Animator noRecentAppsFadeAnim = null;
     92         if (mNoRecentAppsView != null &&  // doesn't exist on large devices
     93                 mNoRecentAppsView.getVisibility() == View.VISIBLE) {
     94             noRecentAppsFadeAnim = ObjectAnimator.ofFloat(mNoRecentAppsView, "alpha",
     95                     mContentView.getAlpha(), appearing ? 1.0f : 0.0f);
     96             noRecentAppsFadeAnim.setInterpolator(appearing
     97                     ? new android.view.animation.AccelerateInterpolator(1.0f)
     98                     : new android.view.animation.DecelerateInterpolator(1.0f));
     99             noRecentAppsFadeAnim.setDuration(appearing ? OPEN_DURATION : CLOSE_DURATION);
    100         }
    101 
    102         mContentAnim = new AnimatorSet();
    103         final Builder builder = mContentAnim.play(fadeAnim).with(posAnim);
    104 
    105         if (noRecentAppsFadeAnim != null) {
    106             builder.with(noRecentAppsFadeAnim);
    107         }
    108 
    109         if (appearing) {
    110             Drawable background = mScrimView.getBackground();
    111             if (background != null) {
    112                 Animator bgAnim = ObjectAnimator.ofInt(background,
    113                     "alpha", appearing ? 0 : 255, appearing ? 255 : 0);
    114                 bgAnim.setDuration(appearing ? SCRIM_DURATION : CLOSE_DURATION);
    115                 builder.with(bgAnim);
    116             }
    117         } else {
    118             final Resources res = mRootView.getResources();
    119             boolean isTablet = res.getBoolean(R.bool.config_recents_interface_for_tablets);
    120             if (!isTablet) {
    121                 View recentsTransitionBackground =
    122                         mRootView.findViewById(R.id.recents_transition_background);
    123                 recentsTransitionBackground.setVisibility(View.VISIBLE);
    124                 Drawable bgDrawable = new ColorDrawable(0xFF000000);
    125                 recentsTransitionBackground.setBackground(bgDrawable);
    126                 Animator bgAnim = ObjectAnimator.ofInt(bgDrawable, "alpha", 0, 255);
    127                 bgAnim.setDuration(CLOSE_DURATION);
    128                 bgAnim.setInterpolator(new android.view.animation.AccelerateInterpolator(1f));
    129                 builder.with(bgAnim);
    130             }
    131         }
    132         mContentAnim.addListener(this);
    133         if (mListener != null) {
    134             mContentAnim.addListener(mListener);
    135         }
    136     }
    137 
    138     void startAnimation(boolean appearing) {
    139         if (DEBUG) Slog.d(TAG, "startAnimation(appearing=" + appearing + ")");
    140 
    141         createAnimation(appearing);
    142 
    143         // isHardwareAccelerated() checks if we're attached to a window and if that
    144         // window is HW accelerated-- we were sometimes not attached to a window
    145         // and buildLayer was throwing an IllegalStateException
    146         if (mContentView.isHardwareAccelerated()) {
    147             mContentView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
    148             mContentView.buildLayer();
    149         }
    150         mContentAnim.start();
    151 
    152         mVisible = appearing;
    153     }
    154 
    155     void jumpTo(boolean appearing) {
    156         mContentView.setTranslationY(appearing ? 0 : mPanelHeight);
    157         if (mScrimView.getBackground() != null) {
    158             mScrimView.getBackground().setAlpha(appearing ? 255 : 0);
    159         }
    160         View recentsTransitionBackground =
    161                 mRootView.findViewById(R.id.recents_transition_background);
    162         recentsTransitionBackground.setVisibility(View.INVISIBLE);
    163         mRootView.requestLayout();
    164     }
    165 
    166     public void setPanelHeight(int h) {
    167         if (DEBUG) Slog.d(TAG, "panelHeight=" + h);
    168         mPanelHeight = h;
    169     }
    170 
    171     public void onAnimationCancel(Animator animation) {
    172         if (DEBUG) Slog.d(TAG, "onAnimationCancel");
    173         // force this to zero so we close the window
    174         mVisible = false;
    175     }
    176 
    177     public void onAnimationEnd(Animator animation) {
    178         if (DEBUG) Slog.d(TAG, "onAnimationEnd");
    179         if (!mVisible) {
    180             mRootView.hideWindow();
    181         }
    182         mContentView.setLayerType(View.LAYER_TYPE_NONE, null);
    183         mContentView.setAlpha(1f);
    184         mContentAnim = null;
    185     }
    186 
    187     public void onAnimationRepeat(Animator animation) {
    188     }
    189 
    190     public void onAnimationStart(Animator animation) {
    191     }
    192 }
    193