MeatPopsicle
MeatPopsicle

Reputation: 992

Android long press system back button listener

I want to add a listener for when the android system back button is long pressed i.e. a long press version of Activity.onBackPressed

This only needs to work when my app is visible.

Chrome shows the history menu when back is long pressed so it must be possible but can't find a hook for it. Thanks

Upvotes: 0

Views: 3904

Answers (4)

haoxiqiang
haoxiqiang

Reputation: 567

Add an implementation of the chromium project.

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    // Detecting a long press of the back button via onLongPress is broken in Android N.
    // To work around this, use a postDelayed, which is supported in all versions.
    if (keyCode == KeyEvent.KEYCODE_BACK) {
        mHandler.postDelayed(mShowHistoryRunnable, ViewConfiguration.getLongPressTimeout());
        return super.onKeyDown(keyCode, event);
    }
    return super.onKeyDown(keyCode, event);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK) {
        mHandler.removeCallbacks(mShowHistoryRunnable);
    }
    return super.onKeyUp(keyCode, event);
}

Upvotes: 0

Angel Koh
Angel Koh

Reputation: 13545

You can look at how firefox implement the Long Back Press.

https://github.com/mozilla-mobile/fenix/blob/master/app/src/main/java/org/mozilla/fenix/HomeActivity.kt

they implement it using both onKeyDown/onKeyUp and onKeyLongPress.

the reason both are used is because

Android N and Huawei devices have broken onKeyLongPress events for the back button, so we instead implement the long press behavior ourselves

  • 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 long press action is run

Below is their implementation.

// See onKeyDown for why this is necessary
private var backLongPressJob: Job? = null

private fun shouldUseCustomBackLongPress(): Boolean {
    val isAndroidN =
        Build.VERSION.SDK_INT == Build.VERSION_CODES.N || Build.VERSION.SDK_INT == Build.VERSION_CODES.N_MR1
    // Huawei devices seem to have problems with onKeyLongPress
    // See https://github.com/mozilla-mobile/fenix/issues/13498
    val isHuawei = Build.MANUFACTURER.equals("huawei", ignoreCase = true)
    return isAndroidN || isHuawei
}

private fun handleBackLongPress(): Boolean {
    supportFragmentManager.primaryNavigationFragment?.childFragmentManager?.fragments?.forEach {
        if (it is OnBackLongPressedListener && it.onBackLongPressed()) {
            return true
        }
    }
    return false
}

final override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
    // Inspired by https://searchfox.org/mozilla-esr68/source/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java#584-613
    // Android N and Huawei devices have broken onKeyLongPress events for the back button, so we
    // instead implement the long press behavior ourselves
    // - 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 long press action is run
    if (shouldUseCustomBackLongPress() && keyCode == KeyEvent.KEYCODE_BACK) {
        backLongPressJob = lifecycleScope.launch {
            delay(ViewConfiguration.getLongPressTimeout().toLong())
            handleBackLongPress()
        }
    }
    return super.onKeyDown(keyCode, event)
}

final override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
    if (shouldUseCustomBackLongPress() && keyCode == KeyEvent.KEYCODE_BACK) {
        backLongPressJob?.cancel()
    }
    return super.onKeyUp(keyCode, event)
}

final override fun onKeyLongPress(keyCode: Int, event: KeyEvent?): Boolean {
    // onKeyLongPress is broken in Android N so we don't handle back button long presses here
    // for N. The version check ensures we don't handle back button long presses twice.
    if (!shouldUseCustomBackLongPress() && keyCode == KeyEvent.KEYCODE_BACK) {
        return handleBackLongPress()
    }
    return super.onKeyLongPress(keyCode, event)
}

Upvotes: 1

DeC
DeC

Reputation: 31

I hope below idea works!!!

Add below code in your activity

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK) {
        //This event will be triggered after 1 second. 
        //In case if you move out of KEYCODE_BACK, onKeyUp event will be triggered and this event will be cancelled 
        handler.postDelayed(mLongPressed, 1000); 
        return true;
    }
    return super.onKeyDown(keyCode, event);
}

@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
    handler.removeCallbacks(mLongPressed);
    return super.onKeyUp(keyCode, event);
}

handler code:

final Handler handler = new Handler();
Runnable mLongPressed = new Runnable() {
    public void run() {
        Log.i("Activity", "Long press detected").
       //Add your code
    }
};

Upvotes: 0

oemel09
oemel09

Reputation: 763

You can try overriding the onKeyLongPress method inside your Activity.

@Override
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK) {
        System.out.println("Back button long pressed");
        return true;
    }
    return super.onKeyLongPress(keyCode, event);
}

Upvotes: 5

Related Questions