appcompat v21 throws java.lang.UnsupportedOperationException
Asked Answered
P

4

10

After updating my project to use the appcompat library to version 21.0.0 I have a problem with a context menu created with a gridview multichoice modal event. The same code works nice with appcompat v20.

This is the relevant part of the main activity:

public class MainActivity extends android.support.v7.app.ActionBarActivity 
    implements AbsListView.MultiChoiceModeListener {

    ...
    mGridView.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE_MODAL);
    mGridView.setMultiChoiceModeListener(this);

    @Override
    public boolean onCreateActionMode(final ActionMode mode, final Menu menu) {
        mode.setTitle("Started");
        mode.getMenuInflater().inflate(R.menu.context_menu, menu);
        return true;
    }
}

and this is the context_menu.xml:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/menu_item_share"
        android:title="Share..."
        app:showAsAction="ifRoom"
        android:icon="@android:drawable/ic_menu_share"
        app:actionProviderClass="android.support.v7.widget.ShareActionProvider" />
</menu>

And this is the stacktrace I'm getting back:

java.lang.UnsupportedOperationException: This is not supported, use MenuItemCompat.setActionProvider()
        at android.support.v7.internal.view.menu.MenuItemImpl.setActionProvider(MenuItemImpl.java:628)
        at android.support.v7.internal.view.menu.MenuItemWrapperICS.setSupportActionProvider(MenuItemWrapperICS.java:315)
        at android.support.v4.view.MenuItemCompat.setActionProvider(MenuItemCompat.java:345)
        at android.support.v7.internal.view.SupportMenuInflater$MenuState.setItem(SupportMenuInflater.java:473)
        at android.support.v7.internal.view.SupportMenuInflater$MenuState.addSubMenuItem(SupportMenuInflater.java:485)
        at android.support.v7.internal.view.SupportMenuInflater.parseMenu(SupportMenuInflater.java:194)
        at android.support.v7.internal.view.SupportMenuInflater.inflate(SupportMenuInflater.java:118)
        at creativesdk.adobe.com.myapplication.MainActivity.onCreateActionMode(MainActivity.java:71)
        at android.widget.AbsListView$MultiChoiceModeWrapper.onCreateActionMode(AbsListView.java:6165)
        at android.support.v7.internal.view.SupportActionModeWrapper$CallbackWrapper.onCreateActionMode(SupportActionModeWrapper.java:151)
        at android.support.v7.app.ActionBarActivityDelegateBase$ActionModeCallbackWrapper.onCreateActionMode(ActionBarActivityDelegateBase.java:1367)
        at android.support.v7.internal.app.WindowDecorActionBar$ActionModeImpl.dispatchOnCreate(WindowDecorActionBar.java:1012)
        at android.support.v7.internal.app.WindowDecorActionBar.startActionMode(WindowDecorActionBar.java:510)
        at android.support.v7.app.ActionBarActivityDelegateBase.startSupportActionMode(ActionBarActivityDelegateBase.java:576)
        at android.support.v7.app.ActionBarActivityDelegateHC.startActionModeForChild(ActionBarActivityDelegateHC.java:62)
        at android.support.v7.internal.widget.NativeActionModeAwareLayout.startActionModeForChild(NativeActionModeAwareLayout.java:44)
        at android.view.ViewGroup.startActionModeForChild(ViewGroup.java:694)
        at android.view.View.startActionMode(View.java:4857)
        at android.widget.AbsListView.performLongPress(AbsListView.java:3102)
        at android.widget.AbsListView$CheckForLongPress.run(AbsListView.java:3061)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5221)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

I'm curious to know if anybody found the same problem and if there's a way around it.

Palatalized answered 20/10, 2014 at 18:29 Comment(0)
W
9

There is indeed an issue on ICS devices when trying to inflate the menu item from the ActionMode with AppCompat v21. It seems the menu items are wrapped 2 times and a wrapped item method gets called instead of the native one, causing this Exception.

Google needs to fix this in a future version of AppCompat.

Anyway, here's a hack I implemented to make it work with the current release:

1) Create an utility class in the package android.support.v7.internal.view.menu (using this package is mandatory to allow accessing package-protected methods without using reflection):

package android.support.v7.internal.view.menu;

import android.view.Menu;

/**
 * Hack to allow inflating ActionMode menus on Android 4.0.x with AppCompat v21
 */
public class MenuUnwrapper {

    public static Menu unwrap(Menu menu) {
        if (menu instanceof MenuWrapperICS) {
            return ((MenuWrapperICS) menu).getWrappedObject();
        }
        return menu;
    }
}

2) Inflate your menu like this:

@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
    mode.getMenuInflater().inflate(R.menu.context_menu, MenuUnwrapper.unwrap(menu));
    return true;
}

EDIT:

The bug has been fixed in AppCompat v21.0.2 and this hack is no longer necessary.

Update your tools.

Wreak answered 6/11, 2014 at 14:54 Comment(4)
Tried this solution but didn't work for me. The problem is that mode.getMenuInflater() still returns a android.support.v7.internal.view.SupportMenuInflater that inflates MenuItemWrapperICS items. Any ideas?Pape
It took me a while but I found out what was going on. I also add to unwrap the menu on onPrepareActionMode. Hope it helps someone. Thanks.Pape
Yes, you need to unwrap the menu in every method where you need to inflate items in it. The problem is that somewhere in the AppCompat code, the menu is wrapped when it should not, and later you get this invalid menu back in each callback. Do you confirm you had the issue on a 4.0.x (Ice Cream Sandwich) device and not on Jellybean or KitKat ? Happy this helped you!Wreak
Yes. It seems to be ICS only. Thanks a lot again, I don't think I wouldn't have found this by myself.Pape
R
4

Try this. It worked to me.

MenuItem menuItem =  menu.findItem(R.id.search);
if (menuItem != null) {
    MenuItemCompat.setOnActionExpandListener(menuItem,this);
    MenuItemCompat.setActionView(menuItem, mSearchView);
}
Rangoon answered 3/12, 2014 at 12:34 Comment(0)
A
3

Try this

inflater.inflate(R.menu.menu, menu);

// search
MenuItem item = menu.findItem(R.id.settings_search);
MenuItemCompat.setOnActionExpandListener(
    item, new MenuItemCompat.OnActionExpandListener() {

    @Override
    public boolean onMenuItemActionExpand(MenuItem item) {
       return true;
    }

    @Override
    public boolean onMenuItemActionCollapse(MenuItem item) {
        return true;
    }
});
Auk answered 9/7, 2015 at 13:20 Comment(1)
This appears to be the correct answer. The exception is telling you to use a static method of the MenuItemCompat class.Froward
E
0
@Override
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            Log.d(TAG, "onCreateActionMode");

            MenuItem item = menu.findItem(R.id.menu_item_share);
            mShareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(item);
            MenuItemCompat.setActionProvider(item, mShareActionProvider);

            return true;
        }
Echinoderm answered 10/2, 2016 at 14:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.