About this book

Recently, with the increasing popularity of mobile phones, mobile operating systems have emerged and quickly spread. Now people with smart phones can do everything that they can do with their computers. The popularity of the Android mobile operating system has increased and is widely used. In this book, new features and innovations of Android 4.0 will be discussed.

"Android 4: New Features for Application Development" is a practical and hands-on guide for developing android applications using new features of Android Ice Cream Sandwich (Android 4.0) with a step-by-step approach and clearly explained sample codes. You will learn the new APIs in Android 4.0 with sample code.

This book will cover the new features and APIs of Android 4.0 (Android Ice Cream Sandwich). It will show the usage of the new APIs with a step-by-step approach and clearly explained sample code.

You will learn about the new user interface components such as Action Bar and GridLayout. You will also learn about new APIs for social media integration and accessing calendar data. We will also look at new connectivity APIs such as Wi-Fi Direct and Android Beam. Supporting multiple screen sizes and multiple versions of Android is also among the subjects that you will learn.

You can use "Android 4: New Features for Application Development" as a reference book for developing Android applications using new features of Android 4.0 with its clearly explained, step-by-step sample codes.

Publication date:
December 2012
Publisher
Packt
Pages
166
ISBN
9781849519526

 

Chapter 1. Action Bar for All

Action bar API was firstly introduced with Android 3.0. With Android Ice Cream Sandwich, action bar supports small screen sizes. This chapter shows how to use and configure the action bar.

The topics covered in this chapter are as follows:

  • Action bar types

  • Adding an action bar

  • Adding an ActionProvider and ShareActionProvider

  • Adding an action view

  • Using action bar for navigation

 

Action bar


Action bar is a user interface element located on top of the user's device screen. It provides actions and navigation capabilities to the user. Action bar has been available since API Level 11 (Android 3.0 Honeycomb) and after Ice Cream Sandwich was released, it supports small screen devices too. A sample Action Bar with tabs is shown in the following screenshot:

As it can be seen in the preceding screenshot, on the left of the bar there is an application logo and title, and then come the tabs for navigation. Lastly, the action buttons are placed after the tabs. The action buttons that do not fit to screen are displayed as an overflow menu with three dots on the right of the bar. In the previous screenshot, the action bar is displayed on a large screen device. However, in small screen devices, the Action Bar is displayed as a stack of bars as seen in the following screenshot:

As it can be seen in the preceding screenshot, there is not enough space to display all action bar items and the action bar is displayed with two bars on top of the screen.

Another type of action bar is the split action bar. In this type of action bar, action buttons are displayed in a bar at the bottom of the screen in narrow screens as shown in the following screenshot:

Adding an action bar

After Ice Cream Sandwich, Android doesn't require the menu button to reach the options menu. The best practice is to use action bar instead of the menu button. It is very easy to migrate from the options menu to the action bar. Now we are going to create a menu and then migrate that menu to the action bar.

Firstly, create an Android project and then add a menu that contains Settings and About as menu items. The resulting menu XML file should look like the following code block:

Tip

Downloading the example code

You can download the example code files for all Packt books you have purchased from your account at http://www.PacktPub.com. If you purchased this book elsewhere, you can visit http://www.PacktPub.com/support and register to have the files e-mailed directly to you.

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
    
    <item android:id="@+id/settings" android:title="Settings"></item>
    
    <item android:id="@+id/about" android:title="About"></item>
    
</menu>

The layout XML for this sample is a LinearLayout layout with a TextView component in it as shown in the following code block:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />

</LinearLayout>

Implement the onCreateOptionsMenu and onOptionsItemSelected methods as shown in the following code block, in order to show the menu items:

package com.chapter1;

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

public class Chapter1Activity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
            //Inflate the menu.xml of the android project
             //in order to create menu
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.menu, menu);
    return true;
    }
    
    @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    // Handle item selection
    //According to selection, show the Toast message
    //of the selected button
    switch (item.getItemId()) {

    case R.id.settings:
      Toast.makeText(this, "Settings options menu button is pressed", Toast.LENGTH_LONG).show();
      return true;
    case R.id.about:
      Toast.makeText(this, "About options menu button is pressed", Toast.LENGTH_LONG).show();
      return true;
      default:
      return super.onOptionsItemSelected(item);
    }
  }
}

In order to display the action bar, the Android applications should target a minimum of API Level 11 in the AndroidManifest.xml file as shown in the following code block:

<?xml version="1.0" encoding="utf-8"?>
<!—set targetSDKversion to 11 because Action Bar is
     available since API Level 11-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.chapter1"
    android:versionCode="1"
    android:versionName="1.0" >

    < uses-sdk android:minSdkVersion="5" 
               android:targetSdkVersion="11"  />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".Chapter1Activity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

With this configuration, when the application runs on devices that have Android 3.0 or greater, the action bar will be displayed.

When we run this application on an emulator with API Level 15, we will see the overflow menu on the right of the action bar and the options menu buttons will be displayed when the overflow menu is pressed. In order to show the options menu buttons on the action bar (not as an overflow menu), just add android:showAsAction="ifRoom|withText" in the item tags of the menu XML file. The resulting menu XML file should look like the following code block:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
    
    <item android:id="@+id/settings" android:title="Settings" android:showAsAction="ifRoom|withText"></item>
    
    <item android:id="@+id/about" android:title="About" android:showAsAction="ifRoom|withText"></item>
    
</menu>

If there is not enough space (ifRoom) to display the options menu buttons, the buttons will be displayed as an overflow menu. In order to show the options menu buttons with icon only (if an icon is provided), withText should be removed. When you run the application it will look like the following screenshot:

In some cases, you may not want to display the action bar. In order to remove the action bar, add android:theme="@android:style/Theme.Holo.NoActionBar" to the activity tag in the AndroidManifest.xml file. The resulting AndroidManifest.xml should look like the following code block:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.chapter1"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="5" 
              android:targetSdkVersion="11"  />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".Chapter1Activity"
            android:label="@string/app_name" 
            android:theme="@android:style/Theme.Holo.NoActionBar" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

In order to show the action bar as a split action bar, add the android:uiOptions="splitActionBarWhenNarrow" application in the activity tag in AndroidManifest.xml. The resulting AndroidManifest.xml should look like the following code block:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.chapter1"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="5"   
        android:targetSdkVersion="11"  />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" 
        android:uiOptions="splitActionBarWhenNarrow">
        <activity
            android:name=".Chapter1Activity"
            android:label="@string/app_name" 
            >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

When you run this application on an emulator, the screen will look like the following screenshot:

 

Adding an ActionProvider


In order to use a custom view instead of a simple button in action bar, the ActionProvider class could be the solution. ActionProvider has been available since API Level 14. ActionProvider can generate a custom view in the action bar, can generate submenus, and can handle events of the views that it generates. In order to create an ActionProvider, we should extend the ActionProvider class. The following code shows a sample class that extends the ActionProvider class and displays a custom layout instead of a simple button in action bar:

import android.content.Context;
import android.view.ActionProvider;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageButton;
import android.widget.Toast;

public class Chapter1ActionProvider extends ActionProvider {

  Context mContext;
  
  public Chapter1ActionProvider(Context context) {
    super(context);
    mContext = context;
  }

  @Override
  public View onCreateActionView() {
        //This method is the place where we generate a custom layout for the Action Bar menu item
     LayoutInflater layoutInflater = LayoutInflater.from(mContext);
         View view = layoutInflater.inflate(R.layout.action_provider, null);
         ImageButton button = (ImageButton) view.findViewById(R.id.button);

         button.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View v) {
          Toast.makeText(mContext, "Action Provider click", Toast.LENGTH_LONG).show();
             }
         });
    return view;
  }
  
  @Override
  public boolean onPerformDefaultAction() {
          //This is the method which is called when the Action Bar menu item is in overflow menu and clicked from there
          Toast.makeText(mContext, "Action Provider click", Toast.LENGTH_LONG).show();
    return true;
  }
}

We have to add a constructor and override the onCreateActionView() method. In the constructor, we assign Context to a variable because we are going to need it in further implementations. The onCreateActionView() method is the place where we generate a custom layout for the action bar menu item. onPerformDefaultAction() is the method which is called when the action bar menu item is in the overflow menu and is clicked from there. If the ActionProvider provides submenus, this method is never called. The layout XML for the custom layout used in the onCreateActionView() method is shown in the following code block:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="center"
    android:focusable="true"
    android:addStatesFromChildren="true"
    android:background="?android:attr/actionBarItemBackground"
    style="?android:attr/actionButtonStyle">

    <ImageButton android:id="@+id/button"
        android:background="@drawable/ic_launcher"
        android:layout_width="32dip"
        android:layout_height="32dip"
        android:layout_gravity="center"
        android:scaleType="fitCenter"
        android:adjustViewBounds="true" />
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Some Text"
        android:textAppearance="?android:attr/textAppearanceLarge" />

</LinearLayout>

As you can see in the XML file, we added an ImageButton component and a TextView component to a LinearLayout layout. The onClickListener() event of ImageButton is implemented in the onCreateActionView() method of the Chapter1ActionProvider class. In this event, a Toast message is displayed.

The Activity class that displays the action bar is shown the following code block:

public class Chapter1ActionProviderActivity extends Activity{

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
  }
  
  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.menu, menu);
    return true;
  }
  
   @Override
    public boolean onOptionsItemSelected(MenuItem item) {
    // Handle item selection
    switch (item.getItemId()) {

    case R.id.about:
        Toast.makeText(this, "About options menu button is pressed", Toast.LENGTH_LONG).show();
        return true;
      default:
        return super.onOptionsItemSelected(item);
      }
    }
}

In order to display a custom layout for an action bar menu item, we have to assign an ActionProvider class in the menu XML file. We assign Chapter1ActionProvider which was implemented as in the earlier code as ActionProvider. The menu XML file in our example is as follows:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
    
    <item android:id="@+id/settings" android:title="Settings" android:showAsAction="ifRoom|withText"
        
    android:actionProviderClass="com.chapter1.Chapter1ActionProvider"></item>
    
    <item android:id="@+id/about" android:title="About" android:showAsAction="ifRoom|withText"></item>
    
</menu>

As you see in the menu XML file, we provided an ActionProvider class to the settings menu item. The last important thing is setting the minimum SDK version to API Level 14 in the AndroidManifest.xml file, because ActionProvider is a new feature released in API Level 14. The AndroidManifest.xml file should look like the following code block:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.chapter1"
    android:versionCode="1"
    android:versionName="1.0" >
<!—set minSDKversion to 11 because ActionProvider is
     available since API Level 11-->

    <uses-sdk android:minSdkVersion="14"  
        android:targetSdkVersion="14"  />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".Chapter1ActionProviderActivity"
            android:label="@string/app_name" 
            >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

When you run this application in an emulator, a user interface component with an image button and a text view will be displayed in the action bar. A toast message will be displayed if you press the image button. The screen will look like the following:

Adding submenus to the ActionProvider

It is possible to show submenus with ActionProvider. In order to add submenus, we should override the onPrepareSubMenu(SubMenu subMenu) and hasSubMenu() methods in the Chapter1ActionProvider class. The resulting code of the Chapter1ActionProvider class should look like the following code block:

package com.chapter1;

import android.app.Activity;
import android.content.Context;
import android.view.ActionProvider;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.SubMenu;
import android.view.View;
import android.widget.ImageButton;
import android.widget.Toast;

public class Chapter1ActionProvider extends ActionProvider implements 
OnMenuItemClickListener {

  Context mContext;
  
  public Chapter1ActionProvider(Context context) {
    super(context);
    mContext = context;
  }

  @Override
  public View onCreateActionView() {
         return null;
  }
  
  @Override
  public boolean onPerformDefaultAction() {
    
    Toast.makeText(mContext, "Action Provider click", Toast.LENGTH_LONG).show();
    return true;
  }
  
  @Override
  public void onPrepareSubMenu(SubMenu subMenu) {
    //In order to add submenus, we should override this method
    // we dynamically created submenus

    subMenu.clear();
    subMenu.add("SubItem1").setOnMenuItemClickListener(this);
    subMenu.add("SubItem2").setOnMenuItemClickListener(this);
  }

  @Override
  public boolean onMenuItemClick(MenuItem item) {
    
    Toast.makeText(mContext, "Sub Item click", Toast.LENGTH_LONG).show();
    return true;
  }
  
  @Override
  public boolean hasSubMenu() {
       // we implemented it as returning true because we have menu
    return true;
  }

}

In the onPrepareSubMenu(SubMenu subMenu) method, we dynamically created submenus and set their onMenuItemClickListener events. The onPrepareSubMenu(SubMenu subMenu) method is called if the hasSubMenu() method returns true, so we implemented it as returning true.

It is also possible to create submenus from a menu XML file. If you want to create submenus from a menu XML file, onPrepareSubMenu(SubMenu subMenu) should look like the following code block:

  @Override
  public void onPrepareSubMenu(SubMenu subMenu) {

    MenuInflater inflater = ((Activity)mContext).getMenuInflater();
    inflater.inflate(R.menu.menu2, subMenu);
  }

This code shows how we could inflate an XML file to create the submenus using the menu XML file menu2.

ShareActionProvider

ShareActionProvider provides a consistent way of sharing. It puts an action button on the action bar with a share icon. When you click that button, it lists the available applications for sharing. All you need is to declare ShareActionProvider in the menu item as shown in the following code block:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
    
    <item android:id="@+id/share" android:title="Share" android:showAsAction="ifRoom"
    android:actionProviderClass="android.widget.ShareActionProvider"></item>
    <item android:id="@+id/about" android:title="About" android:showAsAction="ifRoom"></item>
    <item android:id="@+id/settings" android:title="Settings" android:showAsAction="ifRoom"></item>
    
</menu>

The Activity class that uses ShareActionProvider should look like the following code block:

package com.chapter1;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.ShareActionProvider;

public class Chapter1ShareActionProviderActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
      
      ShareActionProvider myShareActionProvider;
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.menu, menu);
    MenuItem item = menu.findItem(R.id.share);
    myShareActionProvider = (ShareActionProvider)item.getActionProvider();
    myShareActionProvider.setShareHistoryFileName(ShareActionProvider.DEFAULT_SHARE_HISTORY_FILE_NAME);
    myShareActionProvider.setShareIntent(getShareIntent());
    
    return true;
    }
    
    private Intent getShareIntent() {
      Intent shareIntent = new Intent(Intent.ACTION_SEND);
      shareIntent.setType("text/plain");
      shareIntent.putExtra(Intent.EXTRA_TEXT, "www.somesite.com");
      return shareIntent;
      }

}

As you can see in the code, we get the ShareActionProvider attribute of the menu item in the onCreateOptionsMenu(Menu menu) method. Then we define the intent for sharing with the setShareIntent method of ShareActionProvider. getShareIntent() method creates an intent for sharing text. We use this method to define intent for the ShareActionProvider instance.

ShareActionProvider keeps the history of applications used for sharing in a file. The default file that ShareActionProvider uses is ShareActionProvider.DEFAULT_SHARE_HISTORY_FILE_NAME. It is possible to change this file with the setShareHistoryFileName method. All you need is to pass an XML file name with the .xml extension to this method. ShareActionProvider uses this file to find the most frequently used application for sharing. Then it displays the most frequently used application near the share action button as a default sharing target.

The screen of the application with ShareActionProvider looks like the following:

Since the ShareActionProvider was introduced in API Level 14, we have to set the minimum SDK to 14 in the AndroidManifest.xml file as shown in the following code block:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.chapter1"
    android:versionCode="1"
    android:versionName="1.0" >
<!—set minSdkVersion to 14 because ShareActionProvider is available
    since API Level 14-->

    <uses-sdk android:minSdkVersion="14" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".Chapter1ShareActionProviderActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
 

Adding an action view


An action view is a user interface component that appears in the action bar instead of an action button. This view is collapsible, that is if it is configured as collapsible, meaning it expands when the action button is pressed. If it is not configured as collapsible, it is viewed expanded by default. In the following example, we added an action view and showed its events and how to handle these events.

Firstly, add a layout for the action view that has three buttons with the text Large, Medium, and Small as shown in the following code block:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >
    <Button
        android:id="@+id/buttonLarge"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="Large"
        android:textSize="15dp" />

    <Button
        android:id="@+id/buttonMedium"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="Medium"
        android:textSize="12dp" />
    
    <Button
        android:id="@+id/buttonSmall"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="Small"
        android:textSize="9dp" />

</LinearLayout>

Then we need to bind this action view to an action bar menu item. The XML code of menu is shown in the following code bock:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
    
    <item android:id="@+id/size" android:title="Size" android:showAsAction="ifRoom|collapseActionView"
    android:actionLayout="@layout/actionview"></item>
   
    <item android:id="@+id/about" android:title="About" android:showAsAction="ifRoom"></item>
    <item android:id="@+id/settings" android:title="Settings" android:showAsAction="ifRoom|withText"></item>
    
</menu>

As you can see in the menu XML code, we bind the action view to the size menu item by setting the actionLayout property. We also set the showAsAction property to collapseActionView. This way the action view is collapsible and it expands when the action button item is pressed. This option helps us to save space in the action bar. If this property is not set as collapseActionView, the action view is displayed as expanded by default.

The Activity class that handles action view events is shown in the following code block:

package com.chapter1;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MenuItem.OnActionExpandListener;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class Chapter1ActionViewActivity extends Activity implements 
OnClickListener {
  Button buttonLarge;
  Button buttonMedium;
  Button buttonSmall;
  Menu menu;
  
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
      //you can set on click listeners of the items in Action View in this method

      this.menu = menu;
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.menu, menu);
    MenuItem item = menu.findItem(R.id.size);
    item.setOnActionExpandListener(new Chapter1ActionListener(this));
    buttonLarge = (Button)item.getActionView().findViewById(R.id.buttonLarge);
    buttonLarge.setOnClickListener(this);
    
    buttonMedium = (Button)item.getActionView().findViewById(R.id.buttonMedium);
    buttonMedium.setOnClickListener(this);
    
    buttonSmall = (Button)item.getActionView().findViewById(R.id.buttonSmall);
    buttonSmall.setOnClickListener(this);
    
    return true;
    }
    
    @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    // Handle item selection
    switch (item.getItemId()) {

    case R.id.size:
      Toast.makeText(this, "Size options menu button is pressed", Toast.LENGTH_LONG).show();
      return true;
    case R.id.about:
      Toast.makeText(this, "About options menu button is pressed", Toast.LENGTH_LONG).show();
      return true;
      case R.id.settings:
      Toast.makeText(this, "Settings options menu button is pressed", Toast.LENGTH_LONG).show();
      return true;
    default:
      return super.onOptionsItemSelected(item);
    }
  }

  @Override
  public void onClick(View v) {
    
    if(v == buttonLarge )
    {
      Toast.makeText(this, "Large button is pressed", Toast.LENGTH_LONG).show();
                   //Collapse the action view
      menu.findItem(R.id.size).collapseActionView();
    }
    else if(v == buttonMedium )
    {
      Toast.makeText(this, "Medium button is pressed", Toast.LENGTH_LONG).show();
                    //Collapse the action view
      menu.findItem(R.id.size).collapseActionView();
    }
    else if(v == buttonSmall)
    {
      Toast.makeText(this, "Small button is pressed", Toast.LENGTH_LONG).show();
                    //Collapse the action view
      menu.findItem(R.id.size).collapseActionView();
    }
    
  }
  
      // This class returns a callback when Action View is expanded or collapsed
  public static class Chapter1ActionListener implements OnActionExpandListener
  {
    Activity activity;
    
    public Chapter1ActionListener(Activity activity)
    {
      this.activity = activity;
    }

    @Override
    public boolean onMenuItemActionCollapse(MenuItem item) {

      Toast.makeText(activity, item.getTitle()+" button is collapsed", Toast.LENGTH_LONG).show();
      return true;
  }

   @Override
    public boolean onMenuItemActionExpand(MenuItem item) {
      Toast.makeText(activity, item.getTitle()+" button is expanded", Toast.LENGTH_LONG).show();
      return true;
    }
    
  }
}

As you see in the Chapter1ActionViewActivity, you can set event listeners of the items in action view in the onCreateOptionsMenu(Menu menu) method. We set the onClickListener event of the buttons in the action view in the onCreateOptionsMenu(Menu menu) method.

It is possible to expand and collapse the action view programmatically with the expandActionView() and col lapseActionView() methods. As you can see in the onClick(View v) method of the Chapter1ActionViewActivity method, we manually collapsed the action view with the collapseActionView() method.

You can do an action when the action view is expanded or collapsed with the OnActionExpandListener class. As you can see in the code, we defined the Chapter1ActionListener class that implements OnActionExpandListener. We override the onMenuItemActionCollapse(MenuItem item) and onMenuItemActionExpand(MenuItem item) methods of this class in order to show a Toast message. We passed Activity as a parameter to the constructor of Chapter1ActionListener because we need the Activity when showing the Toast message. We have to register the setOnActionExpandListener() method with the OnActionExpandListener class, in order to handle expand and collapse events. As you can see in the code, we registered this event in the onCreateOptionsMenu(Menu menu) method. We show a Toast message when the action view is collapsed and expanded.

Since the action view is introduced in API Level 14, we have to set the minimum SDK property to 14 or greater in the AndroidManifest.xml file as shown in the following code block:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.chapter1"
    android:versionCode="1"
    android:versionName="1.0" >
<!—set minSdkVersion to 14 because Action View is
   available since API Level 14-->

    <uses-sdk android:minSdkVersion="14" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".Chapter1ActionViewActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

When you run this application on an emulator it will look like the following screenshot:

 

Using the action bar for navigation


Tabbed navigation could also be implemented with the TabWidget class. However, the action bar has some advantages. The action bar automatically adjusts itself according to the device screen size. For instance, if there is not enough space for tabs, it will display tabs in a stacked bar manner. Thus, it's better to use the action bar for tabbed navigation implementation.

Now, we are going to see how to use the action bar for tabbed navigation. Firstly, create an Android project and add two fragments: one that displays Fragment A and an other that displays Fragment B. The layout XML for fragments should look like the following code block:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Fragment A"
        android:textAppearance="?android:attr/textAppearanceLarge" android:layout_gravity="center_horizontal"/>

</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Fragment B"
        android:textAppearance="?android:attr/textAppearanceLarge" 
        android:layout_gravity="center_horizontal"/>

</LinearLayout>

The classes that extend the Fragment class for the two fragments should look like the following code block:

package com.chapter1;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class FragmentA extends Fragment {

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
      View view = inflater.inflate(R.layout.fragment_a, container,false);
    return view;
  }
}
package com.chapter1;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class FragmentB extends Fragment {

  
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_b, container, false);
    return view;
  }
}

In order to use action bar for tabbed navigation, we should firstly implement the ActionBar.TabListener class. The class that implements TabListener is going to be used in the Activity class in adding tabs. The Activity class with the TabListener implementation should look like the following code block:

package com.chapter1;

import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.ActionBar.TabListener;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;

public class Chapter1ActionBarTabActivity extends Activity {

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    
    ActionBar actionBar = getActionBar();
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

    Tab tab = actionBar
        .newTab()
        .setText("First tab")
        .setTabListener(
          new Chapter1TabListener<FragmentA>(this, "fragmentA",FragmentA.class));
    actionBar.addTab(tab);

    tab = actionBar
        .newTab()
        .setText("Second Tab")
        .setTabListener(
            new Chapter1TabListener<FragmentB>(this, "fragmentB",FragmentB.class));
    actionBar.addTab(tab);
  }

  public static class Chapter1TabListener<T extends Fragment> implements
      TabListener {
    private Fragment mFragment;
    private final Activity mActivity;
    private final String mTag;
    private final Class<T> mClass;

    public Chapter1TabListener(Activity activity, String tag, Class<T> clz) {
      mActivity = activity;
      mTag = tag;
      mClass = clz;
    }

    @Override
    public void onTabSelected(Tab tab, FragmentTransaction ft) {
                 // we initialize and add the fragment to our Activity if it doesn't exist

      if (mFragment == null) {

        mFragment = Fragment.instantiate(mActivity, mClass.getName());			
        ft.add(android.R.id.content, mFragment, mTag);

        } else {
                          // If it exists, we simply attach it
        ft.attach(mFragment);
      }
    }

    @Override
    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
                    // in this method we detach the fragment because // it shouldn't be displayed
    if (mFragment != null) {
        ft.detach(mFragment);
        }
    }
    @Override
    public void onTabReselected(Tab tab, FragmentTransaction ft) {
                 // This method is called when the tab is reselected
    }
  }
}

In the Chapter1TabListener class there are three methods that need to be overridden: onTabReselected(Tab tab, FragmentTransaction ft), onTabUnselected(Tab tab, FragmentTransaction ft), and onTabSelected(Tab tab, FragmentTransaction ft). In the onTabSelected(Tab tab, FragmentTransaction ft) method, we initialize and add the fragment to our activity if it doesn't exist. If it exists, we simply attach to it. When the tab is unselected, the onTabUnselected(Tab tab, FragmentTransaction ft) method is called. In this method, we detach the fragment because it shouldn't be displayed. When the tab is reselected, the onTabReselected(Tab tab, FragmentTransaction ft) method is called. We do nothing in this method. In the Chapter1ActionBarTabActivity class, we create and set up the action bar. Layout for our activity has nothing but a LinearLayout layout and we use fragments for the user interface. Firstly, we set the navigation mode of action bar to ActionBar.NAVIGATION_MODE_TABS because we want tabbed navigation. Then we create two tabs, set their TabListener events, and add them to the action bar instance. When you run the application, you will see two tabs named FIRST TAB and SECOND TAB. The first tab will display Fragment A and the second tab will display Fragment B. The screen will look like the following:

It is important not to forget to set the minimum SDK level to API Level 11 or higher, because the action bar was introduced in API Level 11.

 

Summary


In this chapter, you learned how to use the action bar as this approach is more consistent than using the options menu. You also saw how to create custom layouts in the action bar using the ActionProvider. You learned how to use ShareActionProvider and how it is an effective way of implementing sharing in your app. You learned how to use the action view and how to make it collapsible. Finally, you learned how to use a the ction bar for tabbed navigation. It has the advantages of adapting itself to device screen size, so it is better to use the action bar than using older APIs. In the next chapter, we are going to learn about an Android layout called GridLayout and we will see how to add and configure it.

About the Author

  • Murat Aydin

    Murat Aydin is a senior software engineer in a company that develops software technologies for defense systems, and is an enthusiastic Android developer. He has several Android applications in Google Play. He is a Sun Certified Java Developer and has eight years of experience in developing web based applications using Java technologies, and desktop and engineering applications using .Net technologies. Murat Aydin earned his BSc degree in Computer Engineering from METU (Middle East Technical University) and his MSc degree in Software Engineering from METU. He is a member of GDG Ankara (Google Developer Group Ankara, www.gdgankara.org), who organize several Android events in GDG Ankara, such as Android Developer Days. (www.androiddeveloperdays.com). He is married and lives in Ankara with his wife Ülkü. Linkedin: http://www.linkedin.com/pub/murat-ayd%C4%B1n/33/702/6a2 Twitter: @maydintr

    Browse publications by this author
Book Title
Access this book, plus 7,500 other titles for FREE
Start FREE trial