diff options
Diffstat (limited to 'src/com/android/tv/ui/sidepanel/SideFragmentManager.java')
-rw-r--r-- | src/com/android/tv/ui/sidepanel/SideFragmentManager.java | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/src/com/android/tv/ui/sidepanel/SideFragmentManager.java b/src/com/android/tv/ui/sidepanel/SideFragmentManager.java new file mode 100644 index 00000000..b1041629 --- /dev/null +++ b/src/com/android/tv/ui/sidepanel/SideFragmentManager.java @@ -0,0 +1,222 @@ +/* + * 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.sidepanel; + +import android.animation.Animator; +import android.animation.AnimatorInflater; +import android.animation.AnimatorListenerAdapter; +import android.app.Activity; +import android.app.FragmentManager; +import android.app.FragmentTransaction; +import android.view.View; + +import com.android.tv.R; + +public class SideFragmentManager { + private static final String FIRST_BACKSTACK_RECORD_NAME = "0"; + + private final Activity mActivity; + private final FragmentManager mFragmentManager; + private final Runnable mPreShowRunnable; + private final Runnable mPostHideRunnable; + + // To get the count reliably while using popBackStack(), + // instead of using getBackStackEntryCount() with popBackStackImmediate(). + private int mFragmentCount; + + private final View mPanel; + private final Animator mShowAnimator; + private final Animator mHideAnimator; + + private final Runnable mHideAllRunnable = new Runnable() { + @Override + public void run() { + hideAll(true); + } + }; + private final long mShowDurationMillis; + + public SideFragmentManager(Activity activity, Runnable preShowRunnable, + Runnable postHideRunnable) { + mActivity = activity; + mFragmentManager = mActivity.getFragmentManager(); + mPreShowRunnable = preShowRunnable; + mPostHideRunnable = postHideRunnable; + + mPanel = mActivity.findViewById(R.id.side_panel); + mShowAnimator = AnimatorInflater.loadAnimator(mActivity, R.animator.side_panel_enter); + mShowAnimator.setTarget(mPanel); + mHideAnimator = AnimatorInflater.loadAnimator(mActivity, R.animator.side_panel_exit); + mHideAnimator.setTarget(mPanel); + mHideAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + // Animation is still in running state at this point. + hideAllInternal(); + } + }); + + mShowDurationMillis = mActivity.getResources().getInteger( + R.integer.side_panel_show_duration); + } + + public int getCount() { + return mFragmentCount; + } + + public boolean isActive() { + return mFragmentCount != 0 && !isHiding(); + } + + public boolean isHiding() { + return mHideAnimator.isStarted(); + } + + public void show(SideFragment sideFragment) { + SideFragment.preloadRecycledViews(mActivity); + if (isHiding()) { + mHideAnimator.end(); + } + boolean isFirst = (mFragmentCount == 0); + if (isFirst) { + if (mPreShowRunnable != null) { + mPreShowRunnable.run(); + } + } + + FragmentTransaction ft = mFragmentManager.beginTransaction(); + if (!isFirst) { + ft.setCustomAnimations( + R.animator.side_panel_fragment_enter, + R.animator.side_panel_fragment_exit, + R.animator.side_panel_fragment_pop_enter, + R.animator.side_panel_fragment_pop_exit); + } + ft.replace(R.id.side_fragment_container, sideFragment) + .addToBackStack(Integer.toString(mFragmentCount)).commit(); + mFragmentCount++; + + if (isFirst) { + mPanel.setVisibility(View.VISIBLE); + mShowAnimator.start(); + } + scheduleHideAll(); + } + + public void popSideFragment() { + if (!isActive()) { + return; + } else if (mFragmentCount == 1) { + // Show closing animation with the last fragment. + hideAll(true); + return; + } + mFragmentManager.popBackStack(); + mFragmentCount--; + } + + public void hideAll(boolean withAnimation) { + if (withAnimation) { + if (!isHiding()) { + mHideAnimator.start(); + } + return; + } + if (isHiding()) { + mHideAnimator.end(); + return; + } + hideAllInternal(); + } + + private void hideAllInternal() { + if (mFragmentCount == 0) { + return; + } + + mPanel.setVisibility(View.GONE); + mFragmentManager.popBackStack(FIRST_BACKSTACK_RECORD_NAME, + FragmentManager.POP_BACK_STACK_INCLUSIVE); + mFragmentCount = 0; + + if (mPostHideRunnable != null) { + mPostHideRunnable.run(); + } + } + + /** + * Show the side panel with animation. If there are many entries in the fragment stack, + * the animation look like that there's only one fragment. + * + * @param withAnimation specifies if animation should be shown. + */ + public void showSidePanel(boolean withAnimation) { + SideFragment.preloadRecycledViews(mActivity); + if (mFragmentCount == 0) { + return; + } + + mPanel.setVisibility(View.VISIBLE); + if (withAnimation) { + mShowAnimator.start(); + } + scheduleHideAll(); + } + + /** + * Hide the side panel. This method just hide the panel and preserves the back + * stack. If you want to empty the back stack, call {@link #hideAll}. + */ + public void hideSidePanel(boolean withAnimation) { + if (withAnimation) { + mPanel.removeCallbacks(mHideAllRunnable); + Animator hideAnimator = + AnimatorInflater.loadAnimator(mActivity, R.animator.side_panel_exit); + hideAnimator.setTarget(mPanel); + hideAnimator.start(); + hideAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mPanel.setVisibility(View.GONE); + } + }); + } else { + mPanel.setVisibility(View.GONE); + } + } + + public boolean isSidePanelVisible() { + return mPanel.getVisibility() == View.VISIBLE; + } + + public void scheduleHideAll() { + mPanel.removeCallbacks(mHideAllRunnable); + mPanel.postDelayed(mHideAllRunnable, mShowDurationMillis); + } + + /** + * Should {@code keyCode} hide the current panel. + */ + public boolean isHideKeyForCurrentPanel(int keyCode) { + if (isActive()) { + SideFragment current = (SideFragment) mFragmentManager.findFragmentById( + R.id.side_fragment_container); + return current != null && current.isHideKeyForThisPanel(keyCode); + } + return false; + } +} |