Bug 1304688 - Implement long-press timer to workaround broken onKeyLongPress on Android N r?sebastian
Note: we also change the return value of a long-press when the tab history fragment is showing:
we want to completely ignore long-presses in this case, previously we used to return false in this
case, which suggests that we didn't handle the event - however we explicitly consider this a no-op,
so should return a value reflecting that (in reality: no one else handles the long-press, so this
makes no effective difference).
MozReview-Commit-ID: FYrCVsNHfjv
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -154,16 +154,17 @@ import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.SubMenu;
import android.view.View;
+import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewStub;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.animation.Interpolator;
import android.widget.Button;
import android.widget.ListView;
import android.widget.RelativeLayout;
@@ -544,26 +545,54 @@ public class BrowserApp extends GeckoApp
mFindInPageBar.show();
return true;
}
}
return false;
}
+ private Runnable mCheckLongPress;
+ {
+ // Only initialise the runnable if we are >= N.
+ // See onKeyDown() for more details of the back-button long-press workaround
+ if (!Versions.preN) {
+ mCheckLongPress = new Runnable() {
+ public void run() {
+ handleBackLongPress();
+ }
+ };
+ }
+ }
+
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
+ // Bug 1304688: Android N has broken passing onKeyLongPress events for the back button, so we
+ // instead copy the long-press-handler technique from Android's KeyButtonView.
+ // - For short presses, we cancel the callback in onKeyUp
+ // - For long presses, the normal keypress is marked as cancelled, hence won't be handled elsewhere
+ // (but Android still provides the haptic feedback), and the runnable is run.
+ if (!Versions.preN) {
+ ThreadUtils.getUiHandler().removeCallbacks(mCheckLongPress);
+ ThreadUtils.getUiHandler().postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
+ }
+
if (!mBrowserToolbar.isEditing() && onKey(null, keyCode, event)) {
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (!Versions.preN &&
+ keyCode == KeyEvent.KEYCODE_BACK) {
+ ThreadUtils.getUiHandler().removeCallbacks(mCheckLongPress);
+ }
+
if (AndroidGamepadManager.handleKeyEvent(event)) {
return true;
}
return super.onKeyUp(keyCode, event);
}
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -3868,31 +3897,47 @@ public class BrowserApp extends GeckoApp
titleString = R.string.exit_guest_session_title;
msgString = R.string.exit_guest_session_text;
}
ps.show(res.getString(titleString), res.getString(msgString), null, ListView.CHOICE_MODE_NONE);
}
/**
+ * Handle a long press on the back button
+ */
+ private boolean handleBackLongPress() {
+ // If the tab search history is already shown, do nothing.
+ TabHistoryFragment frag = (TabHistoryFragment) getSupportFragmentManager().findFragmentByTag(TAB_HISTORY_FRAGMENT_TAG);
+ if (frag != null) {
+ return true;
+ }
+
+ Tab tab = Tabs.getInstance().getSelectedTab();
+ if (tab != null && !tab.isEditing()) {
+ return tabHistoryController.showTabHistory(tab, TabHistoryController.HistoryAction.ALL);
+ }
+
+ return false;
+ }
+
+ /**
* This will detect if the key pressed is back. If so, will show the history.
*/
@Override
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK) {
- // If the tab search history is already shown, do nothing.
- TabHistoryFragment frag = (TabHistoryFragment) getSupportFragmentManager().findFragmentByTag(TAB_HISTORY_FRAGMENT_TAG);
- if (frag != null) {
- return false;
+ // onKeyLongPress is broken in Android N, see onKeyDown() for more information. We add a version
+ // check here to match our fallback code in order to avoid handling a long press twice (which
+ // could happen if newer versions of android and/or other vendors were to fix this problem).
+ if (Versions.preN &&
+ keyCode == KeyEvent.KEYCODE_BACK) {
+ if (handleBackLongPress()) {
+ return true;
}
- Tab tab = Tabs.getInstance().getSelectedTab();
- if (tab != null && !tab.isEditing()) {
- return tabHistoryController.showTabHistory(tab, TabHistoryController.HistoryAction.ALL);
- }
}
return super.onKeyLongPress(keyCode, event);
}
/*
* If the app has been launched a certain number of times, and we haven't asked for feedback before,
* open a new tab with about:feedback when launching the app from the icon shortcut.
*/