I can successfully intercept the ActionBar
home button from my NavigationDrawerFragment
, which is added to my MainActivity
, like so:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (!loggedIn() && item.getItemId() == android.R.id.home) {
login();
return true;
}
return super.onOptionsItemSelected(item);
}
However, in my ComposeActivity
with ComposeFragment
this does not work. onOptionsItemSelected
is not called on the fragment.
I have debugged the code and the issue seems to come down to the design of the Android support library. It appears that both FragmentActivity
and Activity
have their own references to a FragmentManager
.
FragmentActivity
first checks if Activity
can handle the event before checking any of its fragments, which is consistent with the docs:
/**
* Dispatch context and options menu to fragments.
*/
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
if (super.onMenuItemSelected(featureId, item)) {
return true;
}
switch (featureId) {
case Window.FEATURE_OPTIONS_PANEL:
return mFragments.dispatchOptionsItemSelected(item);
case Window.FEATURE_CONTEXT_MENU:
return mFragments.dispatchContextItemSelected(item);
default:
return false;
}
}
As seen in the snippet below, Activity
handles the home button as a last resort, after checking if either it or any of its fragments can handle the event. But this reference to FragmentManager
does not contain any fragments, the fragments are in the FragmentActivity
's manager. Therefore the event will get swallowed by the Activity
class if ActionBar.DISPLAY_HOME_AS_UP
is set.
public boolean onMenuItemSelected(int featureId, MenuItem item) {
/* ... */
if (onOptionsItemSelected(item)) {
return true;
}
if (mFragments.dispatchOptionsItemSelected(item)) {
return true;
}
if (item.getItemId() == android.R.id.home && mActionBar != null &&
(mActionBar.getDisplayOptions() & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
if (mParent == null) {
return onNavigateUp();
} else {
return mParent.onNavigateUpFromChild(this);
}
}
return false;
/* ... */
}
It turns out that my MainActivity
, being the root of my application and using a navigation drawer, did not have this flag set and so did not swallow the event. But my ComposeActivity
has a parent activity and I need this flag to be set so it is not possible to intercept the action bar home button.
To sum up the issue: It is not possible to intercept a click on the Action Bar home button from a fragment in an activity with with DISPLAY_HOME_AS_UP set.
So is this a bug in the support library? It doesn't look like it would occur if I targeted a later Android version and dropped the support library.
Regarding workarounds for this, I guess I could:
- In my
ComposeActivity
'sonOptionsItemSelected
I can manually pass the event to each of my fragments, seeing if they can handle it before calling super. - Override onMenuItemSelected in
ComposeActivity
and do the same thing.
Anybody encountered this before? Should I log a bug somewhere? Any other ideas of ways around this issue?