aboutsummaryrefslogtreecommitdiff
path: root/src/com/android/tv/menu/Menu.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/tv/menu/Menu.java')
-rw-r--r--src/com/android/tv/menu/Menu.java171
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);
- }
- }
- }
}