31

I know how to take control of the back button. I have a VideoView embedded in a FrameLayout. My question is when the video pops up, the video controls are present for a few seconds. Hitting the back button while they are visible hides the video controls. Is there a way to ignore that function and do the next back action as if the video controls weren't visible?

The reason I ask is if I really do want to go back, I must hit the back button twice; once to hide the controls and second to actually go back

Ronnie
  • 11,138
  • 21
  • 78
  • 140

5 Answers5

34

Based on the source code, this should work:

  1. Extend MediaController (for the purposes of this answer, call it RonnieMediaController)
  2. Override dispatchKeyEvent() in RonnieMediaController
  3. Before chaining to the superclass, check for KeyEvent.KEYCODE_BACK, and if that is encountered, tell your activity to finish()
  4. Use RonnieMediaController instead of MediaController with your VideoView

Personally, I'd just leave it alone, as with this change your user cannot make a RonnieMediaController disappear on demand.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Thanks for the reply. I want to at least give it a try to see what it looks like. I have this so far: http://pastie.org/1924377 and I am seeing "back btn hit" in my LogCat so that is working. The part I am having trouble on is calling `finish()` ...since I am not extending `Activity`, `finish()` isn't available to me – Ronnie May 18 '11 at 23:51
  • @Ronnie: `MediaController` inherits from `View`, so `getContext()` should return your `Activity`. – CommonsWare May 18 '11 at 23:55
  • So this is how I assume you would use `getContext()` but it isn't working. `Context c = getContext(); c.finish();` It is saying `finish() is undefined for Context` – Ronnie May 20 '11 at 16:34
  • @Ronnie: You have to cast the `Context` to be an `Activity`. – CommonsWare May 20 '11 at 16:41
  • got it! Thanks that worked. You were right thought, I don't really like the way it functions now. Its was better originally like you said. Thanks again. – Ronnie May 20 '11 at 16:54
  • @CommonsWare yes it works: if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) ((Activity) getContext()).finish(); then I return true, else super.dispatchevent – sherpya Jan 24 '12 at 05:05
  • @CommonsWare: I have a somewhat similar problem with MediaController. Can you please take a look? http://stackoverflow.com/questions/22269880/why-mediacontroller-prevents-my-onkeyup-commands-to-run – Behnam Mar 08 '14 at 13:45
  • @CommonsWare : I tried the way as you mentioned. But for me, back button is working only when I play the video for about 3 seconds. Also back button is working before the video is set. If am not playing the video, back button won't work. – Anooj Krishnan G Apr 05 '16 at 10:11
  • This solution doesn't work for me, dispatchKeyEvent is not even triggered on Back button click. I use a S8+ with API 28 software. – Harsha Vardhan Sep 21 '19 at 10:26
  • Excellent, working like charm – Shailendra Madda Apr 29 '22 at 19:04
18

You can simply write:

mVideoView.setMediaController(new MediaController(this){
        public boolean dispatchKeyEvent(KeyEvent event)
        {
            if (event.getKeyCode() == KeyEvent.KEYCODE_BACK)
                ((Activity) getContext()).finish();

            return super.dispatchKeyEvent(event);
        }
    });

No need to create new class.

Serge Him
  • 936
  • 6
  • 8
  • 1
    If the event is called twice on backbuttonpress you could add this filter inside the first if condition: if (event.getAction() == KeyEvent.ACTION_UP){..} – Jasper Jan 06 '15 at 18:52
  • This is the best solution if you're already extending something, as you can only do one extension. – Riot Goes Woof Jun 23 '15 at 15:04
15

The previous solutions no longer work with Android Pie +, you must instead :

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        mediaController.addOnUnhandledKeyEventListener((v, event) -> {
            //Handle BACK button
            if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP)
            {
                mediaController.hide(); //Hide mediaController,according to your needs, you can also called here onBackPressed() or finish() 
            }
            return true;
        });
    }
Didier116
  • 151
  • 1
  • 3
  • 2
    Not only the accepted solution now not work, Android even refuse to hide the media controller when tab back, that means while media controller is showing, nothing happens no matter how many times you tab the back button. – Antony Ng Oct 13 '21 at 04:44
6

You can also have the Activity handle the event:

mVideoView.setMediaController(new MediaController(this){
    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK ) {
            if (event.getAction() == KeyEvent.ACTION_DOWN) {
                return true;
            } else if (event.getAction() == KeyEvent.ACTION_UP) {
                ((Activity) getContext()).onBackPressed();
                return true;
            }
        }
        return super.dispatchKeyEvent(event);
    }       
});

Then handle it in your Activity:

@Override
public void onBackPressed() {
    // clean up or send result here
    finish();
}
Greg T
  • 3,278
  • 3
  • 37
  • 39
0

In Xamarin.Android, you can deal with this problem like this

public class CustomMediaController : MediaController
    {
        private FragmentActivity act;
        public CustomMediaController(Context context, FragmentActivity myActivity) : base(context)
        {
            act = myActivity;
        }
        public override bool DispatchKeyEvent(KeyEvent e)
        {
            if(e.KeyCode == Keycode.Back)
            {
                act.OnBackPressed();
            }
            return base.DispatchKeyEvent(e);
        }
    }