Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to hide or add menu items for Flavor?

I have an app that has 3 different flavors, full, part1 and part2.

All different flavors have different package names, so I can ship them as different apps.

Now I want that only part1 gets a menu item called Reload. The other 2 flavors shouldn't have this menu item. Is this possible?

I tried the following with the menu resources:

app
|
+-src
  |
  +-full
  |
  +-main
  | |
  | +-res
  |   |
  |   +-menu
  |     |
  |     +-main_activity.xml
  |
  +-part1
  | |
  | +-res
  |   |
  |   +-menu
  |     |
  |     +-main_activity.xml
  |
  +-part2

Where main_activity.xml for part1 is:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/action_reload"
        android:icon="@drawable/ic_reload"
        android:title="@string/action_reload"
        app:showAsAction="always"/>
</menu>

And main_activity.xml for main is:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto">
</menu>

However, if I build the app in any other build variant than part1, I get a compilation error in my MainActivity where I need to react to the menu selection:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.action_reload: // Compile error: This item is not available
            // TODO reload
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}

It's quite obvious why that is. But do you have any suggestion what the solution is to customize menus for different build flavors?

like image 784
Terry Avatar asked Apr 12 '16 09:04

Terry


2 Answers

There's another way - create value file with boolean resource, with different value for each flavor e.g.:

main/res/values/bool.xml :

 <resources>
        <bool name="show_reload">false</bool>
    </resources>

part1/res/values/bool.xml :

    <?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="show_reload">true</bool>
</resources>

and then in your menu reource set the visibility value dependent on resource:

<menu ..>
    <item ..
      android:visible="@bool/show_reload"
      ..
    />
</menu>
like image 165
sashk0 Avatar answered Oct 05 '22 04:10

sashk0


If You don't want to copy whole class file, but to detect flavour or setting for any flavour and adjust it then do this:

In gradle file create config field:

defaultConfig {
    ...
    buildConfigField "boolean", "SHOW_MY_MENU_ITEM", "true"
}
productFlavors {
    FooFlavour {
        ...
        buildConfigField "boolean", "SHOW_MY_MENU_ITEM", "false"
    }
}

then build gradle. You can access this config field in Activity like this:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.foo_menu, menu);
    if (!BuildConfig.SHOW_MY_MENU_ITEM) {
        MenuItem myItem = menu.findItem(R.id.my_menu_item);
        myItem.setVisible(false);
    }
    return super.onCreateOptionsMenu(menu);
}

Similar, but in my opinion better approach is by using resValue, first create it in gradle file:

defaultConfig {
    ...
    resValue "bool", "show_my_menu_item", "true"
}
productFlavours {
    FooFlavour {
        ...
        resValue "bool", "show_my_menu_item", "false"
    }
}

After this resValue can be accessed directly in menu.xml:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        ...
        android:visible="@bool/show_my_menu_item" />
</menu>
like image 20
Darek Deoniziak Avatar answered Oct 05 '22 03:10

Darek Deoniziak