Xamarin Android: Handle Hardware Key in Spinner Dropdown

I've got an Android application written using Xamarin Android (not Xamarin Forms). It runs on a Zebra WT6000, which has hardware keys "P1" and "P2". By default, these are mapped to volume-down and volume-up (respectively).

Within my application, I use these keys for other things (and provide an alternative way for the user to manage audio volume). This all works as intended.

My problem is that I have a spinner (Android.Widget.Spinner), and when the spinner is tapped and the dropdown appears, the default button mappings come back in force, ignoring the key handlers in my activity.

I have tried this:

MySpinner.KeyPress += (sender, evt) => { /* do a thing */ };

and also:

MySpinner.SetOnKeyListener(new KeyListener());
...
private class KeyListener : Java.Lang.Object, View.IOnKeyListener
{
    public bool OnKey(View v, [GeneratedEnum] Keycode keyCode, KeyEvent e)
    {
        // do a thing
        return true;
    }
}

However, neither my lambda function nor my OnKey() method ever get called, and the key handling doesn't change.

I suspect that the spinner's dropdown is its own DialogFragment (with it's own key handling) rather than part of my activity. If so, I suspect I have to call the SetOnKeyListener() of that DialogFragment (rather than the SetOnKeyListener() of the spinner).

Any suggestions would be most welcome.

1 answer

  • answered 2018-11-05 23:28 Douglas Henke

    I found a way to do this (and by "way to do this" I mean "kludge"). The basic idea is that I have my own custom array adapter (derived from ArrayAdapter) to build the spinner rows. In its GetDropDownView() override, I set the KeyPress handler of the parent (where said parent is passed in as an argument).

    Code:

    public class CustomArrayAdapter<T> : ArrayAdapter<T>
    {
        private bool ParentKeyHandlerHasBeenSet;
        ...
        public override View GetDropDownView(int position, View convertView, ViewGroup parent)
        {
            if (!ParentKeyHandlerHasBeenSet && parent.Id == -1)
            {
                parent.KeyPress += (sender, evt) => { evt.Handled = true; };
                ParentKeyHandlerHasBeenSet = true;
            }
    
            return MyPrivateMethodThatBuildsTheView(...);
         }
    }
    

    That's obviously not a lovely, clean solution. If you have a better one, please share.