Home | History | Annotate | Download | only in old
      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.tv.settings.dialog.old;
     18 
     19 import android.animation.Animator;
     20 import android.animation.AnimatorListenerAdapter;
     21 import android.animation.ObjectAnimator;
     22 import android.app.Activity;
     23 import android.content.Intent;
     24 import android.graphics.drawable.ColorDrawable;
     25 import android.support.v4.view.ViewCompat;
     26 import android.view.View;
     27 import android.view.ViewGroup;
     28 import android.view.ViewTreeObserver;
     29 import android.view.animation.DecelerateInterpolator;
     30 import android.view.animation.Interpolator;
     31 import android.widget.ImageView;
     32 import android.widget.TextView;
     33 
     34 import com.android.tv.settings.R;
     35 import com.android.tv.settings.widget.FrameLayoutWithShadows;
     36 
     37 /**
     38  * This class exists to make extending both v4 DialogFragments and regular DialogFragments easy
     39  */
     40 public class BaseDialogFragment {
     41 
     42     private static final int ANIMATE_IN_DURATION = 250;
     43     private static final int ANIMATE_DELAY = 550;
     44     private static final int SLIDE_IN_DISTANCE = 120;
     45 
     46     public static final String TAG_CONTENT = "content";
     47     public static final String TAG_ACTION = "action";
     48 
     49     public int mContentAreaId = R.id.content_fragment;
     50     public int mActionAreaId = R.id.action_fragment;
     51 
     52     private FrameLayoutWithShadows mShadowLayer;
     53     public boolean mFirstOnStart = true;
     54     private boolean mIntroAnimationInProgress = false;
     55 
     56     private final LiteFragment mFragment;
     57 
     58     // Related to activity entry transition
     59     private ColorDrawable mBgDrawable = new ColorDrawable();
     60 
     61     public BaseDialogFragment(LiteFragment fragment) {
     62         mFragment = fragment;
     63     }
     64 
     65     public void onActionClicked(Activity activity, Action action) {
     66         if (activity instanceof ActionAdapter.Listener) {
     67             ((ActionAdapter.Listener) activity).onActionClicked(action);
     68         } else {
     69             Intent intent = action.getIntent();
     70             if (intent != null) {
     71                 activity.startActivity(intent);
     72                 activity.finish();
     73             }
     74         }
     75     }
     76 
     77     public void disableEntryAnimation() {
     78         mFirstOnStart = false;
     79     }
     80 
     81     /**
     82      * This method sets the layout property of this class. <br/>
     83      * Activities extending {@link DialogFragment} should call this method
     84      * before calling {@link #onCreate(Bundle)} if they want to have a
     85      * custom view.
     86      *
     87      * @param contentAreaId id of the content area
     88      * @param actionAreaId id of the action area
     89      */
     90     public void setLayoutProperties(int contentAreaId, int actionAreaId) {
     91         mContentAreaId = contentAreaId;
     92         mActionAreaId = actionAreaId;
     93     }
     94 
     95     public void performEntryTransition(final Activity activity, final ViewGroup contentView,
     96             final ImageView icon, final TextView title,
     97             final TextView description, final TextView breadcrumb) {
     98         // Pull out the root layout of the dialog and set the background drawable, to be
     99         // faded in during the transition.
    100         final ViewGroup twoPane = (ViewGroup) contentView.getChildAt(0);
    101         twoPane.setVisibility(View.INVISIBLE);
    102 
    103         // If the appropriate data is embedded in the intent and there is an icon specified
    104         // in the content fragment, we animate the icon from its initial position to the final
    105         // position. Otherwise, we perform a simpler transition in which the ActionFragment
    106         // slides in and the ContentFragment text fields slide in.
    107         mIntroAnimationInProgress = true;
    108 
    109         // Fade out the old activity, and hard cut the new activity.
    110         activity.overridePendingTransition(R.anim.hard_cut_in, R.anim.fade_out);
    111 
    112         int bgColor = mFragment.getActivity().getColor(R.color.dialog_activity_background);
    113         mBgDrawable.setColor(bgColor);
    114         mBgDrawable.setAlpha(0);
    115         twoPane.setBackground(mBgDrawable);
    116 
    117         // If we're animating the icon, we create a new ImageView in which to place the embedded
    118         // bitmap. We place it in the root layout to match its location in the previous activity.
    119         mShadowLayer = (FrameLayoutWithShadows) twoPane.findViewById(R.id.shadow_layout);
    120 
    121         // We need to defer the remainder of the animation preparation until the first
    122         // layout has occurred, as we don't yet know the final location of the icon.
    123         twoPane.getViewTreeObserver().addOnGlobalLayoutListener(
    124                 new ViewTreeObserver.OnGlobalLayoutListener() {
    125             @Override
    126             public void onGlobalLayout() {
    127                 twoPane.getViewTreeObserver().removeOnGlobalLayoutListener(this);
    128                 // if we buildLayer() at this time,  the texture is actually not created
    129                 // delay a little so we can make sure all hardware layer is created before
    130                 // animation, in that way we can avoid the jittering of start animation
    131                 twoPane.postOnAnimationDelayed(mEntryAnimationRunnable, ANIMATE_DELAY);
    132             }
    133 
    134             final Runnable mEntryAnimationRunnable = new Runnable() {
    135                 @Override
    136                 public void run() {
    137                     if (!mFragment.isAdded()) {
    138                         // We have been detached before this could run, so just bail
    139                         return;
    140                     }
    141 
    142                     twoPane.setVisibility(View.VISIBLE);
    143                     final int secondaryDelay = SLIDE_IN_DISTANCE;
    144 
    145                     // Fade in the activity background protection
    146                     ObjectAnimator oa = ObjectAnimator.ofInt(mBgDrawable, "alpha", 255);
    147                     oa.setDuration(ANIMATE_IN_DURATION);
    148                     oa.setStartDelay(secondaryDelay);
    149                     oa.setInterpolator(new DecelerateInterpolator(1.0f));
    150                     oa.start();
    151 
    152                     View actionFragmentView = activity.findViewById(mActionAreaId);
    153                     boolean isRtl = ViewCompat.getLayoutDirection(contentView) ==
    154                             ViewCompat.LAYOUT_DIRECTION_RTL;
    155                     int startDist = isRtl ? SLIDE_IN_DISTANCE : -SLIDE_IN_DISTANCE;
    156                     int endDist = isRtl ? -actionFragmentView.getMeasuredWidth() :
    157                             actionFragmentView.getMeasuredWidth();
    158 
    159                     // Fade in and slide in the ContentFragment TextViews from the start.
    160                     prepareAndAnimateView(title, 0, startDist,
    161                             secondaryDelay, ANIMATE_IN_DURATION,
    162                             new DecelerateInterpolator(1.0f),
    163                             false);
    164                     prepareAndAnimateView(breadcrumb, 0, startDist,
    165                             secondaryDelay, ANIMATE_IN_DURATION,
    166                             new DecelerateInterpolator(1.0f),
    167                             false);
    168                     prepareAndAnimateView(description, 0,
    169                             startDist,
    170                             secondaryDelay, ANIMATE_IN_DURATION,
    171                             new DecelerateInterpolator(1.0f),
    172                             false);
    173 
    174                     // Fade in and slide in the ActionFragment from the end.
    175                     prepareAndAnimateView(actionFragmentView, 0,
    176                             endDist, secondaryDelay,
    177                             ANIMATE_IN_DURATION, new DecelerateInterpolator(1.0f),
    178                             false);
    179 
    180                     if (icon != null) {
    181                         prepareAndAnimateView(icon, 0, startDist,
    182                                 secondaryDelay, ANIMATE_IN_DURATION,
    183                                 new DecelerateInterpolator(1.0f), true /* is the icon */);
    184                         if (mShadowLayer != null) {
    185                             mShadowLayer.setShadowsAlpha(0f);
    186                         }
    187                     }
    188                 }
    189             };
    190         });
    191     }
    192 
    193     /**
    194      * Animates a view.
    195      *
    196      * @param v              view to animate
    197      * @param initAlpha      initial alpha
    198      * @param initTransX     initial translation in the X
    199      * @param delay          delay in ms
    200      * @param duration       duration in ms
    201      * @param interpolator   interpolator to be used, can be null
    202      * @param isIcon         if {@code true}, this is the main icon being moved
    203      */
    204     public void prepareAndAnimateView(final View v, float initAlpha, float initTransX, int delay,
    205             int duration, Interpolator interpolator, final boolean isIcon) {
    206         if (v != null && v.getWindowToken() != null) {
    207             v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
    208             v.buildLayer();
    209             v.setAlpha(initAlpha);
    210             v.setTranslationX(initTransX);
    211             v.animate().alpha(1f).translationX(0).setDuration(duration).setStartDelay(delay);
    212             if (interpolator != null) {
    213                 v.animate().setInterpolator(interpolator);
    214             }
    215             v.animate().setListener(new AnimatorListenerAdapter() {
    216                 @Override
    217                 public void onAnimationEnd(Animator animation) {
    218                     v.setLayerType(View.LAYER_TYPE_NONE, null);
    219                     if (isIcon) {
    220                         if (mShadowLayer != null) {
    221                             mShadowLayer.setShadowsAlpha(1f);
    222                         }
    223                         onIntroAnimationFinished();
    224                     }
    225                 }
    226             });
    227             v.animate().start();
    228         }
    229     }
    230 
    231     /**
    232      * Called when intro animation is finished.
    233      * <p>
    234      * If a subclass is going to alter the view, should wait until this is called.
    235      */
    236     public void onIntroAnimationFinished() {
    237         mIntroAnimationInProgress = false;
    238     }
    239 
    240     public boolean isIntroAnimationInProgress() {
    241         return mIntroAnimationInProgress;
    242     }
    243 
    244     public ColorDrawable getBackgroundDrawable() {
    245         return mBgDrawable;
    246     }
    247 
    248     public void setBackgroundDrawable(ColorDrawable drawable) {
    249         mBgDrawable = drawable;
    250     }
    251 
    252 }
    253