summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGrace Kloba <klobag@google.com>2009-09-18 11:48:29 -0700
committerGrace Kloba <klobag@google.com>2009-09-20 10:21:23 -0700
commit5942df0c38dff7e4335e352e2d03f100b07b8907 (patch)
tree0e6cfeaa8a6c96d05e5f1d56162747ebfbe99f86
parent7d9e4240fd61ccc17797e520b834b3a27c8bf6ad (diff)
downloadpackages_apps_browser-5942df0c38dff7e4335e352e2d03f100b07b8907.zip
packages_apps_browser-5942df0c38dff7e4335e352e2d03f100b07b8907.tar.gz
packages_apps_browser-5942df0c38dff7e4335e352e2d03f100b07b8907.tar.bz2
Handle BACK key at UP in the Browser.
Remove KeyTracker, use KeyEvent instead. Remove ImageGrid and ImageAdapter.
-rw-r--r--src/com/android/browser/ActiveTabsPage.java9
-rw-r--r--src/com/android/browser/BrowserActivity.java135
-rw-r--r--src/com/android/browser/BrowserBookmarksPage.java13
-rw-r--r--src/com/android/browser/ImageAdapter.java265
-rw-r--r--src/com/android/browser/ImageGrid.java232
-rw-r--r--src/com/android/browser/KeyTracker.java107
6 files changed, 67 insertions, 694 deletions
diff --git a/src/com/android/browser/ActiveTabsPage.java b/src/com/android/browser/ActiveTabsPage.java
index 2971e09..e589d42 100644
--- a/src/com/android/browser/ActiveTabsPage.java
+++ b/src/com/android/browser/ActiveTabsPage.java
@@ -68,15 +68,6 @@ public class ActiveTabsPage extends LinearLayout {
});
}
- public boolean dispatchKeyEvent(KeyEvent event) {
- if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
- if (event.isDown()) return true;
- mBrowserActivity.removeActiveTabPage(true);
- return true;
- }
- return super.dispatchKeyEvent(event);
- }
-
/**
* Special class to hold the close drawable. Its sole purpose is to allow
* the parent to be pressed without being pressed itself. This way the line
diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java
index 1730f9b..15772a5 100644
--- a/src/com/android/browser/BrowserActivity.java
+++ b/src/com/android/browser/BrowserActivity.java
@@ -149,8 +149,7 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class BrowserActivity extends Activity
- implements KeyTracker.OnKeyTracker,
- View.OnCreateContextMenuListener,
+ implements View.OnCreateContextMenuListener,
DownloadListener {
/* Define some aliases to make these debugging flags easier to refer to.
@@ -2130,80 +2129,73 @@ public class BrowserActivity extends Activity
}
}
- public KeyTracker.State onKeyTracker(int keyCode,
- KeyEvent event,
- KeyTracker.Stage stage,
- int duration) {
- // if onKeyTracker() is called after activity onStop()
- // because of accumulated key events,
- // we should ignore it as browser is not active any more.
- WebView topWindow = getTopWindow();
- if (topWindow == null && mCustomView == null)
- return KeyTracker.State.NOT_TRACKING;
-
- if (keyCode == KeyEvent.KEYCODE_BACK) {
- // Check if a custom view is currently showing and, if it is, hide it.
- if (mCustomView != null) {
- mWebChromeClient.onHideCustomView();
- return KeyTracker.State.DONE_TRACKING;
- }
- if (stage == KeyTracker.Stage.LONG_REPEAT) {
- bookmarksOrHistoryPicker(true);
- return KeyTracker.State.DONE_TRACKING;
- } else if (stage == KeyTracker.Stage.UP) {
- // FIXME: Currently, we do not have a notion of the
- // history picker for the subwindow, but maybe we
- // should?
- WebView subwindow = mTabControl.getCurrentSubWindow();
- if (subwindow != null) {
- if (subwindow.canGoBack()) {
- subwindow.goBack();
- } else {
- dismissSubWindow(mTabControl.getCurrentTab());
- }
- } else {
- goBackOnePageOrQuit();
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ // The default key mode is DEFAULT_KEYS_SEARCH_LOCAL. As the MENU is
+ // still down, we don't want to trigger the search. Pretend to consume
+ // the key and do nothing.
+ if (mMenuIsDown) return true;
+
+ switch(keyCode) {
+ case KeyEvent.KEYCODE_MENU:
+ mMenuIsDown = true;
+ break;
+ case KeyEvent.KEYCODE_SPACE:
+ // Browser's hidden shortcut key. Don't call super so that
+ // search won't be triggered.
+ return true;
+ case KeyEvent.KEYCODE_BACK:
+ if (event.getRepeatCount() == 0) {
+ event.startTracking();
+ return true;
+ } else if (mCustomView == null && mActiveTabsPage == null
+ && event.isLongPress()) {
+ bookmarksOrHistoryPicker(true);
+ return true;
}
- return KeyTracker.State.DONE_TRACKING;
- }
- return KeyTracker.State.KEEP_TRACKING;
+ break;
}
- return KeyTracker.State.NOT_TRACKING;
+ return super.onKeyDown(keyCode, event);
}
- @Override public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_MENU) {
- mMenuIsDown = true;
- } else if (mMenuIsDown) {
- // The default key mode is DEFAULT_KEYS_SEARCH_LOCAL. As the MENU is
- // still down, we don't want to trigger the search. Pretend to
- // consume the key and do nothing.
- return true;
- }
- boolean handled = mKeyTracker.doKeyDown(keyCode, event);
- if (!handled) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_SPACE:
- if (event.isShiftPressed()) {
- getTopWindow().pageUp(false);
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ switch(keyCode) {
+ case KeyEvent.KEYCODE_MENU:
+ mMenuIsDown = false;
+ break;
+ case KeyEvent.KEYCODE_SPACE:
+ if (event.isShiftPressed()) {
+ getTopWindow().pageUp(false);
+ } else {
+ getTopWindow().pageDown(false);
+ }
+ return true;
+ case KeyEvent.KEYCODE_BACK:
+ if (event.isTracking() && !event.isCanceled()) {
+ if (mCustomView != null) {
+ // if a custom view is showing, hide it
+ mWebChromeClient.onHideCustomView();
+ } else if (mActiveTabsPage != null) {
+ // if tab page is showing, hide it
+ removeActiveTabPage(true);
} else {
- getTopWindow().pageDown(false);
+ WebView subwindow = mTabControl.getCurrentSubWindow();
+ if (subwindow != null) {
+ if (subwindow.canGoBack()) {
+ subwindow.goBack();
+ } else {
+ dismissSubWindow(mTabControl.getCurrentTab());
+ }
+ } else {
+ goBackOnePageOrQuit();
+ }
}
- handled = true;
- break;
-
- default:
- break;
- }
- }
- return handled || super.onKeyDown(keyCode, event);
- }
-
- @Override public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_MENU) {
- mMenuIsDown = false;
+ return true;
+ }
+ break;
}
- return mKeyTracker.doKeyUp(keyCode, event) || super.onKeyUp(keyCode, event);
+ return super.onKeyUp(keyCode, event);
}
/* package */ void stopLoading() {
@@ -4244,11 +4236,6 @@ public class BrowserActivity extends Activity
private boolean mMenuIsDown;
- private final KeyTracker mKeyTracker = new KeyTracker(this);
-
- // As trackball doesn't send repeat down, we have to track it ourselves
- private boolean mTrackTrackball;
-
private static boolean mInTrace;
// Performance probe
diff --git a/src/com/android/browser/BrowserBookmarksPage.java b/src/com/android/browser/BrowserBookmarksPage.java
index c981d7a..b91e322 100644
--- a/src/com/android/browser/BrowserBookmarksPage.java
+++ b/src/com/android/browser/BrowserBookmarksPage.java
@@ -631,13 +631,12 @@ public class BrowserBookmarksPage extends Activity implements
public void deleteBookmark(int position) {
mBookmarksAdapter.deleteRow(position);
}
-
- public boolean dispatchKeyEvent(KeyEvent event) {
- if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.isDown()) {
- setResultToParent(RESULT_CANCELED, null);
- mCanceled = true;
- }
- return super.dispatchKeyEvent(event);
+
+ @Override
+ public void onBackPressed() {
+ setResultToParent(RESULT_CANCELED, null);
+ mCanceled = true;
+ super.onBackPressed();
}
// This Activity is generally a sub-Activity of CombinedHistoryActivity. In
diff --git a/src/com/android/browser/ImageAdapter.java b/src/com/android/browser/ImageAdapter.java
deleted file mode 100644
index f95753a..0000000
--- a/src/com/android/browser/ImageAdapter.java
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Copyright (C) 2008 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.browser;
-
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.database.DataSetObserver;
-import android.graphics.Color;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.LayoutInflater;
-import android.widget.ImageView;
-import android.widget.ListAdapter;
-import android.widget.TextView;
-
-import java.util.ArrayList;
-
-/**
- * Adapter used by ImageGrid.
- */
-public class ImageAdapter implements ListAdapter {
-
- ArrayList<TabControl.Tab> mItems; // Items shown in the grid
- private ArrayList<DataSetObserver> mDataObservers; // Data change listeners
- private Context mContext; // Context to use to inflate views
- private boolean mMaxedOut;
- private ImageGrid mImageGrid;
- private boolean mIsLive;
- private int mTabHeight;
-
- ImageAdapter(Context context, ImageGrid grid, boolean live) {
- mContext = context;
- mIsLive = live;
- mItems = new ArrayList<TabControl.Tab>();
- mImageGrid = grid;
- mDataObservers = new ArrayList<DataSetObserver>();
- }
-
- void heightChanged(int newHeight) {
- mTabHeight = newHeight;
- }
-
- /**
- * Whether the adapter is at its limit, determined by TabControl.MAX_TABS
- *
- * @return True if the number of Tabs represented in this Adapter is at its
- * maximum.
- */
- public boolean maxedOut() {
- return mMaxedOut;
- }
-
- /**
- * Clear the internal WebViews and remove their picture listeners.
- */
- public void clear() {
- mItems.clear();
- notifyObservers();
- }
-
- /**
- * Add a new window web page to the grid
- *
- * @param t The tab to display
- */
- public void add(TabControl.Tab t) {
- if (mMaxedOut) {
- return;
- }
- mItems.add(t);
- notifyObservers();
- if (mItems.size() == TabControl.MAX_TABS) {
- mMaxedOut = true;
- }
- }
-
- /**
- * Remove a window from the list. At this point, the window
- * has already gone. It just needs to be removed from the screen
- *
- * @param index window to remove
- */
- public void remove(int index) {
- if (index >= 0 && index < mItems.size()) {
- mItems.remove(index);
- notifyObservers();
- mMaxedOut = false;
- }
- }
-
- /* (non-Javadoc)
- * @see android.widget.ListAdapter#areAllItemsSelectable()
- */
- public boolean areAllItemsEnabled() {
- return true;
- }
-
- /* (non-Javadoc)
- * @see android.widget.ListAdapter#isSelectable(int)
- */
- public boolean isEnabled(int position) {
- if (position >= 0 && position <= mItems.size()) {
- return true;
- }
- return false;
- }
-
- /* (non-Javadoc)
- * @see android.widget.Adapter#getCount()
- */
- public int getCount() {
- // Include the New Window button if we have not reached the tab limit
- if (!mMaxedOut) {
- return mItems.size()+1;
- }
- return mItems.size();
- }
-
- /* (non-Javadoc)
- * @see android.widget.Adapter#getItem(int)
- */
- public Object getItem(int position) {
- if (!mMaxedOut) {
- if (0 == position) {
- return null;
- }
- return mItems.get(position);
- }
- return mItems.get(position);
- }
-
- /* (non-Javadoc)
- * @see android.widget.Adapter#getItemId(int)
- */
- public long getItemId(int position) {
- return position;
- }
-
- /* (non-Javadoc)
- * @see android.widget.Adapter#getView(int, android.view.View,
- * android.view.ViewGroup)
- */
- public View getView(int position, View convertView, ViewGroup parent) {
- View v = null;
- if (convertView != null) {
- v = convertView;
- } else {
- LayoutInflater factory = LayoutInflater.from(mContext);
- v = factory.inflate(R.layout.tabitem, null);
- }
- FakeWebView img = (FakeWebView) v.findViewById(R.id.icon);
- ImageView close = (ImageView) v.findViewById(R.id.close);
- TextView tv = (TextView) v.findViewById(R.id.label);
-
- // position needs to be in the range of Tab indices.
- if (!mMaxedOut) {
- position--;
- }
-
- // Create the View for actual tabs
- if (position != ImageGrid.NEW_TAB) {
- TabControl.Tab t = mItems.get(position);
- img.setTab(t);
- tv.setText(t.getTitle());
- // Do not put the 'X' if the tab picker isn't "live" (meaning the
- // user cannot click on a tab)
- if (!mIsLive) {
- close.setVisibility(View.GONE);
- } else {
- close.setVisibility(View.VISIBLE);
- final int pos = position;
- close.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- ImageAdapter.this.confirmClose(pos);
- }
- });
- }
- } else {
- img.setBackgroundColor(Color.BLACK);
- img.setImageResource(R.drawable.ic_new_window);
- img.setScaleType(ImageView.ScaleType.CENTER);
- img.setPadding(0, 0, 0, 34);
- tv.setText(R.string.new_window);
- close.setVisibility(View.GONE);
- }
- ViewGroup.LayoutParams lp = img.getLayoutParams();
- if (lp.height != mTabHeight) {
- lp.height = mTabHeight;
- img.requestLayout();
- }
- return v;
- }
-
- /*
- * Pop a confirmation dialog to the user asking if they want to close this
- * tab.
- */
- private void confirmClose(final int position) {
- final ImageGrid.Listener l = mImageGrid.getListener();
- if (l == null) {
- return;
- }
- l.remove(position);
- }
-
- /* (non-Javadoc)
- * @see android.widget.Adapter#registerDataSetObserver(android.database.DataSetObserver)
- */
- public void registerDataSetObserver(DataSetObserver observer) {
- mDataObservers.add(observer);
- }
-
- /* (non-Javadoc)
- * @see android.widget.Adapter#hasStableIds()
- */
- public boolean hasStableIds() {
- return true;
- }
-
- /* (non-Javadoc)
- * @see android.widget.Adapter#unregisterDataSetObserver(android.database.DataSetObserver)
- */
- public void unregisterDataSetObserver(DataSetObserver observer) {
- mDataObservers.remove(observer);
- }
-
- /**
- * Notify all the observers that a change has happened.
- */
- void notifyObservers() {
- for (DataSetObserver observer : mDataObservers) {
- observer.onChanged();
- }
- }
-
- public int getItemViewType(int position) {
- return 0;
- }
-
- public int getViewTypeCount() {
- return 1;
- }
-
- public boolean isEmpty() {
- return getCount() == 0;
- }
-}
diff --git a/src/com/android/browser/ImageGrid.java b/src/com/android/browser/ImageGrid.java
deleted file mode 100644
index 9967f36..0000000
--- a/src/com/android/browser/ImageGrid.java
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Copyright (C) 2008 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.browser;
-
-import android.content.Context;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.KeyEvent;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.View.OnCreateContextMenuListener;
-import android.webkit.WebView;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.GridView;
-
-/**
- * This class implements a Grid layout of Views for the Tab picker.
- */
-class ImageGrid extends GridView implements OnItemClickListener,
- OnCreateContextMenuListener {
-
- private Listener mListener;
- private ImageAdapter mAdapter;
- private boolean mIsLive;
- private static final int SPACING = 10;
- public static final int CANCEL = -99;
- public static final int NEW_TAB = -1;
-
- /**
- * Constructor
- * @param context Context to use when inflating resources.
- * @param live TRUE if the view can accept touch or click
- * @param l Listener to respond to clicks etc.
- */
- public ImageGrid(Context context, boolean live, Listener l) {
- super(context);
-
- mIsLive = live;
- if (live) {
- setFocusable(true);
- setFocusableInTouchMode(true);
- setOnItemClickListener(this);
- setOnCreateContextMenuListener(this);
- }
- mListener = l;
-
- mAdapter = new ImageAdapter(context, this, live);
- setAdapter(mAdapter);
-
- setBackgroundColor(0xFF000000);
-
- setVerticalSpacing(SPACING);
- setHorizontalSpacing(SPACING);
- setNumColumns(2);
- setStretchMode(GridView.STRETCH_COLUMN_WIDTH);
- setSelector(android.R.drawable.gallery_thumb);
- }
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- // We always consume the BACK key even if mListener is null or the
- // ImageGrid is not "live." This prevents crashes during tab animations
- // if the user presses BACK.
- if ((event.getAction() == KeyEvent.ACTION_DOWN) &&
- (event.getKeyCode() == KeyEvent.KEYCODE_BACK)) {
- if (mListener != null && mIsLive) {
- mListener.onClick(CANCEL);
- invalidate();
- }
- return true;
- }
- return super.dispatchKeyEvent(event);
- }
-
- /**
- * Called by BrowserActivity to add a new window to the tab picker.
- * This does not happen dynamically, this only happens during view
- * setup.
- *
- * @param v Webview of the tab to add
- * @param name Web page title
- * @param url URL of the webpage
- */
- public void add(TabControl.Tab t) {
- mAdapter.add(t);
- }
-
- /**
- * Called by BrowserActivity when a window has been removed from the
- * tab list.
- *
- * @param index Window to remove, from 0 to MAX_TABS-1
- */
- public void remove(int index) {
- if (Browser.DEBUG && (index < 0 || index >= TabControl.MAX_TABS)) {
- throw new AssertionError();
- }
- mAdapter.remove(index);
- }
-
- /**
- * Request focus to initially set to a particular tab.
- *
- * @param startingIndex This is a Tab index from 0 - MAX_TABS-1 and does not
- * include the "New Tab" cell.
- */
- public void setCurrentIndex(int startingIndex) {
- if (!mAdapter.maxedOut()) {
- startingIndex++;
- }
- setSelection(startingIndex);
- }
-
- public Listener getListener() {
- return mListener;
- }
-
- public void setListener(Listener l) {
- mListener = l;
- }
-
- /**
- * Return true if the ImageGrid is live. This means that tabs can be chosen
- * and the menu can be invoked.
- */
- public boolean isLive() {
- return mIsLive;
- }
-
- /**
- * Do some internal cleanup of the ImageGrid's adapter.
- */
- public void clear() {
- mAdapter.clear();
- }
-
- /* (non-Javadoc)
- * @see android.widget.AdapterView.OnItemClickListener#onItemClick(android.widget.AdapterView, android.view.View, int, long)
- */
- public void onItemClick(AdapterView parent, View v, int position, long id) {
- if (!mAdapter.maxedOut()) {
- position--;
- }
- // Position will be -1 for the "New Tab" cell.
- if (mListener != null) {
- mListener.onClick(position);
- }
- }
-
- /* (non-Javadoc)
- * @see android.view.View.OnCreateContextMenuListener#onCreateContextMenu(android.view.ContextMenu, android.view.View, java.lang.Object)
- */
- public void onCreateContextMenu(ContextMenu menu, View v,
- ContextMenuInfo menuInfo) {
- // Do not create the context menu if there is no listener or the Tab
- // overview is not "live."
- if (mListener == null || !mIsLive) {
- return;
- }
- AdapterView.AdapterContextMenuInfo info =
- (AdapterView.AdapterContextMenuInfo) menuInfo;
- boolean maxed = mAdapter.maxedOut();
- if (info.position > 0 || maxed) {
- MenuInflater inflater = new MenuInflater(mContext);
- inflater.inflate(R.menu.tabscontext, menu);
- int position = info.position;
- if (!maxed) {
- position--;
- }
- menu.setHeaderTitle(mAdapter.mItems.get(position).getTitle());
- }
- }
-
- // convert a context menu position to an actual tab position. Since context
- // menus are not created for the "New Tab" cell, this will always return a
- // valid tab position.
- public int getContextMenuPosition(MenuItem menu) {
- AdapterView.AdapterContextMenuInfo info =
- (AdapterView.AdapterContextMenuInfo) menu.getMenuInfo();
- int pos = info.position;
- if (!mAdapter.maxedOut()) {
- pos--;
- }
- return pos;
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- // Called when our orientation changes. Tell the adapter about the new
- // size. Compute the individual tab height by taking the grid height
- // and subtracting the SPACING. Then subtract the list padding twice
- // (once for each tab on screen) and divide the remaining height by 2.
- int tabHeight = (h - SPACING
- - 2 * (getListPaddingTop() + getListPaddingBottom())) / 2;
- mAdapter.heightChanged(tabHeight);
- super.onSizeChanged(w, h, oldw, oldh);
- }
-
- /**
- * Listener to be notified by behavior of ImageGrid.
- */
- public interface Listener {
- /**
- * Called when enter is pressed on the list.
- * @param position The index of the selected image when
- * enter is pressed.
- */
- void onClick(int position);
-
- /**
- * Called when remove is called on the grid.
- */
- void remove(int position);
- }
-
-}
diff --git a/src/com/android/browser/KeyTracker.java b/src/com/android/browser/KeyTracker.java
deleted file mode 100644
index 344e4f8..0000000
--- a/src/com/android/browser/KeyTracker.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2006 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.browser;
-
-import android.view.KeyEvent;
-import android.view.ViewConfiguration;
-
-class KeyTracker {
-
- public enum Stage {
- DOWN, //!< the key has just been pressed
- SHORT_REPEAT, //!< repeated key, but duration is under the long-press threshold
- LONG_REPEAT, //!< repeated key, but duration is over the long-press threshold
- UP //!< the key is being released
- }
-
- public enum State {
- KEEP_TRACKING, //!< return this to continue to track the key
- DONE_TRACKING, //!< return this if you handled the key, but need not track it anymore
- NOT_TRACKING //!< return this if you will not handle this key
- }
-
- public interface OnKeyTracker {
-
- /** Called whenever there is a key event [down, short/long repeat, up]
- @param keyCode The current keyCode (see KeyEvent class)
- @param msg The message associated with the keyCode
- @maram stage The state the key press is in [down, short/long repeat, up]
- @param duration The number of milliseconds since this key was initially pressed
- @return your state after seeing the key. If you return DONE_TRACKING or NOT_TRACKING,
- you will not be called again for the lifetime of this key event.
- */
- public State onKeyTracker(int keyCode, KeyEvent event, Stage stage, int duration);
- }
-
- public KeyTracker(OnKeyTracker tracker) {
- mTracker = tracker;
- }
-
- public boolean doKeyDown(int keyCode, KeyEvent event) {
- long now = System.currentTimeMillis();
- Stage stage = null;
-
- // check if its a new/different key
- if (mKeyCode != keyCode || event.getRepeatCount() == 0) {
- mKeyCode = keyCode;
- mStartMS = now;
- stage = Stage.DOWN;
- }
- else if (mState == State.KEEP_TRACKING) {
- stage = (now - mStartMS) >= LONG_PRESS_DURATION_MS ? Stage.LONG_REPEAT : Stage.SHORT_REPEAT;
- }
-
- if (stage != null) {
- mEvent = event;
- callTracker(stage, now);
- }
-
- return mState != State.NOT_TRACKING;
- }
-
- public boolean doKeyUp(int keyCode, KeyEvent event) {
- boolean handled = false;
-
- if (mState == State.KEEP_TRACKING && mKeyCode == keyCode) {
- mEvent = event;
- callTracker(Stage.UP, System.currentTimeMillis());
- handled = mState != State.NOT_TRACKING;
- }
- mKeyCode = NOT_A_KEYCODE;
- return handled;
- }
-
- private void callTracker(Stage stage, long now) {
- mState = mTracker.onKeyTracker(mKeyCode, mEvent, stage, (int)(now - mStartMS));
- }
-
- private void dump() {
- System.out.println(" key=" + mKeyCode + " dur=" + (System.currentTimeMillis() - mStartMS) +
- " state=" + mState);
- }
-
- private int mKeyCode = NOT_A_KEYCODE;
- private KeyEvent mEvent;
- private long mStartMS;
- private State mState;
- private OnKeyTracker mTracker;
-
- private static final int LONG_PRESS_DURATION_MS =
- ViewConfiguration.getLongPressTimeout();
- private static final int NOT_A_KEYCODE = -123456;
-}
-