Saturday, 30 March 2019

Window.Callback is overwritten by Toolbar

I found that in setActionBar method from Activity:

public void setActionBar(@Nullable Toolbar toolbar) {
    final ActionBar ab = getActionBar();
    if (ab instanceof WindowDecorActionBar) {
        throw new IllegalStateException("This Activity already has an action bar supplied " +
                "by the window decor. Do not request Window.FEATURE_ACTION_BAR and set " +
                "android:windowActionBar to false in your theme to use a Toolbar instead.");
    }

    // If we reach here then we're setting a new action bar
    // First clear out the MenuInflater to make sure that it is valid for the new Action Bar
    mMenuInflater = null;

    // If we have an action bar currently, destroy it
    if (ab != null) {
        ab.onDestroy();
    }

    if (toolbar != null) {
        final ToolbarActionBar tbab = new ToolbarActionBar(toolbar, getTitle(), this);
        mActionBar = tbab;
        mWindow.setCallback(tbab.getWrappedWindowCallback());
    } else {
        mActionBar = null;
        // Re-set the original window callback since we may have already set a Toolbar wrapper
        mWindow.setCallback(this);
    }

    invalidateOptionsMenu();
}

As you can see there mWindow.setCallback(tbab.getWrappedWindowCallback()) is called with wrapped callback. And if we check implementation of ToolbarAractionBar:

ToolbarActionBar(Toolbar toolbar, CharSequence title, Window.Callback windowCallback) {
    mDecorToolbar = new ToolbarWidgetWrapper(toolbar, false);
    mWindowCallback = new ToolbarCallbackWrapper(windowCallback);
    mDecorToolbar.setWindowCallback(mWindowCallback);
    toolbar.setOnMenuItemClickListener(mMenuClicker);
    mDecorToolbar.setWindowTitle(title);
}

public Window.Callback getWrappedWindowCallback() {
    return mWindowCallback;
}

It wraps last parameter of constructor, which was this (instance of Activity).

The problem appears if before calling setActionBar we set our own implementation of Window.Callback (that correctly wraps original one). In this case not our implementation is wrapped by ToolbarActionBar but original one.

It would not be a problem if getWindow().getCallback() used instead of this as ToolbarActionBar constructor parameter. So it looks like a bug in android sdk.

The question is: does anyone know how to deal with such situation or some workaround for that issue? (lets assume that we should set our callback before adding action bar)


btw. setSupportActionBar looks not the same but very similar and have the same issue.



from Window.Callback is overwritten by Toolbar

No comments:

Post a Comment