20-Dec-11 (Created: 20-Dec-11) | More in 'Android Basic UI'

02 Understanding Android Menus

Understanding Android Menus

Be it Swing, or WPF, or any other UI framework, Menus are familiar concepts. However Android presents enough twists and patterns to make menus an interesting read. Menus in Android are simple enough, yet they carry enough depth to make them flexible. To start with there is a familiar "Menu" class containing a number of "SubMenus" and "MenuItems". These "MenuItems" could further be grouped together based on arbitrary "Group ID"s or "Group Numbers".

With in a group a menuitem carries with it a name (title) an id and a "sort" order number. For example if you have a menu item "item4" carrying an order number of 4 and another menu item "item6" carrying an order number of 6, then the menu item "item4" will show up first in the menu.

Some of these number ranges are reserved for certain kinds of menus. For example menu items that are considered less important than others start at 0x40000. Similarly Container menu items start at 0x10000. Next up System Menu items start at 0X20000. Then comes secondary menus followed by Alternative menus at 0x40000. These various types of menu items are further discussed in this chapter a little later.

Once again following a familiar tune, an "Activity" class allows you to add "MenuItems" to a "Menu" in an overriden method called "onCreateOptionsMenu" bearing the following signature


@Override
public boolean onCreateOptionsMenu(Menu menu) 
{
   ...return true;   
}

Subsequently when a menu item is clicked the following overridden call back method is called on the same "Activity" class. The signature for this method looks like


@Override
public boolean onOptionsItemSelected(MenuItem item) 
{
   switch(item.getItemId()) {
      .....
   }
   //for items handled
   return true;
   
   //for the rest
   ...return super.onOptionsItemSelected(item);
}

However menus can be constructed programmatically you may prefer to load them through xml files.

Exploring onCreateOptionsMenu

This is a method that gets used quite often. So it is worth looking into the process of adding menu items to a menu. The code below adds three menu items.


@Override
public boolean onCreateOptionsMenu(Menu menu) 
{
   menu.add(0 //Group
         ,1 //item id
         ,0 //order
         ,"append");
   menu.add(0,2,1,"item2");
   menu.add(0,3,2,"clear");
   
   //call the base class to include system menus
   super.onCreateOptionsMenu(menu);
   
   //It is important to return true to see the menu
   return true;   
}

This method should return "true" to make the menu visible. If this method returns false then the menu will not be displayed.

It is also important to call the base class implementation of this method. This will allow the system an opportunity to populate menu with "system" menu items. To keep these "system" menus separate from the other sort of menus, the system adds them starting at CATEGORY_SYSTEM (which starts at 0x20000).

The first parameter is an integer number representing a group. The second parameter is an "id" that is sent back to the callback function when that menu item is chosen. The third integer represents the order of the menu item in the set of other menu items. The smaller this number is the earlier that menu item shows up in the menu.

The last item is the name or title of the menu. Instead of the free text you can use a string resource as well through R.java constants file.

Group, item id, and order are all optional and you can use the Menu.NONE to indicate that. Here is an example showing two groups of menus: Group 1 and Group 2.


@Override
public boolean onCreateOptionsMenu(Menu menu) 
{
   //Group 1
   menu.add(1,1,1,"g1.item1");
   menu.add(1,2,2,"g1.item2");

   //Group 2   
   menu.add(2,3,3,"g2.item1");
   menu.add(2,4,4,"g2.item2");
   
   return true; // it is important to return true   
}

Notice how the item "id" s are independent of the groups. The order is also independent of a group. So what good is a group then? Well you can do the following for a "group" of menu items.

The following methods allow you to manipulate a menu based on groups


removeGroup(id)
setGroupCheckable(id, checkable, exclusive)
setGroupEnabled(id,boolean enabled)
setGroupVisible(id,visible)

removeGroup removes all menu items from that group given the group id. You can enable or disable menus in a given group using setGroupEnabled method. Similarly you can control the visibility of a group of menu items using setGroupVisible.

setGroupCheckable is more interesting. You can use this method to show a check mark on a menu item when that menu item is selected. When applied to a group it will enable this capacity for all items with in that group. if the exclusive flag is set then only one menu item with in that group is allowed to go into a checked state. The other menu items will be unchecked.

Exploring onOptionsItemSelected

A template of this method could look like this:


@Override
public boolean onOptionsItemSelected(MenuItem item) {
   switch(item.getItemId()) {
      .....
   }
   //for items handled
   return true;

   //for the rest
   ...return super.onOptionsItemSelected(item);
}

This is the method that gets called when a menu option is chosen. If a menu item is handled by this method then the method should return true. The menu event will not be further propagated. For the menu item call backs that this method doesn't deal with it should call the parent method.

The default implementation returns false so that the "normal" processing can take place. Normal processing includes calling the item's menu click listener code.

Here is an example of that approach


public class MyResponse implements OnMenuClickListener
{
   //some local variable to work on
   //...
   //Some constructors
   @override
   boolean onMenuItemClick(MenuItem item)
   {
      //do your thing
      return true;
   }
}

....

MyResponse myResponse = new MyResponse(...);
menuItem.setOnMenuItemClickListener(myResponse);
...

The above method is called when the menu item has been invoked. This is the first code that is executed; if it returns true, no other callbacks will be executed.

A menu item can be associated with an "Intent" using method setIntent(intent). By default there is no intent associated with a menu item. But when one exists, and no one else handles the menu item, as pointed out above, then the default behavior is to invoke the intent using startActivity(intent).

Sample code exercising the above methods


package com.ai.android.HelloWorld;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;

public class HelloWorld extends Activity {
   
   //Initialize this in onCreateOptions
   Menu myMenu = null;
   
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //TextView tv = new TextView(this);
        //tv.setText("Hello, Android. Say hello");
        //setContentView(tv);
        
        setContentView(R.layout.main);
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) 
    {
       //call the parent to attach any system level menus
       super.onCreateOptionsMenu(menu);
       
       this.myMenu = menu;
       
       //add a few normal menus
       addRegularMenuItems(menu);
       
       //add a few secondary menus
       add5SecondaryMenuItems(menu);
       
       //it must return true to show the menu
       //if it is false menu won't show
       return true;
    }
    
    private void addRegularMenuItems(Menu menu)
    {
       //Secondary items are shown just like everything else
       int base=Menu.FIRST; // value is 1

       menu.add(base,base,base,"append");
       menu.add(base,base+1,base+1,"item 2");
       menu.add(base,base+2,base+2,"clear");
       
       menu.add(base,base+3,base+3,"hide secondary");
       menu.add(base,base+4,base+4,"show secondary");

       menu.add(base,base+5,base+5,"enable secondary");
       menu.add(base,base+6,base+6,"disable secondary");
       
       menu.add(base,base+7,base+7,"check secondary");
       menu.add(base,base+8,base+8,"uncheck secondary");
    }
    
    private void add5SecondaryMenuItems(Menu menu)
    {
       //Secondary items are shown just like everything else
       int base=Menu.CATEGORY_SECONDARY;

       menu.add(base,base+1,base+1,"sec. item 1");
       menu.add(base,base+2,base+2,"sec. item 2");
       menu.add(base,base+3,base+3,"sec. item 3");
       menu.add(base,base+3,base+3,"sec. item 4");
       menu.add(base,base+4,base+4,"sec. item 5");
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) 
    {
       if (item.getItemId() == 1)
       {
           appendText("\nhello");
       }
       else if (item.getItemId() == 2)
       {
          appendText("\nitem2");
       }
       else if (item.getItemId() == 3)
       {
          emptyText();
       }
       else if (item.getItemId() == 4)
       {
          //hide secondary
          this.appendMenuItemText(item);
          this.myMenu.setGroupVisible(Menu.CATEGORY_SECONDARY,false);
       }
       else if (item.getItemId() == 5)
       {
          //show secondary
          this.appendMenuItemText(item);
          this.myMenu.setGroupVisible(Menu.CATEGORY_SECONDARY,true);
       }
       else if (item.getItemId() == 6)
       {
          //enable secondary
          this.appendMenuItemText(item);
          this.myMenu.setGroupEnabled(Menu.CATEGORY_SECONDARY,true);
       }
       else if (item.getItemId() == 7)
       {
          //disable secondary
          this.appendMenuItemText(item);
          this.myMenu.setGroupEnabled(Menu.CATEGORY_SECONDARY,false);
       }
       else if (item.getItemId() == 8)
       {
          //check secondary
          this.appendMenuItemText(item);
          this.myMenu.setGroupCheckable(Menu.CATEGORY_SECONDARY,true,false);
       }
       else if (item.getItemId() == 9)
       {
          //uncheck secondary
          this.appendMenuItemText(item);
          this.myMenu.setGroupCheckable(Menu.CATEGORY_SECONDARY,false,false);
       }
       else
       {
          this.appendMenuItemText(item);
       }
       //should return true if the menu item
       //is handled
       return true;
       
       //If it is not our menu item
       //let the base class handle it
        //return super.onOptionsItemSelected(item);

    }
    
    private void appendText(String text)
    {
          TextView tv = 
             (TextView)this.findViewById(R.id.textViewId);
          tv.setText(tv.getText() + text);
    }
    private void appendMenuItemText(MenuItem menuItem)
    {
       String title = menuItem.getTitle().toString();
          TextView tv = 
             (TextView)this.findViewById(R.id.textViewId);
          tv.setText(tv.getText() + "\n" + title);
    }
    private void emptyText()
    {
          TextView tv = 
             (TextView)this.findViewById(R.id.textViewId);
          tv.setText("");
    }
}

Icon Menus

You can use icons to represent your menu options. However icon menu items do not support item check marks and only show condensed titles.

here is some sample code


//add a menu item and remember it
MenuItem item8 = menu.add(base,base+8,base+8,"uncheck secondary");
item8.setIcon(R.drawable.balloons);

The icon will show as long as the menu item is displayed on the main sheet. If there are two many menu items, and a "more" button open up to show them, then the icon may not show up.

Working with SubMenus (Starting at 0x40000)

Let's take a quick look of some sample code for a Submenu


private void addSubMenu(Menu menu)
{
   //Secondary items are shown just like everything else
   int base=Menu.FIRST + 100;
   SubMenu sm = menu.addSubMenu(base,base+1,Menu.NONE,"submenu");
   sm.add(base,base+2,base+2,"sub item1");
   sm.add(base,base+3,base+3, "sub item2");
   sm.add(base,base+4,base+4, "sub item3");
}

A "sub menu" is a subclass and child of a menu object. A menu can have as many submenus as you want. However a "SubMenu" does not behave like a "Menu". Particularly you cannot add another "SubMenu" to a "SubMenu". Code allows it, but you will get a runtime exception.

The documentation also suggests that sub menus do not support item icons. However the sub menu itself can have an icon. Let us extend the code above and try it and see what happens:


    private void addSubMenu(Menu menu)
    {
       //Secondary items are shown just like everything else
       int base=Menu.FIRST + 100;
       SubMenu sm = menu.addSubMenu(base,base+1,Menu.NONE,"submenu");
      
      //remember the menu item to add an icon to it
       MenuItem item1 = sm.add(base,base+2,base+2,"sub item1");
       
       sm.add(base,base+3,base+3, "sub item2");
       sm.add(base,base+4,base+4, "sub item3");

       //work the icons
       //submenu item icons are not supported
       item1.setIcon(R.drawable.icon48x48_2);
       
       //the following is ok however
       sm.setIcon(R.drawable.icon48x48_1);
      
       //This will result in runtime exception
       //sm.addSubMenu("try this");
    }

As pointed out in the comments. Submenu itself can have an icon in the main menu. But the menu items belonging to that submenu will ignore the icons. Adding a sub menu to a sub menu will result in a runtime exception.

Expanded Menus

If there are more than 6 menu items are visible, then a "more" button will appear to show the rest of the menu items. This menu is called an expanded menu. These menus do not show item icons and item check marks are discouraged.

Container Menu Items (Starting at 0x10000)

System Menu Items (Starting at 0x20000)

For example most windows applications come with menus like open, close, exit. These are system menus. However currently system does not populate these menus. It is conceivable that they might be chosen to be implemented in a subsequent release. The documentation suggests that programmers make provisions in their code so that they could accomodate them when they show up. The way to do this is to call the onCreateOptionsMenu of the parent. This would allow the system to add system menus to a group identified by an integer CATEGORY_SYSTEM, and the ids and the "order" numbers of the menus will also start and get incremented.

if we were adding system menus that may look like the following


menu.add(CATEGORY_SYSTEM //group
   ,CATEGORY_SYSTEM + 1 //id
   ,CATEGORY_SYSTEM + 1 //order
   ,"System Menu Item1" );

menu.add(CATEGORY_SYSTEM,CATEGORY_SYSTEM+2,CATEGORY_SYSTEM+2,"System Menu Item2");

Secondary Menu Items (Starting at 0x30000)

It is possible that all menus are not created equal. Some may require less attention than others. Android provides a way to group these menu items together in to a group called CATEGORY_SECONDARY. In fact of the different menu categories this may be the only group, besides the default, that gets specified by a programmer. Because the system menus are placed in by the system, alternative menus are populated based on mime types, and selected alternative menus are populated by the selected mime type of the object.

Here is a good way to populate secondary menus


menu.add(CATEGORY_SECONDARY //group
   ,CATEGORY_SECONDARY + 1 //id
   ,CATEGORY_SECONDARY + 1 //order
   ,"Secondary Menu Item1" );

menu.add(CATEGORY_SECONDARY
   ,CATEGORY_SECONDARY+2
   ,CATEGORY_SECONDARY+2
   ,"Secondary Menu Item2");
   

Notice again how the group number hasn't changed.

Working with Alternative Menu Items (Starting at 0x40000)

Alternative Menus

It is easy to appreciate Alternative menus, but to understand them well you have to first understand content providers, content URIs, content mime types, and finally intents.

Alternative menus facilitate multiple applications on Android to use each other. So in a sense they are part of an "inter" application communication or usage framework. Alternative menus allow one application to include menus from another application. When those menus are chosen the target application or "activity" will be launched with a "url" to the data needed by that "activity". The invoked activity will then use the "data url" from the "intent" that is passed along to get started.

Take the following sample from the NotesList application.


@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);

   setDefaultKeyMode(DEFAULT_KEYS_SHORTCUT);

   // If no data was given in the intent (because we were started
   // as a MAIN activity), then use our default content provider.
   Intent intent = getIntent();
   if (intent.getData() == null) {
      intent.setData(Notes.CONTENT_URI);
   }

   // Inform the list we provide context menus for items
   getListView().setOnCreateContextMenuListener(this);
   
   // Perform a managed query. The Activity will handle closing 
   //and requerying the cursor when needed.
   Cursor cursor = managedQuery(getIntent().getData(), 
                           PROJECTION, null, null,
         Notes.DEFAULT_SORT_ORDER);

   // Used to map notes entries from the database to views
   SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, 
                  R.layout.noteslist_item, cursor,
                  new String[] { Notes.TITLE }, 
                  new int[] { android.R.id.text1 });
   setListAdapter(adapter);
} 

Imagine a menu item in another application was invoked to launch this activity. Then the first thing you have to do is to retrive the data so that the activity can act upon. The following code does that:


   Intent intent = getIntent();
   if (intent.getData() == null) {
      intent.setData(Notes.CONTENT_URI);
   }

you obtain the Intent first. Then you would see if it has any data pointer in it often called content uri. If this were invoked because of a menu option then you would have the content uri. This content URI would look like the following:


public static final String AUTHORITY 
= "com.google.provider.NotePad";

public static final Uri CONTENT_URI 
 = Uri.parse("content://" + AUTHORITY + "/notes");

Put together the content uri will have a structure

   
"content://com.google.provider.NotePad/notes"

As you can see this is just a pointer to the data and not the data itself. Then the activity is responsible for retrieving that data. Here is the code again:


// Perform a managed query. The Activity will handle closing 
//and requerying the cursor when needed.
Cursor cursor = managedQuery(getIntent().getData(), 
                        PROJECTION, null, null,
      Notes.DEFAULT_SORT_ORDER);

// Used to map notes entries from the database to views
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, 
               R.layout.noteslist_item, cursor,
               new String[] { Notes.TITLE }, 
               new int[] { android.R.id.text1 });
setListAdapter(adapter);

Notice how the url is used to make a managed query on the data provider to get the data and then set the data into the list control.

So now we have all the programming needed to respond to menu items invoked by other applications to handle data coming from a data provider identified by:

   
"content://com.google.provider.NotePad/notes"

Notice how the intent to get the menus uses the data provider as an input and not the mime type directly. This connection will become clear after seeing how the "menu provider activity" declares itself.

Declaring Intent for Alternative menus


<activity android:name="NotesList" android:label="@string/title_notes_list">
   <intent-filter>
      <action android:name="android.intent.action.MAIN" />
      <category android:name="android.intent.category.LAUNCHER" />
   </intent-filter>
   <intent-filter>
      <action android:name="android.intent.action.VIEW" />
      <action android:name="android.intent.action.EDIT" />
      <action android:name="android.intent.action.PICK" />
      <category android:name="android.intent.category.DEFAULT" />
      <data android:mimeType="vnd.android.cursor.dir/vnd.google.note" />
   </intent-filter>
   <intent-filter>
      <action android:name="android.intent.action.GET_CONTENT" />
      <category android:name="android.intent.category.DEFAULT" />
      <data android:mimeType="vnd.android.cursor.item/vnd.google.note" />
   </intent-filter>
</activity>

These entries in the manifest xml file will declare that the activity "NotesList" can respond to an event like "VIEW" for data of type


<data android:mimeType="vnd.android.cursor.dir/vnd.google.note" />

The question then is this mime type connected to the data provider

   
"content://com.google.provider.NotePad/notes"

To make this jump Android will ask the content provider to see what is the mime type for content://com.google.provider.NotePad/notes. Here is the code how the provider answers that query


@Override
public String getType(Uri uri) {
   switch (sUriMatcher.match(uri)) {
   case NOTES:
      return Notes.CONTENT_TYPE;

   case NOTE_ID:
      return Notes.CONTENT_ITEM_TYPE;

   default:
      throw new IllegalArgumentException("Unknown URI " + uri);
   }
}

Where the constants are


public static final String CONTENT_TYPE = 
   "vnd.android.cursor.dir/vnd.google.note";

public static final String CONTENT_ITEM_TYPE = 
   "vnd.android.cursor.item/vnd.google.note";

Placing Aleternative Menus in the options menu

Now that we have enough understanding of how this works let's jump into the code and see if it makes sense


@Override public boolean
onCreateOptionsMenu(Menu menu){
    super.onCreateOptionsMenu(menu);

    // Create an Intent that describes the requirements to fulfill to be included
    // in our menu. The offering app must include a category value of Intent.ALTERNATIVE_CATEGORY. 
    Intent intent = new Intent(null, getIntent().getData());
    intent.addCategory(Intent.ALTERNATIVE_CATEGORY);
        
    // Search for, and populate the menu with, acceptable offering applications.
    menu.addIntentOptions(
         CATEGORY_ALTERNATIVE,      // Group
         CATEGORY_ALTERNATIVE,      // Any unique IDs we might care to add.
       CATEGORY_ALTERNATIVE,      // order
         MySampleClass.class.getName(),  // Name of the class displaying the menu--here, its this class. 
         null,   // No specifics.
         intent, // Previously created intent that describes our requirements.
         0,      // No flags.
         null);  // No specifics.

    return true;
}

To invite the alternative menus to our party you start with an intent. This intent does not have any "action" as we are just collecting the menu items. We need to specify the data source uri for the intent. This is done through getIntent().getData().

Then we invoke menu.addIntentOptions by specifying the "group" for these menu items and a starting menu id and the intent we created. See the SDK documentation for a complete description of the arguments for this method.

If you were handling the SELECTED_ALTERNATIVE menus then we need to do this in the onPrepareOptionsMenu.

Working with Context Menus

Context menus do not support shortcuts, icons, or sub menus.

An activity has only one regular menu but can host multiple context menus one for each View if it chooses to. These menus are shown when the mouse click is pressed little longer than usual. This is called "long click". This is equivalent to a "right click" in windows.

You first register the view for context menu ability in your create activity call back.


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

      ....
      //Then call this method towards the end
        setContentView(R.layout.main);
        
        //Then call the context menu
        //Otherwise you will get an exception
        registerForContextMenu(this.getTextView());
    }

Then you need to set your menu items


    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
        menu.setHeaderTitle("Sample menu");
        menu.add(200, 200, 200, "item1");
    }

Then you can look at the clicked item as follows


    @Override
    public boolean onContextItemSelected(MenuItem item) {
      this.appendMenuItemText(item);
      //menu item has been handled
      return true;
    }

Loading Menus through XML files

You can define your menus through xml files as well. These xml files are stored in a res sub directory called "menu". The ids for these files will be generated into R.java. Once you have these ids you can do the following


// Inflate the currently selected menu XML resource.
@Override
public boolean onCreateOptionsMenu(Menu menu) 
{
   MenuInflater inflater = getMenuInflater(); //from activity
   inflater.inflate(R.menu.menu1, menu);
}

Let me borrow some code from the "apidemos" to show you what the "menu1.xml" may look like


<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- This group uses the default category. -->
    <group android:id="@+id/most_used_items">
    
        <item android:id="@+id/last_most_item"
            android:orderInCategory="10"
            android:title="@string/last_most_often" />
    
        <item android:id="@+id/middle_most_item"
            android:orderInCategory="7"
            android:title="@string/middle_most_often" />
    
        <item android:id="@+id/first_most_item"
            android:orderInCategory="4"
            android:title="@string/first_most_often" />
    
    </group>
    
    <!-- This group uses the secondary category, which is used for less oftenly used items.
         Notice these items will show up after the above items.
         (Furthermore, notice how the orders in each category are independent from the other
         category.) -->
    <group android:id="@+id/least_used_items"
        android:menuCategory="secondary">
        
        <item android:id="@+id/last_least_item"
            android:orderInCategory="3"
            android:title="@string/last_least_often" />
    
        <item android:id="@+id/middle_least_item"
            android:orderInCategory="2"
            android:title="@string/middle_least_often" />
    
        <item android:id="@+id/first_least_item"
            android:orderInCategory="0"
            android:title="@string/first_least_often" />
    
    </group>
</menu>

Runnable class and menu items

How to use showAlert convenience dialog

Sample Menu XML files: Checkable


<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Checkable items appear only in submenus or context menus. -->
    <!-- Carefully look at the attribute name checkableBehavior on groups, but
         the attribute name checkable on items. The checkableBehavior encompasses
         the number of items that will be checkable within that group. -->
    <item android:title="None">
        <menu>
            <!-- The none checkableBehavior is default, but we explicitly show it here. -->
            <group android:id="@+id/noncheckable_group"
                    android:checkableBehavior="none">
                <!-- Notice how these items inherit from the group. -->
                <item android:id="@+id/noncheckable_item_1"
                        android:title="@string/item_1" />
                <item android:id="@+id/noncheckable_item_2"
                        android:title="@string/item_2" />
                <item android:id="@+id/noncheckable_item_3"
                        android:title="@string/item_3" />
            </group>
        </menu>
    </item>

    <item android:title="All">
        <menu>
            <group android:id="@+id/checkable_group"
                    android:checkableBehavior="all">
                <!-- Notice how these items inherit from the group. -->
                <item android:id="@+id/checkable_item_1"
                        android:title="@string/item_1" />
                <item android:id="@+id/checkable_item_2"
                        android:title="@string/item_2"
                        android:checked="true" />
                <item android:id="@+id/checkable_item_3"
                        android:title="@string/item_3"
                        android:checked="true" />
            </group>
        </menu>
    </item>

    <item android:title="Single">
        <menu>
            <group android:id="@+id/exclusive_checkable_group"
                    android:checkableBehavior="single">
                <!-- Notice how these items inherit from the group. -->
                <item android:id="@+id/exclusive_checkable_item_1"
                        android:title="@string/item_1" />
                <item android:id="@+id/exclusive_checkable_item_2"
                        android:title="@string/item_2" />
                <item android:id="@+id/exclusive_checkable_item_3"
                        android:title="@string/item_3"
                        android:checked="true" />
            </group>
        </menu>
    </item>

    <item android:title="All without group">
        <menu>
            <!-- Notice how these items have each set. -->
            <item android:id="@+id/nongroup_checkable_item_1"
                    android:title="@string/item_1"
                    android:checkable="true" />
            <item android:id="@+id/nongroup_checkable_item_2"
                    android:title="@string/item_2"
                    android:checkable="true"
                    android:checked="true" />
            <item android:id="@+id/nongroup_checkable_item_3"
                    android:title="@string/item_3"
                    android:checkable="true"
                    android:checked="true" />
        </menu>
    </item>
</menu>

Sample Menu XML Files: Disabled


<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:id="@+id/enabled_item"
        android:title="Enabled"
        android:icon="@drawable/stat_happy" />

    <item android:id="@+id/disabled_item"
        android:title="Disabled"
        android:enabled="false"
        android:icon="@drawable/stat_sad" />
</menu>

Sample Menu XML Files: Groups


<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:id="@+id/browser_visibility"
        android:title="@string/browser_visibility" />

    <group android:id="@+id/browser">
        <item android:id="@+id/refresh"
            android:title="@string/browser_refresh" />
        <item android:id="@+id/bookmark"
            android:title="@string/browser_bookmark" />
    </group>

    <item android:id="@+id/email_visibility"
        android:title="@string/email_visibility" />

    <group android:id="@+id/email">
        <item android:id="@+id/reply"
            android:title="@string/email_reply" />
        <item android:id="@+id/forward"
            android:title="@string/email_forward" />
    </group>
</menu>

Sample Menu XML Files: Order


<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- These are in reverse order in this resource, 
      but the orderInCategory attribute will
        order them for the menu 
      (they all have the same default category). 
   -->
    <item android:id="@+id/fourth_item"
        android:orderInCategory="3"
        android:title="Fourth" />
    <item android:id="@+id/third_item"
        android:orderInCategory="2"
        android:title="Third" />
    <item android:id="@+id/second_item"
        android:orderInCategory="1"
        android:title="Second" />
    <item android:id="@+id/first_item"
        android:orderInCategory="0"
        android:title="First" />
</menu>

Sample Menu XML Files: Shortcuts


<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/invisible_item"
        android:visible="false"
        android:alphabeticShortcut="i"
        android:title="Invisible item" />
    <item android:id="@+id/a_item"
        android:alphabeticShortcut="a"
        android:title="Alvin" />
    <item android:id="@+id/b_item"
        android:alphabeticShortcut="b"
        android:title="Bart" />
    <item android:id="@+id/c_item"
        android:alphabeticShortcut="c"
        android:title="Chris" />
    <item android:id="@+id/d_item"
        android:alphabeticShortcut="d"
        android:title="David" />
    <item android:id="@+id/e_item"
        android:alphabeticShortcut="e"
        android:title="Eric" />
    <item android:id="@+id/f_item"
        android:alphabeticShortcut="f"
        android:title="Frank" />
    <item android:id="@+id/g_item"
        android:alphabeticShortcut="g"
        android:title="Gary" />
    <item android:id="@+id/h_item"
        android:alphabeticShortcut="h"
        android:title="Henry" />
    <item android:id="@+id/excl_item"
        android:alphabeticShortcut="!"
        android:title="Exclamation" />
</menu>

Sample Menu XML Files: Submenu


<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:title="Normal 1" />
    <item android:id="@+id/submenu"
        android:title="Emotions">
        <menu>        
            <item android:id="@+id/happy"
                android:title="Happy"
                android:icon="@drawable/stat_happy" />
            <item android:id="@+id/neutral"
                android:title="Neutral"
                android:icon="@drawable/stat_neutral" />
            <item android:id="@+id/sad"
                android:title="Sad"
                android:icon="@drawable/stat_sad" />
        </menu>
    </item>
    <item android:title="Normal 2" />
</menu>

Sample Menu XML Files: title icon


<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/happy"
        android:title="Happy"
        android:icon="@drawable/stat_happy" />
    <item android:id="@+id/neutral"
        android:title="Neutral"
        android:icon="@drawable/stat_neutral" />
    <item android:id="@+id/sad"
        android:title="Sad"
        android:icon="@drawable/stat_sad" />
</menu>

Sample Menu XML Files: title only


<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/jump"
        android:title="@string/jump" />
    <item android:id="@+id/dive"
        android:title="@string/dive" />
</menu>

Sample Menu XML Files: Visible


<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/visible_item"
        android:title="Visible"
        android:alphabeticShortcut="a" />
    <item android:id="@+id/hidden_item"
        android:title="Hidden"
        android:visible="false"
        android:alphabeticShortcut="b" />
    <group android:id="@+id/hidden_group"
        android:visible="false">
        <item android:id="@+id/hidden_by_group"
            android:title="Hidden by group"
            android:alphabeticShortcut="c" />
    </group>
</menu>