/* * Copyright (C) 2018 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.hideable; import android.content.Context; import android.os.Looper; import android.os.Message; import android.support.annotation.NonNull; import android.support.annotation.UiThread; import android.support.annotation.VisibleForTesting; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener; import com.android.tv.common.WeakHandler; /** * Schedules a view element to be hidden after a delay. * *

When accessibility is turned on elements are not automatically hidden. * *

Users of this class must pass it to {@link * AccessibilityManager#addAccessibilityStateChangeListener(AccessibilityStateChangeListener)} and * {@link * AccessibilityManager#removeAccessibilityStateChangeListener(AccessibilityStateChangeListener)} * during the appropriate live cycle event, or handle calling {@link * #onAccessibilityStateChanged(boolean)}. */ @UiThread public final class AutoHideScheduler implements AccessibilityStateChangeListener { private static final int MSG_HIDE = 1; private final HideHandler mHandler; private final Runnable mRunnable; public AutoHideScheduler(Context context, Runnable runnable) { this( runnable, context.getSystemService(AccessibilityManager.class), Looper.getMainLooper()); } @VisibleForTesting AutoHideScheduler(Runnable runnable, AccessibilityManager accessibilityManager, Looper looper) { // Keep a reference here because HideHandler only has a weak reference to it. mRunnable = runnable; mHandler = new HideHandler(looper, mRunnable); mHandler.setAllowAutoHide(!accessibilityManager.isEnabled()); } public void cancel() { mHandler.removeMessages(MSG_HIDE); } public void schedule(long delayMs) { cancel(); if (mHandler.mAllowAutoHide) { mHandler.sendEmptyMessageDelayed(MSG_HIDE, delayMs); } } @Override public void onAccessibilityStateChanged(boolean enabled) { mHandler.onAccessibilityStateChanged(enabled); } public boolean isScheduled() { return mHandler.hasMessages(MSG_HIDE); } private static class HideHandler extends WeakHandler implements AccessibilityStateChangeListener { private boolean mAllowAutoHide; public HideHandler(Looper looper, Runnable hideRunner) { super(looper, hideRunner); } @Override protected void handleMessage(Message msg, @NonNull Runnable runnable) { switch (msg.what) { case MSG_HIDE: if (mAllowAutoHide) { runnable.run(); } break; default: // do nothing } } public void setAllowAutoHide(boolean mAllowAutoHide) { this.mAllowAutoHide = mAllowAutoHide; } @Override public void onAccessibilityStateChanged(boolean enabled) { mAllowAutoHide = !enabled; } } }