/* * Copyright (C) 2015 Google Inc. * * 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.switchaccess; import android.content.Context; import android.content.SharedPreferences; import android.os.Handler; import android.util.Log; import android.view.WindowManager.BadTokenException; import com.android.talkback.R; import com.android.utils.LogUtils; import com.android.utils.SharedPreferencesUtils; /** * Auto-scanning allows the user to control the phone with one button. The user presses the button * to start moving focus around, and presses it again to select the currently focused item. */ public class AutoScanController implements OptionManager.OptionManagerListener { private static final int MILLISECONDS_PER_SECOND = 1000; private final Context mContext; private final Handler mHandler; private final OptionManager mOptionManager; private final Runnable mAutoScanRunnable = new Runnable() { /** * Advances the focus to the next node in the view. If there are no more nodes that can be * clicked or if Auto Scan was disabled, then the scan is stopped */ @Override public void run() { if (!SwitchAccessPreferenceActivity.isAutoScanEnabled(mContext)) { stopScan(); return; } /* * TODO: Option selection should be configurable. This choice mimics * linear scanning */ if (mIsScanInProgress) { try { if (mReverseScan) { mOptionManager.moveToParent(true); } else { mOptionManager.selectOption(OptionManager.OPTION_INDEX_NEXT); } if (mIsScanInProgress) { mHandler.postDelayed(mAutoScanRunnable, getAutoScanDelay()); } } catch (BadTokenException exception) { stopScan(); LogUtils.log(this, Log.DEBUG, "Unable to start scan: %s", exception); } } } }; private boolean mIsScanInProgress; private boolean mReverseScan; public AutoScanController(OptionManager optionManager, Handler handler, Context context) { mOptionManager = optionManager; mOptionManager.addOptionManagerListener(this); mHandler = handler; mContext = context; } /** * Called when auto scan key is pressed */ public void autoScanActivated(boolean reverseScan) { if (!mIsScanInProgress) { startScan(reverseScan); return; } if (mReverseScan != reverseScan) { mReverseScan = reverseScan; return; } /* The user made a selection. Stop moving focus. */ mHandler.removeCallbacks(mAutoScanRunnable); mOptionManager.selectOption(OptionManager.OPTION_INDEX_CLICK); /* Re-start scanning on the updated tree if focus wasn't cleared */ if (mIsScanInProgress) { mHandler.postDelayed(mAutoScanRunnable, getAutoScanDelay()); } } /** * Scanning stops when focus is cleared */ public void onOptionManagerClearedFocus() { stopScan(); } /** * If auto-scan starts, schedule runnable to continue scanning */ public void onOptionManagerStartedAutoScan() { if (SwitchAccessPreferenceActivity.isAutoScanEnabled(mContext) && !mIsScanInProgress) { mIsScanInProgress = true; mReverseScan = false; mHandler.postDelayed(mAutoScanRunnable, getAutoScanDelay()); } } /** * Starts the auto scan if it is not already running * @param reverseScan if true - scanning starts at the last item and moves backward. */ private void startScan(boolean reverseScan) { mIsScanInProgress = true; mReverseScan = reverseScan; mHandler.post(mAutoScanRunnable); } /** * Stops the auto scan if it is currently running */ public void stopScan() { mIsScanInProgress = false; mHandler.removeCallbacks(mAutoScanRunnable); } /** * @return the current auto scan time delay that is selected in the preferences */ private int getAutoScanDelay() { final SharedPreferences prefs = SharedPreferencesUtils.getSharedPreferences(mContext); return (int) (MILLISECONDS_PER_SECOND * SharedPreferencesUtils.getFloatFromStringPref(prefs, mContext.getResources(), R.string.pref_key_auto_scan_time_delay, R.string.pref_auto_scan_time_delay_default_value)); } }