1 package com.android.tv.ui.hideable; 2 3 import android.content.Context; 4 import android.os.Looper; 5 import android.os.Message; 6 import android.support.annotation.NonNull; 7 import android.support.annotation.UiThread; 8 import android.support.annotation.VisibleForTesting; 9 import android.view.accessibility.AccessibilityManager; 10 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener; 11 import com.android.tv.common.WeakHandler; 12 13 /** 14 * Schedules a view element to be hidden after a delay. 15 * 16 * <p>When accessibility is turned on elements are not automatically hidden. 17 * 18 * <p>Users of this class must pass it to {@link 19 * AccessibilityManager#addAccessibilityStateChangeListener(AccessibilityStateChangeListener)} and 20 * {@link 21 * AccessibilityManager#removeAccessibilityStateChangeListener(AccessibilityStateChangeListener)} 22 * during the appropriate live cycle event, or handle calling {@link 23 * #onAccessibilityStateChanged(boolean)}. 24 */ 25 @UiThread 26 public final class AutoHideScheduler implements AccessibilityStateChangeListener { 27 private static final int MSG_HIDE = 1; 28 29 private final HideHandler mHandler; 30 private final Runnable mRunnable; 31 32 public AutoHideScheduler(Context context, Runnable runnable) { 33 this( 34 runnable, 35 context.getSystemService(AccessibilityManager.class), 36 Looper.getMainLooper()); 37 } 38 39 @VisibleForTesting 40 AutoHideScheduler(Runnable runnable, AccessibilityManager accessibilityManager, Looper looper) { 41 // Keep a reference here because HideHandler only has a weak reference to it. 42 mRunnable = runnable; 43 mHandler = new HideHandler(looper, mRunnable); 44 mHandler.setAllowAutoHide(!accessibilityManager.isEnabled()); 45 } 46 47 public void cancel() { 48 mHandler.removeMessages(MSG_HIDE); 49 } 50 51 public void schedule(long delayMs) { 52 cancel(); 53 if (mHandler.mAllowAutoHide) { 54 mHandler.sendEmptyMessageDelayed(MSG_HIDE, delayMs); 55 } 56 } 57 58 @Override 59 public void onAccessibilityStateChanged(boolean enabled) { 60 mHandler.onAccessibilityStateChanged(enabled); 61 } 62 63 public boolean isScheduled() { 64 return mHandler.hasMessages(MSG_HIDE); 65 } 66 67 private static class HideHandler extends WeakHandler<Runnable> 68 implements AccessibilityStateChangeListener { 69 70 private boolean mAllowAutoHide; 71 72 public HideHandler(Looper looper, Runnable hideRunner) { 73 super(looper, hideRunner); 74 } 75 76 @Override 77 protected void handleMessage(Message msg, @NonNull Runnable runnable) { 78 switch (msg.what) { 79 case MSG_HIDE: 80 if (mAllowAutoHide) { 81 runnable.run(); 82 } 83 break; 84 default: 85 // do nothing 86 } 87 } 88 89 public void setAllowAutoHide(boolean mAllowAutoHide) { 90 this.mAllowAutoHide = mAllowAutoHide; 91 } 92 93 @Override 94 public void onAccessibilityStateChanged(boolean enabled) { 95 mAllowAutoHide = !enabled; 96 } 97 } 98 } 99