1 /*
2  * Copyright (C) 2015 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.ui;
18 
19 import android.animation.TimeInterpolator;
20 import android.app.Dialog;
21 import android.content.Context;
22 import android.os.Handler;
23 import android.util.AttributeSet;
24 import android.util.Log;
25 import android.view.View;
26 import android.view.ViewTreeObserver;
27 import android.view.animation.AnimationUtils;
28 import android.widget.FrameLayout;
29 
30 import com.android.tv.MainActivity;
31 import com.android.tv.R;
32 import com.android.tv.dialog.FullscreenDialogFragment;
33 
34 public class FullscreenDialogView extends FrameLayout
35         implements FullscreenDialogFragment.DialogView {
36     private static final String TAG = "FullscreenDialogView";
37     private static final boolean DEBUG = false;
38 
39     private static final int FADE_IN_DURATION_MS = 400;
40     private static final int FADE_OUT_DURATION_MS = 250;
41     private static final int TRANSITION_INTERVAL_MS = 300;
42 
43     private MainActivity mActivity;
44     private Dialog mDialog;
45     private boolean mSkipEnterAlphaAnimation;
46     private boolean mSkipExitAlphaAnimation;
47 
48     private final TimeInterpolator mLinearOutSlowIn;
49     private final TimeInterpolator mFastOutLinearIn;
50 
FullscreenDialogView(Context context)51     public FullscreenDialogView(Context context) {
52         this(context, null, 0);
53     }
54 
FullscreenDialogView(Context context, AttributeSet attrs)55     public FullscreenDialogView(Context context, AttributeSet attrs) {
56         this(context, attrs, 0);
57     }
58 
FullscreenDialogView(Context context, AttributeSet attrs, int defStyle)59     public FullscreenDialogView(Context context, AttributeSet attrs, int defStyle) {
60         super(context, attrs, defStyle);
61         mLinearOutSlowIn = AnimationUtils.loadInterpolator(context,
62                 android.R.interpolator.linear_out_slow_in);
63         mFastOutLinearIn = AnimationUtils.loadInterpolator(context,
64                 android.R.interpolator.fast_out_linear_in);
65         getViewTreeObserver().addOnGlobalLayoutListener(
66                 new ViewTreeObserver.OnGlobalLayoutListener() {
67                     @Override
68                     public void onGlobalLayout() {
69                         getViewTreeObserver().removeOnGlobalLayoutListener(this);
70                         startEnterAnimation();
71                     }
72                 });
73     }
74 
getActivity()75     protected MainActivity getActivity() {
76         return mActivity;
77     }
78 
79     /**
80      * Gets the host {@link Dialog}.
81      */
getDialog()82     protected Dialog getDialog() {
83         return mDialog;
84     }
85 
86     /**
87      * Dismisses the host {@link Dialog}.
88      */
dismiss()89     protected void dismiss() {
90         startExitAnimation(new Runnable() {
91             @Override
92             public void run() {
93                 mDialog.dismiss();
94             }
95         });
96     }
97 
98     @Override
initialize(MainActivity activity, Dialog dialog)99     public void initialize(MainActivity activity, Dialog dialog) {
100         mActivity = activity;
101         mDialog = dialog;
102     }
103 
104     @Override
onBackPressed()105     public void onBackPressed() { }
106 
107     @Override
onDestroy()108     public void onDestroy() { }
109 
110     /**
111      * Transitions to another view inside the host {@link Dialog}.
112      */
transitionTo(final FullscreenDialogView v)113     public void transitionTo(final FullscreenDialogView v) {
114         mSkipExitAlphaAnimation = true;
115         v.mSkipEnterAlphaAnimation = true;
116         v.initialize(mActivity, mDialog);
117         startExitAnimation(new Runnable() {
118             @Override
119             public void run() {
120                 new Handler().postDelayed(new Runnable() {
121                     @Override
122                     public void run() {
123                         v.initialize(getActivity(), getDialog());
124                         getDialog().setContentView(v);
125                     }
126                 }, TRANSITION_INTERVAL_MS);
127             }
128         });
129     }
130 
131     /**
132      * Called when an enter animation starts. Sub-view specific animation can be implemented.
133      */
onStartEnterAnimation(TimeInterpolator interpolator, long duration)134     protected void onStartEnterAnimation(TimeInterpolator interpolator, long duration) {
135     }
136 
137     /**
138      * Called when an exit animation starts. Sub-view specific animation can be implemented.
139      */
onStartExitAnimation(TimeInterpolator interpolator, long duration, Runnable onAnimationEnded)140     protected void onStartExitAnimation(TimeInterpolator interpolator, long duration,
141             Runnable onAnimationEnded) {
142     }
143 
startEnterAnimation()144     private void startEnterAnimation() {
145         if (DEBUG) Log.d(TAG, "start an enter animation");
146         View backgroundView = findViewById(R.id.background);
147         if (!mSkipEnterAlphaAnimation) {
148             backgroundView.setAlpha(0);
149             backgroundView.animate()
150                     .alpha(1.0f)
151                     .setInterpolator(mLinearOutSlowIn)
152                     .setDuration(FADE_IN_DURATION_MS)
153                     .withLayer()
154                     .start();
155         }
156         onStartEnterAnimation(mLinearOutSlowIn, FADE_IN_DURATION_MS);
157     }
158 
startExitAnimation(final Runnable onAnimationEnded)159     private void startExitAnimation(final Runnable onAnimationEnded) {
160         if (DEBUG) Log.d(TAG, "start an exit animation");
161         View backgroundView = findViewById(R.id.background);
162         if (!mSkipExitAlphaAnimation) {
163             backgroundView.animate()
164                     .alpha(0.0f)
165                     .setInterpolator(mFastOutLinearIn)
166                     .setDuration(FADE_OUT_DURATION_MS)
167                     .withLayer()
168                     .start();
169         }
170         onStartExitAnimation(mFastOutLinearIn, FADE_OUT_DURATION_MS, onAnimationEnded);
171     }
172 }
173