Sunday, November 3, 2013

ActionBarCompat - Action Item's basics

This post discusses how to add Actionitem's using compat library. For configuring v7 libararies, look here.

My Menu acction_bar.xml file goes like this.

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

    <item
        android:id="@+id/action_settings"
        compat:showAsAction="always"
        android:title="@string/action_settings"/>
    <item
        android:id="@+id/action_help"   
        compat:showAsAction="never"
        android:title="@string/action_help"/>
    
</menu>

Observe the above XML contain's xmlns:compat attribute. This attribute is pointing to the Application resources. The attribute compat:showAsAction will bind at run time and thus uses compat library. It is very important to use xmlns:compat.

Use the Menu xml in my ActionBarActivity like

@Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.acction_bar, menu);
        return true;
    }


Output :

Action bar with Action bar compat libararies



Action bar compatible library configuration

Android is providing compat libraries for Android level grater than 7 i.e Andorid Os version 2.1 and above. In this post I would like to discuss the configuration of Actionbar Compat project.

  • Download V7 library project from here
  • Import the downloaded project into the current work space.
  • Build the project.
  • Create  New Android Project.
  • Add the imported project as the supporting project.
Properties of the new working project

As shown above, add the  supporting project as library for the current working project.
Now you are ready with the configuration. 

Post configuration:
Some points to be noted for using the App compat action bar are:
  • The Class which wish to use AppCompat features must extend with ActionBarActivity.
  • In the res - > values --> styles.xml, Modify the AppBaseTheme to
    • <style name="AppBaseTheme" parent="Theme.AppCompat.Light"> for light theme.

Friday, July 26, 2013

BB10 QTranslator and QLocale

In our apps, language change is very common functionality. Before jumping into that topic, let us see the basics QLocale and QTransaltor.

      QLocale contains the language and country details. QLocale() will construct a locale object with the system language and locale. If you want to construct a locale of you interest, then initialize like this

QLocale englishLocale = QLocale(QLocale::English, QLocale::UnitedStates);
std::cout << "Locale is : " << englishLocale.name().toStdString();

The output for the above code is en_US.

     To add a new locale support to your application go to bardescreptor.xml --> Localization tab. You can find the default language already defined. To add your support, click on Add and select the language from the list. This will  be like

Select language

  I'm selecting Hindi from the list. Then we can specify the title, app icon, splash screen in the right pane when the locale is changed to Hindi. The specified values will be automatically reflected once the system language is changed to Hindi. Reference picture below.


     Once you build the application, under the translations folder of the project, projectname_hi.ts will be automatically generated. See the red circle in the above picture. We can define, the hindi translation for a specific string in the generated files.

The question is how will we load these .ts files into our application. This leads us to QTranslator.

     QTranslator is capable of loading the language string file(.ts format) for the specified locale with simple steps.
  • Create a locale object
  • Load the translator with that locale
  • Install the translator into the application. 
QLocale hindiLocale = QLocale(QLocale::Hindi, QLocale::India);
QTranslator translator;
QString locale_string = hindiLocale.name();
QString filename = QString("FileHandling_%1").arg(locale_string);
if (translator.load(filename, "app/native/qm")) {
    Application::instance()->installTranslator(&translator);
}

     In the above code, we are instantiating hindiLocale, initializing translator object, getting the name of hindi locale, load it into  translator, install the translator to the application.

If the specified locale is not found, application will install the default locale.

Tuesday, July 23, 2013

Listview with CustomListItem in Blackberry 10

Listview in BB 10 follows MVC architecture. Here we will learn how to add custom rows to listview. To start, we have to look into 4 topics.

  1. Listview component (View)
  2. DataModel (Model)
  3. ListItemProvider (Controller)
  4. ListItem
The below picture illustrates the overview of listview.



The data of the listview is present in DataModel. ListitemProvider is a factory class which creates the listitem with the data present in the DataModel. At run time, listview will pass the datamodel to the ListItemProvider which then uses DataModel and creates a ListItem. The ListItem is a single row of the ListView.

Let us jump into the example for more practical view.


QuotesListItemProvider *myItemProvider = new QuotesListItemProvider(0);
ArrayDataModel *listDataModel = new ArrayDataModel();
// Here Add data to the listmodel .
// In my case I added strings to the dataModel.
ListView *listView = pane->findChild("quotesList");
listView->setDataModel(listDataModel);
listView->setListItemProvider(myItemProvider);

In the above code, I extracted the listview from the QML, initialised ArrayDataModel, appended data to the model, initialized costom ListItemProvider (QuotesListItemProvider), attached datamodel and listitemprovider to the listview.

To define a CustomListItemProvider class it is mandatory to inherit ListItemProvider class. Our custom class should override createItem() and updateItem() functions of ListItemProvider

QuotesListItemProvider.h is 


#include <bb/cascades/ListItemProvider>
#include <bb/cascades/ListView>
#include <bb/cascades/Container>
#include <bb/cascades/VisualNode>
#include <QVariant>

using namespace bb::cascades;


class QuotesListItemProvider: public bb::cascades::ListItemProvider {
public:
    QuotesListItemProvider(Container *container);
    virtual ~QuotesListItemProvider();

    VisualNode * createItem(ListView* list, const QString &type);
    void updateItem(ListView* list, VisualNode *listItem, 
        const QString &type, const QVariantList &indexPath,
        const QVariant &data);

private:
    Container *container;
};

QuotesListItemProvider.cpp is:

#include "QuotesListItemProvider.h"
#include "QuotesListItem.h"
#include <bb/cascades/StandardListItem>
#include <bb/cascades/LayoutProperties>

QuotesListItemProvider::QuotesListItemProvider(Container *container) {
    this->container = container;
}

QuotesListItemProvider::~QuotesListItemProvider()
{

}

VisualNode * QuotesListItemProvider::createItem(ListView* list,
        const QString &type) {
    
    QuotesListItem *myItem = new QuotesListItem(container);
    return myItem;
}

void QuotesListItemProvider::updateItem(ListView* list,
        bb::cascades::VisualNode *listItem, const QString &type,
        const QVariantList &indexPath, const QVariant &data) {
   
    QuotesListItem *myItem = static_cast(listItem);
    myItem->setTitle(data.toString());
}

In createItem() function, ListItem's are created. The created listitems are then passed to updatedItem() function. Observe the first line of UpdateItem method, VisualNode is casted to  CustomListItem(QuotesListItem). And also the parameter 'data' of QVariant type in updateItem() function is the data of our ArraydataModel in ListView. As our DataModel contains strings, I'm converting this into the string format and updated label in QuotesListItem class.

For creating a list row ( Custom ListItem), we have to inherit CustomControl. 

QuotesListItem.h is 

#include <QObject>
#include <QUrl>
#include <iostream>
#include <bb/cascades/CustomControl>
#include <bb/cascades/QmlDocument>
#include <bb/cascades/Container>
#include <bb/cascades/Image>
#include <bb/cascades/ImageView>
#include <bb/cascades/Label>
#include <bb/cascades/controls/activityindicator.h>

using namespace bb::cascades;

class QuotesListItem: public CustomControl {
    Q_OBJECT
public:
    virtual ~QuotesListItem();
    void setTitle(QString text);
    QuotesListItem(Container *container);

private:

    QString pictureURL;
    Label *label;
    void init();
};

QuotesListItem.cpp is


#include "QuotesListItem.h"
#include "bb/cascades/StackLayout"

QuotesListItem::QuotesListItem(Container* container) :
        CustomControl(container) {

    QmlDocument *document = 
             QmlDocument::create("asset:///QuotesListItem.qml");
    Container *rootContainer = document->createRootObject();

    label = rootContainer->findChild

In this class, I'm inflating a QML and used setRoot function of CustomControl class to attach the QML's root object. setTitle() function is used to set the text. This function is called from updateItem()  of QuoteListItemProvider class.


Friday, June 14, 2013

Json parsing in BB 10

Generally, in many development technologies, we will be adding JSON api to project or provided by OS itself and parse the appropriate response using JSON API's. Here it is a different approach.
  1. Convert JSON response to QVariant using JsonDataAccess.
  2. Query the QVariant object for JSON children Nodes.
[
  {
    "id": "13",
    "en_description": "If leadership does not keep",
    "ar_description": "\u0625\u0646 \u0627",
    "date": "2012-09-28"
  },
  {
    "id": "14",
    "en_description": "The role of the leadership",
    "ar_description": "\u062f\u0648\u0631 \u0627",
    "date": "2012-09-28"
  }
]

In the above Json, I am likely to parse the data of "en_descreption" tag. The method to parse is shown below.

void Quotes::onUrlLoad(QString jsonResponse) {

    ArrayDataModel *arrayDataModel = new ArrayDataModel();

    //  Convert Json file into QTList objects.
    bb::data::JsonDataAccess ja;
    const QVariant jsonva = ja.loadFromBuffer(jsonResponse);
    const QList externalip = jsonva.toList();

    //  Iterate Json List and retrieve data, store it in ArraydataModel
    for (int index = 0; index < externalip.size(); index++) {

        QVariantMap map = externalip.at(index).toMap();
        QVariantMap::Iterator iterator = map.begin();
        while (iterator != map.end()) {
            //  Append "en_descreption" tag's value to the ArrayDataModel.
            if (!iterator.key().toStdString().compare("en_description")) {
                arrayDataModel->append(iterator.value().toString());
            }
            ++iterator;
        }   //  end while.
    }   //  end for

}

Above code does the following things 
  1. Loads Json string using JsonDataAcces.
  2. Converts the Json String to root QVariant object with the help of JsonDataAccess.
  3. Get the List of QVariant variables from the root QVariant variable . Note that as our JSON is an array hence we are using jsonva.toList(). Otherwise we have to use jsonva.toMap() as per documentation.
  4. Pull each QVariantMap from the list.
  5. Iterate the map for the values.
  6. Extract values with "en_description" and store it in ArrayDataModel.
That's it .. we are done with parsing and storing JSON data.

Wednesday, June 5, 2013

Navigation Mode's in Android Action Bars

Actions bar's can be represented in 3 different styles or formats

All these modes can be achieved using Sherlock as well as Native Action bar's. Native action bar's are supported from Android OS Version 3.0 and above.

Sherlock ActionBar with NavigationList

NavigationList is one more type of navigation in ActionBar's which serves the same functionality as tabs.

Let me show you how this look's like
Gmail App with Navigation list mode 
In the above pic, Upon click of Inbox, the navigation list appears.

If you are not familiar with the configuration of Sherlock Action Bar project please refer my previous post.

Comming back...To achieve List style of navigation mode, set the navigationmode of Action bar to ActionBar.NAVIGATION_MODE_LIST and pass the respective adapter for this list. The code is shown below.

/**
* Initialises the views and variables of the activity.
 */
private void init() {

    //  initialise ActionBar
    mActionBar = getSupportActionBar();
    mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
        
    //  Initialise Array Adapter.
    final ArrayAdapter arrayAdapter = new ArrayAdapter(this,
         android.R.layout.simple_spinner_dropdown_item, android.R.id.text1);
    arrayAdapter.add("Login");
    arrayAdapter.add("Elections");
    arrayAdapter.add("Maintainance");
    arrayAdapter.add("Results");
        
    //  Set array adapter to navigation list, implement a listener for the list.
            mActionBar.setListNavigationCallbacks(arrayAdapter, new OnNavigationListener() {
            @Override
            public boolean onNavigationItemSelected(int arg0, long arg1) {
                Toast.makeText(SherlockListActionBarActivity.this, arrayAdapter.getItem(arg0), Toast.LENGTH_SHORT).show();
                return false;
            }
        });
}

The above method should be called from onCreate() method of your SherlockActivity.

This method defines ActionBar, Prepares the Adapter for NavigationList, sets call back for Navigation List item click.

Related topics:

Tuesday, June 4, 2013

Android Sherlock Action Bars with Tab's

Action bar's provide a functionality to integrate tabs.

As mentioned in my previous post I'm just recapping how to configure Sherlock API with our project. 

Steps to implement Sherlock action bar include.
  • Download Sherlock source.
  • UnZip the source and find "actionbarsherlock" folder, which is the library project for implementing Sherlock ActionBar.
  • Import the library project into the workspace.
  • Create a new Android Project.
  • Click on properties of the project and add "actionbarsherlock" as library project.

  • Extend your class with SherlockActivity        
public class SherlockAtionBar extends SherlockActivity
  • Override onCreate and setTheme as one of the sherlock theme before calling super.onCreate()
Now, we are almost ready to implement our tabbed action bar.

Here I would like to use a ViewPager, Fragments along with Tab's.  Add tabs to ActionBar, intialiase FragmentPagerAdapter, set FragmentPagerAdapter to ViewPager, integrate tab clicks with viewpager.

The complete activity looks like

import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.ActionBar.Tab;
import com.actionbarsherlock.app.ActionBar.TabListener;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.vl.actionbar.LoginFragment;
import com.vl.actionbar.R;

import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.view.ViewParent;

import java.util.ArrayList;

/**
 * Sherlock Action Bar to demonstrate Tabs behavior
 * 
 * @author shpolavarapu
 * 
 */
public class SherlockTabsActionBarActivity extends SherlockFragmentActivity {

    private ViewPager mViewPager;
    private ActionBar mSupportActionBar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setTheme(R.style.Theme_Sherlock_Light_DarkActionBar);
        super.onCreate(savedInstanceState);
        
        init();
    }

    /**
     * Initialises the Views and variables for this activity.
     */
    private void init() {
        
        //  Initialise and set viewpager to the activity.
        mViewPager = new ViewPager(this);
        mViewPager.setId(1232);
        setContentView(mViewPager);
        
        //  Init and set ActionBar Properties.
        mSupportActionBar = getSupportActionBar();
        mSupportActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
        
        //  Initialise Adapter for the view pager.
        SherlockTabAdapter adapter = new SherlockTabAdapter();
        ArrayList<Bundle> bundleAL = new ArrayList<Bundle>();
        String texts[] = {"Login", "Elections", "Polling", "Results"};
        for(int index = 0; index < texts.length; index++)
        {
            //  Prepare Bundle object for each tab.
            Bundle bundle = new Bundle();
            bundle.putString("text", texts[index]);
            bundleAL.add(bundle);
            
            //  Add tabs for the action bar.
            ActionBar.Tab tab = mSupportActionBar.newTab().setText(texts[index])
                    .setTabListener(adapter);
            mSupportActionBar.addTab(tab);
        }
        
        adapter.setBundle(bundleAL);
        mViewPager.setAdapter(adapter);
        mViewPager.setOnPageChangeListener(adapter);
    }




    /**
     * Adapter for setting the content for the tab click's.
     * 
     * @author shpolavarapu
     * 
     */
    private class SherlockTabAdapter extends FragmentPagerAdapter implements ActionBar.TabListener,
            ViewPager.OnPageChangeListener {

        private ArrayList<Bundle> mBundleAL;
        
        public SherlockTabAdapter() {
            super(getSupportFragmentManager());
        }
        
        /**
         * ArrayList of bundle's to pass as Arguments to Fragment.
         * @param bundleAL  ArrayList of bundle's
         */
        void setBundle(ArrayList<Bundle> bundleAL) {
            mBundleAL = bundleAL;
        }
        @Override
        public void onPageScrollStateChanged(int position) {
            
        }

        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {

        }

        @Override
        public void onPageSelected(int position) {
            //  Change the tab selection upon page selection.
            mSupportActionBar.setSelectedNavigationItem(position);
        }

        @Override
        public void onTabReselected(Tab arg0, FragmentTransaction arg1) {

        }

        @Override
        public void onTabSelected(Tab tab, FragmentTransaction arg1) {
            //  On Tab selection change the View Pager's Current item position. 
            mViewPager.setCurrentItem(tab.getPosition());
        }

        @Override
        public void onTabUnselected(Tab arg0, FragmentTransaction arg1) {

        }

        @Override
        public Fragment getItem(int pos) {
            return Fragment.instantiate(SherlockTabsActionBarActivity.this, LoginFragment.class.getName(), mBundleAL.get(pos));
        }

        @Override
        public int getCount() {
            return mBundleAL.size();
        }

    }

}

The LoginFragment is posted below.

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class LoginFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        
        View view = inflater.inflate(R.layout.login, null);
        if(getArguments() != null)
        {
            String text = getArguments().getString("text");
            ((TextView)view.findViewById(R.id.tv_login)).setText(text);
        }
        return view;
    }
}

login Layout is posted below :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    android:orientation="vertical" >

     <TextView
        android:id="@+id/tv_login"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Login" />


</LinearLayout>

Output :


Overview:

 Create Tabs and ArrayList of Bundle data which contain name of the tab. Create a ViewPager and set the FragmentPagerAdaper to it. The Adapter also listens TabClick and ViewPager PageChange. On TabClick, Login Fragment with the bundle data as arguments is instantiated  and supplied to viewpager.

Don't forget to add NavigationMode as ActionBar.NAVIGATION_MODE_TABS. Native Action Bar's implementation with tabs can also use the same code with minor changes,

Related topics : 

Android Action Bar MenuItem's using Sherlock API

Android introduced Action bar's in API level 11 i.e in HoneyComb 3.0. Native implementation is posted here.  There is no backward compatibility as of now. This leads to our point of discussion.

In some cases where our action bar needs to be compatible from Android SDK version 2.1. In such cases we can go with Sherlock API.

Steps to implement Sherlock action bar include.
  • Download Sherlock source.
  • UnZip the source and find "actionbarsherlock" folder, which is the library project for implementing Sherlock ActionBar.
  • Import the library project into the workspace.
  • Create a new Android Project.
  • Click on properties of the project and add "actionbarsherlock" as library project.


Now, we are ready to implement our action bar.

1) Extend your class with SherlockActivity
            
public class SherlockAtionBar extends SherlockActivity

2) Override onCreate and setTheme as one of the sherlock theme before calling super.onCreate()

@Override
protected void onCreate(Bundle savedInstanceState) {
    setTheme(R.style.Theme_Sherlock);   
    super.onCreate(savedInstanceState);
    setContentView(R.layout.login);
}

3) Override onCreateOptionsMenu()


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Collapsible Action Item
    menu.add("Search").setIcon(R.drawable.ic_search)
                      .setActionView(R.layout.collapsible_edittext)  
                          .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | 
                                  MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);

    // OverFlow menu in actionbar.
    SubMenu submenu = menu.addSubMenu("");
    submenu.setIcon( R.drawable.abs__ic_menu_moreoverflow_normal_holo_dark);

    submenu.add(1, 0, 1, "Cut");
    submenu.add(1, 1, 2, "Copy");
    submenu.add(1, 2, 3, "Paste");
    submenu.getItem(). setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS|
                         MenuItem.SHOW_AS_ACTION_WITH_TEXT);
    // end overflow menu

   return true;
}


My collapsible_edittext layout looks like


<EditText xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:hint="Search"/>


That's it ..... our action bar with menu items and action view is ready. Snapshot of output is shown below.
 
Sherlock action bar with Action view, menu item's and sub menu item's

 I will now explain code in OnCreateMenuOptions(). First with the submenu thing.

If we add menu items to Menu directly using Menu.add(), Actionbar will have different UI for different OS versions of Android. For 3.0 and above it will be shown as overflow menu like in the above picture. For Android OS version's less than 3.0, action bar's overflow type of menu is overrided by the default menu's(at the bottom). I think you got my point... For consistent behaviour of overflow menu's, we have to use SubMenu instead of Menu. Don't forget to add setShowAction() property for the sub menu item. This property will change the style of the menu's to overflow.

We also have some default things for an activity such as Search. Considering these functionalities,  concept of ActionViews is introduced. In the above discussed OnCreateMenuOptions(), we have added search menu item to Menu and provided collapsible_edittext layout for the ActionView. Upon click of search Menu Item the layout appears on the top of action bar like ..

Sherlock ActionBar with Action View.
As per our layout edit text appears with hint as Search.

Split ActionBar :

 We can split the action bar based on the space availability. Just add a tag android:uiOptions = "splitActionBarWhenNarrow".

Observe the change in the below output by using this tag.

Split action bar in Android Phone
The split behavior is different in large screens. See the below output in Nexus 10 device.


From this observation, we can judge that split behavior comes into act when there is no real estate to display on action bar .

Related topics : 

Sunday, June 2, 2013

Android Http Live Streaming(HLS)

Http Live streaming(HLS) allows applications to stream the media content of servers. If you would like to follow HLS standards, the content type of the media should be in the format of m3u8. m3u8 file is a meta data container for the media information to play. As m3u8 is supported by Android 3.1 and above, if we provide m3u8 URL's the streaming will be automatically done by the Media Player or VideoView  object.

VideoView videoView = (VideoView) findViewById(R.id.videoView);
String httpLiveUrl = "http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8";
videoView.setVideoURI(Uri.parse(httpLiveUrl)); 
videoView.setMediaController(new MediaController(this));
videoView.requestFocus();
videoView.start();

Some of the working urls include

http://qthttp.apple.com.edgesuite.net/1010qwoeiuryfg/sl.m3u8
http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8

To support Android versions 2.1 and above use third party vitamo player.

Saturday, June 1, 2013

Andoroid Action Bar Menu items

ActionBar is a header sort of thing with number of powerful options to play with the application.
Let us come to a conclusion why to go for an action bar?

We will be having some options in our activity like.. popping a Menu, search in the activity, Tabs, title, app icon  etc. Think, if there is a mechanism where we can handle all these tasks in a single view sort of thing.. Yes .. this can be achieved by action bars.

The above pic represents action bar in Google Play App.

Before learning the tabbed behavior, we will go through the integration of menu items with Actionbars. The new menu items with action bar looks like :


Three vertical dots represent the Menu, Upon Click menu items will be populated.

Coming to implementation, there are no changes compared to implementation of menu in previous versions.
  1. Define menu options in xml.
  2. Inflate them and add it to the menu in OnCreateOptionsMenu method.
My menu action_items.xml look like.

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

    <item
        android:id="@+id/refresh"
        android:icon="@drawable/refresh"
         
        android:title="Refresh"/>
    <item
        android:id="@+id/inbox"
        android:icon="@drawable/email"
        android:title="Inbox"/>

    <item
        android:id="@+id/compose"
        android:title="Compose"/>

</menu>

Now, Override OnCreateOptionsMenu() and inflate menu. This piece of code is shown below.

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.action_items, menu);
    return true;
}

We are having number of options to arrange menu within this action bar itself. We can display icons for these menu items.For displaying menu icons provide another tag android:showAsAction="ifRoom". This will show the menu item's icon, if there is sufficient room on the ActionBar. This output wil be like


My action_items.xml look like

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

    <item
        android:id="@+id/refresh"
        android:icon="@drawable/refresh"
        android:showAsAction="ifRoom"
        android:title="Refresh"/>
    <item
        android:id="@+id/inbox"
        android:icon="@drawable/email"
        android:showAsAction="ifRoom"
        android:title="Inbox"/>
    <item
        android:id="@+id/compose"
        android:title="Compose"/>

</menu>


Observe showAsAction tag.

We can split the action bar's to the bottom of the screen when screen is narrow. This can be achieved by adding a tag in manifest file. Add android:uiOptions="splitActionBarWhenNarrow" tag in the Activity of manifest file. The output will be looking like.




With the uiOptions tag in Manifest file, the complete menu is pushed to bottom. In landscape, considering the real estate available, these UI changes wont be reflected. Menu will be placed on the top in landscape mode.

In Some of the devices, where the menu hard key is present, the menu options with 3 dots will not be shown. The default behavior of the device will override the action bar behavior. In such cases, if you strictly want the action bar behavior, call the below method in onCreate() method of your activity.

private void getOverflowMenu() {

     try {
        ViewConfiguration config = ViewConfiguration.get(this);
        Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
        if(menuKeyField != null) {
            menuKeyField.setAccessible(true);
            menuKeyField.setBoolean(config, false);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

For the backward compatibility of Action Bar's, refer to the topic ActionBar's with Sherlock API

Related topics : 

Monday, May 13, 2013

Signals and slots in QML

As like our previous discussion on Signals and slots mechanism, we will follow the same example with a different approach. Approach in the sense, making the signal and slot mechanism work from QML.

Our example output will be like : 



Upon button click signal, change label text

T

The completed mechanism is done in QML. The QML file will look like:

import bb.cascades 1.0

Page {
    Container {
        Button {
            id: myButton
            text : "emit signal"
            horizontalAlignment: HorizontalAlignment.Left
            signal buttonClicked(string text)   //  declare signal
            onClicked: {
                myButton.buttonClicked.connect(label.changeText);   //  connect signal and slot
                myButton.buttonClicked("Button Clicked")    //  Call slot.
            }
        }   //  end button
        Label {
            id: label
            horizontalAlignment: HorizontalAlignment.Right
            text: "Im a label"
            function changeText(text) {
                label.text = text;
            }
        }   //  end label
    }   //  end contianer
}   //  end page

Here comes the detailed explanation in 4 steps :

1)In Button, I'm declaring the signal for the buttonclick.

signal buttonClicked(string text)   //  declare signal

2)Write a slot function to listen the signal.

function changeText(text) {
                label.text = text;
            }

3) Connect the signal and slot.

 myButton.buttonClicked.connect(label.changeText);   //  connect signal and 

4) Call slot method

myButton.buttonClicked("Button Clicked")    //  Call slot.


By this way, we can use signals and slots mechanism from QML.