diff options
Diffstat (limited to 'src/com/android/tv/menu/Menu.java')
-rw-r--r-- | src/com/android/tv/menu/Menu.java | 171 |
1 files changed, 79 insertions, 92 deletions
diff --git a/src/com/android/tv/menu/Menu.java b/src/com/android/tv/menu/Menu.java index e373de61..19a93dbc 100644 --- a/src/com/android/tv/menu/Menu.java +++ b/src/com/android/tv/menu/Menu.java @@ -21,27 +21,23 @@ import android.animation.AnimatorInflater; import android.animation.AnimatorListenerAdapter; import android.content.Context; import android.content.res.Resources; -import android.os.Looper; -import android.os.Message; import android.support.annotation.IntDef; -import android.support.annotation.NonNull; import android.support.annotation.VisibleForTesting; import android.support.v17.leanback.widget.HorizontalGridView; import android.util.Log; - +import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener; import com.android.tv.ChannelTuner; import com.android.tv.R; -import com.android.tv.TvApplication; import com.android.tv.TvOptionsManager; +import com.android.tv.TvSingletons; import com.android.tv.analytics.Tracker; -import com.android.tv.common.TvCommonUtils; -import com.android.tv.common.WeakHandler; +import com.android.tv.common.util.CommonUtils; +import com.android.tv.common.util.DurationTimer; import com.android.tv.menu.MenuRowFactory.PartnerRow; import com.android.tv.menu.MenuRowFactory.TvOptionsRow; import com.android.tv.ui.TunableTvView; -import com.android.tv.util.DurationTimer; +import com.android.tv.ui.hideable.AutoHideScheduler; import com.android.tv.util.ViewCache; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -49,19 +45,25 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -/** - * A class which controls the menu. - */ -public class Menu { +/** A class which controls the menu. */ +public class Menu implements AccessibilityStateChangeListener { private static final String TAG = "Menu"; private static final boolean DEBUG = false; @Retention(RetentionPolicy.SOURCE) - @IntDef({REASON_NONE, REASON_GUIDE, REASON_PLAY_CONTROLS_PLAY, REASON_PLAY_CONTROLS_PAUSE, - REASON_PLAY_CONTROLS_PLAY_PAUSE, REASON_PLAY_CONTROLS_REWIND, - REASON_PLAY_CONTROLS_FAST_FORWARD, REASON_PLAY_CONTROLS_JUMP_TO_PREVIOUS, - REASON_PLAY_CONTROLS_JUMP_TO_NEXT}) + @IntDef({ + REASON_NONE, + REASON_GUIDE, + REASON_PLAY_CONTROLS_PLAY, + REASON_PLAY_CONTROLS_PAUSE, + REASON_PLAY_CONTROLS_PLAY_PAUSE, + REASON_PLAY_CONTROLS_REWIND, + REASON_PLAY_CONTROLS_FAST_FORWARD, + REASON_PLAY_CONTROLS_JUMP_TO_PREVIOUS, + REASON_PLAY_CONTROLS_JUMP_TO_NEXT + }) public @interface MenuShowReason {} + public static final int REASON_NONE = 0; public static final int REASON_GUIDE = 1; public static final int REASON_PLAY_CONTROLS_PLAY = 2; @@ -73,6 +75,7 @@ public class Menu { public static final int REASON_PLAY_CONTROLS_JUMP_TO_NEXT = 8; private static final List<String> sRowIdListForReason = new ArrayList<>(); + static { sRowIdListForReason.add(null); // REASON_NONE sRowIdListForReason.add(ChannelsRow.ID); // REASON_GUIDE @@ -86,6 +89,7 @@ public class Menu { } private static final Map<Integer, Integer> PRELOAD_VIEW_IDS = new HashMap<>(); + static { PRELOAD_VIEW_IDS.put(R.layout.menu_card_guide, 1); PRELOAD_VIEW_IDS.put(R.layout.menu_card_setup, 1); @@ -97,15 +101,13 @@ public class Menu { private static final String SCREEN_NAME = "Menu"; - private static final int MSG_HIDE_MENU = 1000; - private final Context mContext; private final IMenuView mMenuView; private final Tracker mTracker; private final DurationTimer mVisibleTimer = new DurationTimer(); private final long mShowDurationMillis; private final OnMenuVisibilityChangeListener mOnMenuVisibilityChangeListener; - private final WeakHandler<Menu> mHandler = new MenuWeakHandler(this, Looper.getMainLooper()); + private final AutoHideScheduler mAutoHideScheduler; private final MenuUpdater mMenuUpdater; private final List<MenuRow> mMenuRows = new ArrayList<>(); @@ -116,17 +118,24 @@ public class Menu { private boolean mAnimationDisabledForTest; @VisibleForTesting - Menu(Context context, IMenuView menuView, MenuRowFactory menuRowFactory, + Menu( + Context context, + IMenuView menuView, + MenuRowFactory menuRowFactory, OnMenuVisibilityChangeListener onMenuVisibilityChangeListener) { this(context, null, null, menuView, menuRowFactory, onMenuVisibilityChangeListener); } - public Menu(Context context, TunableTvView tvView, TvOptionsManager optionsManager, - IMenuView menuView, MenuRowFactory menuRowFactory, + public Menu( + Context context, + TunableTvView tvView, + TvOptionsManager optionsManager, + IMenuView menuView, + MenuRowFactory menuRowFactory, OnMenuVisibilityChangeListener onMenuVisibilityChangeListener) { mContext = context; mMenuView = menuView; - mTracker = TvApplication.getSingletons(context).getTracker(); + mTracker = TvSingletons.getSingletons(context).getTracker(); mMenuUpdater = new MenuUpdater(this, tvView, optionsManager); Resources res = context.getResources(); mShowDurationMillis = res.getInteger(R.integer.menu_show_duration); @@ -134,12 +143,13 @@ public class Menu { mShowAnimator = AnimatorInflater.loadAnimator(context, R.animator.menu_enter); mShowAnimator.setTarget(mMenuView); mHideAnimator = AnimatorInflater.loadAnimator(context, R.animator.menu_exit); - mHideAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - hideInternal(); - } - }); + mHideAnimator.addListener( + new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + hideInternal(); + } + }); mHideAnimator.setTarget(mMenuView); // Build menu rows addMenuRow(menuRowFactory.createMenuRow(this, PlayControlsRow.class)); @@ -147,6 +157,7 @@ public class Menu { addMenuRow(menuRowFactory.createMenuRow(this, PartnerRow.class)); addMenuRow(menuRowFactory.createMenuRow(this, TvOptionsRow.class)); mMenuView.setMenuRows(mMenuRows); + mAutoHideScheduler = new AutoHideScheduler(context, () -> hide(true)); } /** @@ -163,20 +174,16 @@ public class Menu { } } - /** - * Call this method to end the lifetime of the menu. - */ + /** Call this method to end the lifetime of the menu. */ public void release() { mMenuUpdater.release(); for (MenuRow row : mMenuRows) { row.release(); } - mHandler.removeCallbacksAndMessages(null); + mAutoHideScheduler.cancel(); } - /** - * Preloads the item view used for the menu. - */ + /** Preloads the item view used for the menu. */ public void preloadItemViews() { HorizontalGridView fakeParent = new HorizontalGridView(mContext); for (int id : PRELOAD_VIEW_IDS.keySet()) { @@ -201,20 +208,23 @@ public class Menu { mOnMenuVisibilityChangeListener.onMenuVisibilityChange(true); } String rowIdToSelect = sRowIdListForReason.get(reason); - mMenuView.onShow(reason, rowIdToSelect, mAnimationDisabledForTest ? null : new Runnable() { - @Override - public void run() { - if (isActive()) { - mShowAnimator.start(); - } - } - }); + mMenuView.onShow( + reason, + rowIdToSelect, + mAnimationDisabledForTest + ? null + : new Runnable() { + @Override + public void run() { + if (isActive()) { + mShowAnimator.start(); + } + } + }); scheduleHide(); } - /** - * Closes the menu. - */ + /** Closes the menu. */ public void hide(boolean withAnimation) { if (mShowAnimator.isStarted()) { mShowAnimator.cancel(); @@ -225,7 +235,7 @@ public class Menu { if (mAnimationDisabledForTest) { withAnimation = false; } - mHandler.removeMessages(MSG_HIDE_MENU); + mAutoHideScheduler.cancel(); if (withAnimation) { if (!mHideAnimator.isStarted()) { mHideAnimator.start(); @@ -246,26 +256,21 @@ public class Menu { } } - /** - * Schedules to hide the menu in some seconds. - */ + /** Schedules to hide the menu in some seconds. */ public void scheduleHide() { - mHandler.removeMessages(MSG_HIDE_MENU); - if (!mKeepVisible) { - mHandler.sendEmptyMessageDelayed(MSG_HIDE_MENU, mShowDurationMillis); - } + mAutoHideScheduler.schedule(mShowDurationMillis); } /** - * Called when the caller wants the main menu to be kept visible or not. - * If {@code keepVisible} is set to {@code true}, the hide schedule doesn't close the main menu, - * but calling {@link #hide} still hides it. - * If {@code keepVisible} is set to {@code false}, the hide schedule works as usual. + * Called when the caller wants the main menu to be kept visible or not. If {@code keepVisible} + * is set to {@code true}, the hide schedule doesn't close the main menu, but calling {@link + * #hide} still hides it. If {@code keepVisible} is set to {@code false}, the hide schedule + * works as usual. */ public void setKeepVisible(boolean keepVisible) { mKeepVisible = keepVisible; if (mKeepVisible) { - mHandler.removeMessages(MSG_HIDE_MENU); + mAutoHideScheduler.cancel(); } else if (isActive()) { scheduleHide(); } @@ -273,12 +278,10 @@ public class Menu { @VisibleForTesting boolean isHideScheduled() { - return mHandler.hasMessages(MSG_HIDE_MENU); + return mAutoHideScheduler.isScheduled(); } - /** - * Returns {@code true} if the menu is open and not hiding. - */ + /** Returns {@code true} if the menu is open and not hiding. */ public boolean isActive() { return mMenuView.isVisible() && !mHideAnimator.isStarted(); } @@ -303,9 +306,7 @@ public class Menu { return mMenuView.update(rowId, isActive()); } - /** - * This method is called when channels are changed. - */ + /** This method is called when channels are changed. */ public void onRecentChannelsChanged() { if (DEBUG) Log.d(TAG, "onRecentChannelsChanged"); for (MenuRow row : mMenuRows) { @@ -313,42 +314,28 @@ public class Menu { } } - /** - * This method is called when the stream information is changed. - */ + /** This method is called when the stream information is changed. */ public void onStreamInfoChanged() { if (DEBUG) Log.d(TAG, "update options row in main menu"); mMenuUpdater.onStreamInfoChanged(); } + @Override + public void onAccessibilityStateChanged(boolean enabled) { + mAutoHideScheduler.onAccessibilityStateChanged(enabled); + } + @VisibleForTesting void disableAnimationForTest() { - if (!TvCommonUtils.isRunningInTest()) { + if (!CommonUtils.isRunningInTest()) { throw new RuntimeException("Animation may only be enabled/disabled during tests."); } mAnimationDisabledForTest = true; } - /** - * A listener which receives the notification when the menu is visible/invisible. - */ - public static abstract class OnMenuVisibilityChangeListener { - /** - * Called when the menu becomes visible/invisible. - */ + /** A listener which receives the notification when the menu is visible/invisible. */ + public abstract static class OnMenuVisibilityChangeListener { + /** Called when the menu becomes visible/invisible. */ public abstract void onMenuVisibilityChange(boolean visible); } - - private static class MenuWeakHandler extends WeakHandler<Menu> { - public MenuWeakHandler(Menu menu, Looper mainLooper) { - super(mainLooper, menu); - } - - @Override - public void handleMessage(Message msg, @NonNull Menu menu) { - if (msg.what == MSG_HIDE_MENU) { - menu.hide(true); - } - } - } } |