Instrumentation.invokeMenuActionSync()无法在较旧的Android设备上运行(API10)

时间:2014-04-12 12:39:25

标签: android android-testing android-instrumentation

我的Android应用程序上有一些入侵测试,我想测试我的Activity的onOptionsItemSelected()方法。

为此,我使用了仪器的invokeMenuActionSync方法:

这适用于较新版本的Android,但似乎不会导致onOptionsItemSelected()方法在旧版本上调用(例如API10)。

我尝试过与其他方法结合使用:

if (getInstrumentation().invokeMenuActionSync(activity, R.id.menu_refresh, 0 /* flags */) ||
    getInstrumentation().invokeContextMenuAction(activity, R.id.menu_refresh, 0 /* flags */)) {
   // verify 
}

没有变化。

我正在使用AppCompat ActionBar。

是否有更好的方法可以始终调用它,或者我可以在较旧的API级别上使用并在两者之间切换的方法?

1 个答案:

答案 0 :(得分:0)

我发现使用检测类调用支持菜单的唯一方法是使用丑陋的反射代码 (可能不需要“init”部分中的某个字段和类,抱歉,我也将它们用于其他代码)

// support part
private static Class<?> actionBarActivitySupportClass;  
private static Field mImplField;
private static Class<?> actionBarActivityDelegateBaseClass;
private static Field mActionModeSupportField;
private static Class<?> actionModeSupportImplClass;
private static Field mMenuActionModeSupportField;
private static Class<?> menuBuilderSupportClass;
private static Field mVisibleItemsSupportField;
private static Field mCallbackActionModeSupportField;
private static Class<?> callbackWrapperSupportClass;
private static Field mWrappedSupportField;
private static Method onMenuItemSelectedSupportmethod;
private static Field mActionBarSupportView; 
private static Class<?> actionBarViewSupportClass;
private static Field mOptionMenuSupportField;
private static Method dispatchMenuItemSelected;

static {
    init();
}

private static void init() {
    try {
        actionBarActivitySupportClass = Class.forName("android.support.v7.app.ActionBarActivity"); //$NON-NLS-1$
        mImplField = actionBarActivitySupportClass.getDeclaredField("mImpl"); //$NON-NLS-1$
        mImplField.setAccessible(true);
        actionBarActivityDelegateBaseClass = Class.forName("android.support.v7.app.ActionBarActivityDelegateBase"); //$NON-NLS-1$
        mActionModeSupportField = actionBarActivityDelegateBaseClass.getDeclaredField("mActionMode"); //$NON-NLS-1$
        mActionModeSupportField.setAccessible(true);
        actionModeSupportImplClass = Class.forName("android.support.v7.app.ActionBarImplBase$ActionModeImpl"); //$NON-NLS-1$
        mMenuActionModeSupportField = actionModeSupportImplClass.getDeclaredField("mMenu"); //$NON-NLS-1$
        mMenuActionModeSupportField.setAccessible(true);
        menuBuilderSupportClass = Class.forName("android.support.v7.internal.view.menu.MenuBuilder"); //$NON-NLS-1$
        mVisibleItemsSupportField = menuBuilderSupportClass.getDeclaredField("mVisibleItems"); //$NON-NLS-1$
        mVisibleItemsSupportField.setAccessible(true);
        mCallbackActionModeSupportField = actionModeSupportImplClass.getDeclaredField("mCallback");  //$NON-NLS-1$
        mCallbackActionModeSupportField.setAccessible(true);
        callbackWrapperSupportClass = Class.forName("android.support.v7.app.ActionBarActivityDelegateBase$ActionModeCallbackWrapper"); //$NON-NLS-1$
        mWrappedSupportField = callbackWrapperSupportClass.getDeclaredField("mWrapped"); //$NON-NLS-1$
        mWrappedSupportField.setAccessible(true);
        onMenuItemSelectedSupportmethod = actionModeSupportImplClass.getDeclaredMethod("onMenuItemSelected", new Class[]{menuBuilderSupportClass,MenuItem.class}); //$NON-NLS-1$
        onMenuItemSelectedSupportmethod.setAccessible(true);
        mActionBarSupportView = actionBarActivityDelegateBaseClass.getDeclaredField("mActionBarView"); //$NON-NLS-1$
        mActionBarSupportView.setAccessible(true);
        actionBarViewSupportClass = Class.forName("android.support.v7.internal.widget.ActionBarView");  //$NON-NLS-1$
        mOptionMenuSupportField = actionBarViewSupportClass.getDeclaredField("mOptionsMenu"); //$NON-NLS-1$
        mOptionMenuSupportField.setAccessible(true);
        dispatchMenuItemSelected = menuBuilderSupportClass.getDeclaredMethod("dispatchMenuItemSelected", new Class[]{menuBuilderSupportClass,MenuItem.class}); //$NON-NLS-1$
        dispatchMenuItemSelected.setAccessible(true);
    } catch (ClassNotFoundException e) {
        System.out.println("support class not loaded "+e.getMessage()); //$NON-NLS-1$
    } catch (SecurityException e) {
        System.out.println("support class not loaded "+e.getMessage()); //$NON-NLS-1$
    } catch (NoSuchFieldException e) {
        System.out.println("support class not loaded "+e.getMessage()); //$NON-NLS-1$
    } catch (NoSuchMethodException e) {
        System.out.println("support class not loaded "+e.getMessage()); //$NON-NLS-1$
    }

}

public static void invokeMenu(Instrumentation instrumentation,final Activity activity,final Object item) {
    if ((mImplField != null) && (actionBarActivitySupportClass != null) && (actionBarActivitySupportClass.isInstance(activity)) 
            && (mActionBarSupportView != null) && (mOptionMenuSupportField != null) && (dispatchMenuItemSelected != null)) { 
        activity.runInUiThread(new Runnable() {
            @Override
            public void run() {
                try {
                    Object actionBarActivityDelegateBase = mImplField.get(activity);                
                    if (actionBarActivityDelegateBase != null) {
                        Object actionBarView = mActionBarSupportView.get(actionBarActivityDelegateBase);
                        if (actionBarView != null) {
                            Object mOptionMenu = mOptionMenuSupportField.get(actionBarView);                        
                            dispatchMenuItemSelected.invoke(mOptionMenu, new Object[]{mOptionMenu,item});                       
                        }
                    }                       
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        });
    } else {
        // good old classic way
        instrumentation.invokeMenuActionSync(activity, ((MenuItem)item).getItemId(), 0);
    }

}