aboutsummaryrefslogtreecommitdiff
path: root/src/com/android/tv/ui/TvTransitionManager.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/tv/ui/TvTransitionManager.java')
-rw-r--r--src/com/android/tv/ui/TvTransitionManager.java315
1 files changed, 315 insertions, 0 deletions
diff --git a/src/com/android/tv/ui/TvTransitionManager.java b/src/com/android/tv/ui/TvTransitionManager.java
new file mode 100644
index 00000000..7096893f
--- /dev/null
+++ b/src/com/android/tv/ui/TvTransitionManager.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.ui;
+
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.support.annotation.IntDef;
+import android.transition.Fade;
+import android.transition.Scene;
+import android.transition.Transition;
+import android.transition.TransitionInflater;
+import android.transition.TransitionManager;
+import android.transition.TransitionSet;
+import android.transition.TransitionValues;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.FrameLayout.LayoutParams;
+
+import com.android.tv.MainActivity;
+import com.android.tv.R;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+public class TvTransitionManager extends TransitionManager {
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({SCENE_TYPE_EMPTY, SCENE_TYPE_CHANNEL_BANNER, SCENE_TYPE_INPUT_BANNER,
+ SCENE_TYPE_KEYPAD_CHANNEL_SWITCH, SCENE_TYPE_SELECT_INPUT})
+ public @interface SceneType {}
+ public static final int SCENE_TYPE_EMPTY = 0;
+ public static final int SCENE_TYPE_CHANNEL_BANNER = 1;
+ public static final int SCENE_TYPE_INPUT_BANNER = 2;
+ public static final int SCENE_TYPE_KEYPAD_CHANNEL_SWITCH = 3;
+ public static final int SCENE_TYPE_SELECT_INPUT = 4;
+
+ private final MainActivity mMainActivity;
+ private final ViewGroup mSceneContainer;
+ private final ChannelBannerView mChannelBannerView;
+ private final InputBannerView mInputBannerView;
+ private final KeypadChannelSwitchView mKeypadChannelSwitchView;
+ private final SelectInputView mSelectInputView;
+ private final FrameLayout mEmptyView;
+ private ViewGroup mCurrentSceneView;
+ private Animator mEnterAnimator;
+ private Animator mExitAnimator;
+
+ private boolean mInitialized;
+ private Scene mEmptyScene;
+ private Scene mChannelBannerScene;
+ private Scene mInputBannerScene;
+ private Scene mKeypadChannelSwitchScene;
+ private Scene mSelectInputScene;
+ private Scene mCurrentScene;
+
+ private Listener mListener;
+
+ public TvTransitionManager(MainActivity mainActivity, ViewGroup sceneContainer,
+ ChannelBannerView channelBannerView, InputBannerView inputBannerView,
+ KeypadChannelSwitchView keypadChannelSwitchView, SelectInputView selectInputView) {
+ mMainActivity = mainActivity;
+ mSceneContainer = sceneContainer;
+ mChannelBannerView = channelBannerView;
+ mInputBannerView = inputBannerView;
+ mKeypadChannelSwitchView = keypadChannelSwitchView;
+ mSelectInputView = selectInputView;
+ mEmptyView = (FrameLayout) mMainActivity.getLayoutInflater().inflate(
+ R.layout.empty_info_banner, sceneContainer, false);
+ mCurrentSceneView = mEmptyView;
+ }
+
+ public void goToEmptyScene(boolean withAnimation) {
+ if (mCurrentScene == mEmptyScene) {
+ return;
+ }
+ initIfNeeded();
+ if (withAnimation) {
+ transitionTo(mEmptyScene);
+ } else {
+ TransitionManager.go(mEmptyScene, null);
+ }
+ }
+
+ public void goToChannelBannerScene() {
+ initIfNeeded();
+ if (mMainActivity.getCurrentChannel().isPassthrough()) {
+ if (mCurrentScene != mInputBannerScene) {
+ // Show the input banner instead.
+ LayoutParams lp = (LayoutParams) mInputBannerView.getLayoutParams();
+ lp.width = mCurrentScene == mSelectInputScene ? mSelectInputView.getWidth()
+ : FrameLayout.LayoutParams.WRAP_CONTENT;
+ mInputBannerView.setLayoutParams(lp);
+ mInputBannerView.updateLabel();
+ transitionTo(mInputBannerScene);
+ }
+ } else if (mCurrentScene != mChannelBannerScene) {
+ transitionTo(mChannelBannerScene);
+ }
+ }
+
+ public void goToKeypadChannelSwitchScene() {
+ initIfNeeded();
+ if (mCurrentScene != mKeypadChannelSwitchScene) {
+ transitionTo(mKeypadChannelSwitchScene);
+ }
+ }
+
+ public void goToSelectInputScene() {
+ initIfNeeded();
+ if (mCurrentScene != mSelectInputScene) {
+ transitionTo(mSelectInputScene);
+ }
+ }
+
+ public boolean isSceneActive() {
+ return mCurrentScene != mEmptyScene;
+ }
+
+ public boolean isKeypadChannelSwitchActive() {
+ return mCurrentScene != null && mCurrentScene == mKeypadChannelSwitchScene;
+ }
+
+ public boolean isSelectInputActive() {
+ return mCurrentScene != null && mCurrentScene == mSelectInputScene;
+ }
+
+ public void setListener(Listener listener) {
+ mListener = listener;
+ }
+
+ public void initIfNeeded() {
+ if (mInitialized) {
+ return;
+ }
+ mEnterAnimator = AnimatorInflater.loadAnimator(mMainActivity,
+ R.animator.channel_banner_enter);
+ mExitAnimator = AnimatorInflater.loadAnimator(mMainActivity,
+ R.animator.channel_banner_exit);
+
+ mEmptyScene = new Scene(mSceneContainer, mEmptyView);
+ mEmptyScene.setEnterAction(new Runnable() {
+ @Override
+ public void run() {
+ FrameLayout.LayoutParams emptySceneLayoutParams =
+ (FrameLayout.LayoutParams) mEmptyView.getLayoutParams();
+ ViewGroup.MarginLayoutParams lp =
+ (ViewGroup.MarginLayoutParams) mCurrentSceneView.getLayoutParams();
+ emptySceneLayoutParams.topMargin = mCurrentSceneView.getTop();
+ emptySceneLayoutParams.setMarginStart(lp.getMarginStart());
+ emptySceneLayoutParams.height = mCurrentSceneView.getHeight();
+ emptySceneLayoutParams.width = mCurrentSceneView.getWidth();
+ mEmptyView.setLayoutParams(emptySceneLayoutParams);
+ setCurrentScene(mEmptyScene, mEmptyView);
+ }
+ });
+ mEmptyScene.setExitAction(new Runnable() {
+ @Override
+ public void run() {
+ removeAllViewsFromOverlay();
+ }
+ });
+
+ mChannelBannerScene = buildScene(mSceneContainer, mChannelBannerView);
+ mInputBannerScene = buildScene(mSceneContainer, mInputBannerView);
+ mKeypadChannelSwitchScene = buildScene(mSceneContainer, mKeypadChannelSwitchView);
+ mSelectInputScene = buildScene(mSceneContainer, mSelectInputView);
+ mCurrentScene = mEmptyScene;
+
+ // Enter transitions
+ TransitionSet enter = new TransitionSet()
+ .addTransition(new SceneTransition(SceneTransition.ENTER))
+ .addTransition(new Fade(Fade.IN));
+ setTransition(mEmptyScene, mChannelBannerScene, enter);
+ setTransition(mEmptyScene, mInputBannerScene, enter);
+ setTransition(mEmptyScene, mKeypadChannelSwitchScene, enter);
+ setTransition(mEmptyScene, mSelectInputScene, enter);
+
+ // Exit transitions
+ TransitionSet exit = new TransitionSet()
+ .addTransition(new SceneTransition(SceneTransition.EXIT))
+ .addTransition(new Fade(Fade.OUT));
+ setTransition(mChannelBannerScene, mEmptyScene, exit);
+ setTransition(mInputBannerScene, mEmptyScene, exit);
+ setTransition(mKeypadChannelSwitchScene, mEmptyScene, exit);
+ setTransition(mSelectInputScene, mEmptyScene, exit);
+
+ // All other possible transitions between scenes
+ TransitionInflater ti = TransitionInflater.from(mMainActivity);
+ Transition transition = ti.inflateTransition(R.transition.transition_between_scenes);
+ setTransition(mChannelBannerScene, mKeypadChannelSwitchScene, transition);
+ setTransition(mChannelBannerScene, mSelectInputScene, transition);
+ setTransition(mInputBannerScene, mSelectInputScene, transition);
+ setTransition(mKeypadChannelSwitchScene, mChannelBannerScene, transition);
+ setTransition(mKeypadChannelSwitchScene, mSelectInputScene, transition);
+ setTransition(mSelectInputScene, mChannelBannerScene, transition);
+ setTransition(mSelectInputScene, mInputBannerScene, transition);
+
+ mInitialized = true;
+ }
+
+ /**
+ * Returns the type of the given scene.
+ */
+ @SceneType public int getSceneType(Scene scene) {
+ if (scene == mChannelBannerScene) {
+ return SCENE_TYPE_CHANNEL_BANNER;
+ } else if (scene == mInputBannerScene) {
+ return SCENE_TYPE_INPUT_BANNER;
+ } else if (scene == mKeypadChannelSwitchScene) {
+ return SCENE_TYPE_KEYPAD_CHANNEL_SWITCH;
+ } else if (scene == mSelectInputScene) {
+ return SCENE_TYPE_SELECT_INPUT;
+ }
+ return SCENE_TYPE_EMPTY;
+ }
+
+ private void setCurrentScene(Scene scene, ViewGroup sceneView) {
+ if (mListener != null) {
+ mListener.onSceneChanged(getSceneType(mCurrentScene), getSceneType(scene));
+ }
+ mCurrentScene = scene;
+ mCurrentSceneView = sceneView;
+ // TODO: Is this a still valid call?
+ mMainActivity.updateKeyInputFocus();
+ }
+
+ public interface TransitionLayout {
+ // TODO: remove the parameter fromEmptyScene once a bug regarding transition alpha
+ // is fixed. The bug is that the transition alpha is not reset after the transition is
+ // canceled.
+ void onEnterAction(boolean fromEmptyScene);
+
+ void onExitAction();
+ }
+
+ private Scene buildScene(ViewGroup sceneRoot, final TransitionLayout layout) {
+ final Scene scene = new Scene(sceneRoot, (View) layout);
+ scene.setEnterAction(new Runnable() {
+ @Override
+ public void run() {
+ boolean wasEmptyScene = (mCurrentScene == mEmptyScene);
+ setCurrentScene(scene, (ViewGroup) layout);
+ layout.onEnterAction(wasEmptyScene);
+ }
+ });
+ scene.setExitAction(new Runnable() {
+ @Override
+ public void run() {
+ removeAllViewsFromOverlay();
+ layout.onExitAction();
+ }
+ });
+ return scene;
+ }
+
+ private void removeAllViewsFromOverlay() {
+ // Clean up all the animations which can be still running.
+ mSceneContainer.getOverlay().remove(mChannelBannerView);
+ mSceneContainer.getOverlay().remove(mInputBannerView);
+ mSceneContainer.getOverlay().remove(mKeypadChannelSwitchView);
+ mSceneContainer.getOverlay().remove(mSelectInputView);
+ }
+
+ private class SceneTransition extends Transition {
+ static final int ENTER = 0;
+ static final int EXIT = 1;
+
+ private final Animator mAnimator;
+
+ SceneTransition(int mode) {
+ mAnimator = mode == ENTER ? mEnterAnimator : mExitAnimator;
+ }
+
+ @Override
+ public void captureStartValues(TransitionValues transitionValues) {
+ }
+
+ @Override
+ public void captureEndValues(TransitionValues transitionValues) {
+ }
+
+ @Override
+ public Animator createAnimator(
+ ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) {
+ Animator animator = mAnimator.clone();
+ animator.setTarget(sceneRoot);
+ animator.addListener(new HardwareLayerAnimatorListenerAdapter(sceneRoot));
+ return animator;
+ }
+ }
+
+ /**
+ * An interface for notification of the scene transition.
+ */
+ public interface Listener {
+ /**
+ * Called when the scene changes. This method is called just before the scene transition.
+ */
+ void onSceneChanged(@SceneType int fromSceneType, @SceneType int toSceneType);
+ }
+}