Showing posts with label Android Application. Show all posts
Showing posts with label Android Application. Show all posts

Sunday, July 22, 2012

Monkey test on Android application.

You may be wondering about the test name or thinking that it may be a misnomer. Well, this is not a misnomer. It is a kind of stress test done on an application.

Monkey Test:

Monkey test is a kind of Unit test that runs with no specific test case in mind. Test cases are randomly selected and executed. For example, giving random string to text-field or clicking some random buttons of the application. These kind of test cases check the stability of the application. Monkey test is a kind of black box test.
In my career, I have seen such kind of tests in telecommunication domain (handset manufacturer). In such test cases, the tester can do any sort of random things on the phone and check whether the phone application can handle such scenario or not. In real world no one is going to educate people about how to use the phone. They use the phone in N number of ways and expect it to work under all circumstances. 

Android Monkey test:

If you are an Android application developer and want to do Monkey test on the application, then you can use Android Monkey command line application. It generates a stream of random pseudo user events such as button click, touch, gesture etc. This application can be run on your device or emulator. Monkey test can be used to do stress test on the application.

Perquisite: Android SDK should be present and Android Debug Bridget(ADB) should be accessible. 

During the test if an exception occurs or the application crashes, then Monkey will stop the execution or you can even instruct Monkey to continue the test after exception. It also provides certain debugging configurations where you can configure monkey to get the test execution log.
You may be wondering if Monkey randomly generates the events,  then is it possible to create the same test scenario? I would say yes, Monkey takes care of that. If you give the same seed value (-s option) then Monkey creates same sequence of events. This feature enables you to reproduce the same scenario and allows to take the log and analayze the issue.

Running Monkey test on Android application:

#basic command format:
$ adb shell monkey [options] <event-count>
#To get command argument information, run the following command.
$ adb shell monkey --help
#The command below exercises monkey test on given package(your.package.name here)
# It enables the verbosity and fires 500 random events
$ adb shell monkey -p your.package.name -v 500 
#If you want to increase the verbosity, then increase the number of v like shown below.
#The default verbosity is Level 0 which shows minimum information, 
#i.e startup notification, test completion, and final results
$ adb shell monkey -p your.package.name -vvv 500 
#you can also target activity with certain category
#e.g android.intent.category.LAUNCHER
$ adb shell moneky -p your.package.name -c android.intent.category.LAUNCHER -v 500
#The throttle option enables you to keep delay between events.
#The command below fires events after 3 seconds and generates 50 events.
$adb shell monkey -p your.package.name -v -throttle 3000 50 

you can know more about Application Exerciser Monkey here

Monkey, sometimes, creates problem with adb server. If you notice that adb server is not behaving properly, then you may have to restart the server. Use the following command to do so.
adb kill-server
adb start-server 


Related topics:
Android tutorials
How to do stuff in Android?

Your valuable comments are always welcomed. It will help to improve my post and understanding.

"By three methods we may learn wisdom: First, by reflection, which is noblest; Second, by imitation, which is easiest; and third by experience, which is the bitterest." 
By : Confucius

Friday, July 20, 2012

How to check the Android build version during runtime?

Suppose you are writing an application and want to make sure that min sdk version is supported by the application,  well in such a scenario you would probably specify it in the Android manifest using the following tag.
   <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="11" /> 
True, but what if you are using feature which is not essential for application and is available on certain Android API level or above? Definitely, you will enable or disable the component based on the availability. For example, the application uses the ActionBar available on Android API level 11 or above and you need to determine the Android version during runtime to enable/disable the application component using the ActionBar. The answer to all this is Build class . Build class helps to determine the Android version during run-time. Example code is shown below.

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
            ActionBar actionBar = getActionBar();
            actionBar.setDisplayHomeAsUpEnabled(true);
        }

Related topics:
Android tutorials
How to do stuff in Android?

Your valuable comments are always welcomed. It will help to improve my post and understanding.

"By three methods we may learn wisdom: First, by reflection, which is noblest; Second, by imitation, which is easiest; and third by experience, which is the bitterest."
By : Confucius

Tuesday, July 17, 2012

Tutorial on new Android Jelly Bean notification

You may have heard about Android Jelly Bean (API level 16). Google has improved a lot of features and introduced new features. One of them is the notification. Now they have made the notification more versatile by introducing media rich notification. Google has come up with three special style of notification which are mentioned below. Even developer can write his own customized notification style using remote view.The old Notification class constructor has been deprecated and a brand new and enhanced version of Notification has been introduced.

Notification Type:

  • Basic Notification - Shows simple and short notification with icon.
  • Big Picture Notification - Shows visual content such as bitmap.
  • Big Text Notification - Shows multiline Textview object.
  • Inbox Style Notification - Shows any kind of list, e.g messages, headline etc. 

Old syntax requires us to create an object of notification but now Android uses builder patter to create the notification object. Notification.Builder class has been introduced to make this task easier. This class returns the builder object which is configurable according to your requirements. The helper classes have been introduced like Notification.BigPictureStyle, Notification.BigTextStyle, and Notification.InboxStyle. These classes are re-builder classes which take object created by Notification.Builder class and  modify the behavior like so.

Project Information: Meta-data about the project.

Platform Version : Android API Level 16.
IDE : Eclipse Helios Service Release 2
Emulator : Android 4.1(API 16)

Prerequisite: Preliminary knowledge of Android application framework, and Intent.

First create project by Eclipse > File> New Project>Android Application Project. The following dialog box will appear. Fill the required field, i.e Application Name, Project Name and Package Name. Don't forget to select the Build SDK version (for this tutorial Google API 16 has been selected). Now press the next button.

 Once the dialog box appears, select the BlankActivity and click the next button.



 Fill the Activity Name and Layout file name for the dialog box shown below and hit the finish button.


This process will setup the basic project files. Now we are going to add four buttons in the activity_main.xml file.  You can modify the layout file using either Graphical Layout editor or xml editor. The content of the file should look like this.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center_horizontal">

    <Button
        android:id="@+id/btBasicNotification"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal|center_vertical"
        android:onClick="sendBasicNotification"
        android:text="@string/btBasicNotification" 
        android:background="@drawable/button_background"
        android:textColor="#000000"
        />
    <Button
        android:id="@+id/btBigTextNotification"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal|center_vertical"
        android:onClick="sendBigTextStyleNotification"
        android:text="@string/btBigTextNotification" 
        android:background="@drawable/button_background"
        android:textColor="#000000"
        />
   <Button
        android:id="@+id/btBigPictureNotification"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal|center_vertical"
        android:onClick="sendBigPictureStyleNotification"
        android:text="@string/btBigPictureNotification"
        android:background="@drawable/button_background"
        android:textColor="#000000" />
   <Button
        android:id="@+id/btInboxStyleNotification"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal|center_vertical"
        android:onClick="sendInboxStyleNotification"
        android:text="@string/btInboxStyleNotification"
        android:background="@drawable/button_background"
        android:textColor="#000000"/>
</LinearLayout>

You may have noticed that onClick methods are associated with respective buttons. If you don't know how to define and use the background file for view then ignore the android:background field. Now we are going to define the methods sendBasicNotification, sendBigTextStyleNotification, sendBigPictureStyleNotification and sendInboxStyleNotification. As the method name suggests, it sends that particular kind of notification. In each method we are creating Notification.Builder object, and customizing the object. Here builder pattern has been used to customize the object. Once the customization is done,  call build() method to get the notification object. In this new notification system, at most three actions can be associated to a notification, which are displayed below the notification content.  This can be achieved by calling addAction() method on the builder object. The same number of icons you will see on the notification as you will notice for sendBigPictureStyleNotifcation() method. Notification priority can also be set by calling setPriority() method as shown in sendBigTextStyleNotification() method. In the code given below, intent has been used to invoke the HandleNotificationActivity.

package com.example.jellybeannotificationexample;

import android.app.Activity;
import android.app.Notification;
import android.app.Notification.Builder;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;

public class NotificationMainActivity extends Activity {

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
 }

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

 public void sendBasicNotification(View view) {
  Notification notification = new Notification.Builder(this)
    .setContentTitle("Basic Notification")
    .setContentText("Basic Notification, used earlier")
    .setSmallIcon(R.drawable.ic_launcher_share).build();
  notification.flags |= Notification.FLAG_AUTO_CANCEL;
  NotificationManager notificationManager = getNotificationManager();
  notificationManager.notify(0, notification);
 }

 public void sendBigTextStyleNotification(View view) {
  String msgText = "Jeally Bean Notification example!! "
    + "where you will see three different kind of notification. "
    + "you can even put the very long string here.";

  NotificationManager notificationManager = getNotificationManager();
  PendingIntent pi = getPendingIntent();
  Builder builder = new Notification.Builder(this);
  builder.setContentTitle("Big text Notofication")
    .setContentText("Big text Notification")
    .setSmallIcon(R.drawable.ic_launcher)
    .setAutoCancel(true);
    .setPriority(Notification.PRIORITY_HIGH)
    .addAction(R.drawable.ic_launcher_web, "show activity", pi);
  Notification notification = new Notification.BigTextStyle(builder)
    .bigText(msgText).build();
 
  notificationManager.notify(0, notification);
 }

 public void sendBigPictureStyleNotification(View view) {
  PendingIntent pi = getPendingIntent();
  Builder builder = new Notification.Builder(this);
  builder.setContentTitle("BP notification")
    // Notification title
    .setContentText("BigPicutre notification")
    // you can put subject line.
    .setSmallIcon(R.drawable.ic_launcher)
    // Set your notification icon here.
    .addAction(R.drawable.ic_launcher_web, "show activity", pi)
    .addAction(
      R.drawable.ic_launcher_share,
      "Share",
      PendingIntent.getActivity(getApplicationContext(), 0,
        getIntent(), 0, null));

  // Now create the Big picture notification.
  Notification notification = new Notification.BigPictureStyle(builder)
    .bigPicture(
      BitmapFactory.decodeResource(getResources(),
        R.drawable.big_picture)).build();
  // Put the auto cancel notification flag
  notification.flags |= Notification.FLAG_AUTO_CANCEL;
  NotificationManager notificationManager = getNotificationManager();
  notificationManager.notify(0, notification);
 }

 public void sendInboxStyleNotification(View view) {
  PendingIntent pi = getPendingIntent();
  Builder builder = new Notification.Builder(this)
    .setContentTitle("IS Notification")
    .setContentText("Inbox Style notification!!")
    .setSmallIcon(R.drawable.ic_launcher)
    .addAction(R.drawable.ic_launcher_web, "show activity", pi);

  Notification notification = new Notification.InboxStyle(builder)
    .addLine("First message").addLine("Second message")
    .addLine("Thrid message").addLine("Fourth Message")
    .setSummaryText("+2 more").build();
  // Put the auto cancel notification flag
  notification.flags |= Notification.FLAG_AUTO_CANCEL;
  NotificationManager notificationManager = getNotificationManager();
  notificationManager.notify(0, notification);
 }

 public PendingIntent getPendingIntent() {
  return PendingIntent.getActivity(this, 0, new Intent(this,
    HandleNotificationActivity.class), 0);
 }

 public NotificationManager getNotificationManager() {
  return (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
 }
}


We have defined basic HandleNotificationActivity which just shows a simple message when intent is fired for this activity. The content of the file is as following.
package com.example.jellybeannotificationexample;

import android.app.Activity;
import android.os.Bundle;

public class HandleNotificationActivity extends Activity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.handle_notification_activity);
 }
}

The corresponding layout file(handle_notification_activity.xml) is given below
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
     android:gravity="center_horizontal|center_vertical" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/tvHandleNotification"
        android:textSize="20dp"
        android:textStyle="bold|italic" />

</LinearLayout>

Now you have to define the Android manifiest file. HandleNotificationActivity should be included in the manifest file and then put the intent filter for this activity.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.jellybeannotificationexample"
    android:versionCode="1"
    android:versionName="1.0" >

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

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name">
        <activity
            android:name=".NotificationMainActivity"
            android:label="@string/title_activity_main" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".HandleNotificationActivity"
            android:label="@string/title_activity_main" >
            <intent-filter>
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>


Once you are done with the coding, just execute it. You will see the application as shown in the picture below. On clicking the button you will see the corresponding notification on the upper part of the screen. If you drag the notification down then you can see the entire message and corresponding icon. The  pictures below are the notification when they were dragged down.
jelly bean media rich notification application
Application
Andriod Jelly bean (API 16) Basic notification
Basic notification
Andriod 4.1 (API 16) Big Text style notification
Big Text Style
Andriod 4.1 Jelly bean (API 16) Big picture style notification
Big Picture Style
Andriod 4.1 Jelly bean (API 16) Inbox style notification
Inbox Style

If you are interested to know more about source code, you can find it over here.

Your valuable comments are always welcomed. It will help to improve my post and understanding.

"By three methods we may learn wisdom: First, by reflection, which is noblest; Second, by imitation, which is easiest; and third by experience, which is the bitterest."
By : Confucius

Sunday, July 8, 2012

Tutorial on Android Homescreen Widget with AlarmManager.

This is a follow up tutorial on Android widget. If you haven't read it till now then please go through    it before starting this tutorial. You may be aware that AppWidgetProvider's lowest interval is 30 mins. In this tutorial we will learn  to create widget with update interval less than 30 mins using AlarmManager.

New update:

In Android 4.1, a new feature has been introduced for Homescreen widget which enables widget to reorganize its view when resized. To support this feature a new method onAppWidgetOptionsChanged() has been introduced in AppWidgetProvider class. This method gets called in response to the ACTION_APPWIDGET_OPTIONS_CHANGED broadcast when this widget has been layed out at a new size. 

Project Information:  Meta-information about the project.

Platform Version : Android API Level 16.
IDE : Eclipse Helios Service Release 2
Emulator: Android 4.1

Prerequisite: Preliminary knowledge of Android application framework, Intent Broadcast receiver and AlarmManager.

Example with fixed update interval less than 30 mins.

In this tutorial we will create time widget which shows current time. This widget will get updated every second and we will be using AlarmManager for it. Here, repeating alarm is set for one second interval. But in real world scenario, it is not recommended to use one second repeating alarm because it drains the battery fast. You have to follow the similar steps mentioned in previous widget tutorial  to write widget layout file. But this time we are introducing a TextView field in the layout which will display the time. The content of the "time_widget_layout.xml" is given below.
<linearlayout android:background="@drawable/widget_background" 
   android:layout_height="match_parent" android:layout_width="match_parent" 
   android:orientation="vertical" 
   xmlns:android="http://schemas.android.com/apk/res/android">
     <textview android:gravity="center_horizontal|center_vertical" 
          android:id="@+id/tvTime" android:layout_gravity="center" 
          android:layout_height="match_parent" android:layout_margin="4dip" 
          android:layout_width="match_parent" android:textcolor="#000000" 
          style="android: style/TextAppearance.Medium;"/>
</linearlayout>

Follow the same procedure to create the AppWidgetProvider metadata file. The content of metadata file "widget_metadata.xml" is given below.
  <appwidget-provider android:initiallayout="@layout/time_widget_layout" 
        android:minheight="40dp" android:minwidth="130dp"  
        android:updateperiodmillis="1800000" 
        xmlns:android="http://schemas.android.com/apk/res/android">
</appwidget-provider>

In this tutorial, onEnabled(), onDsiabled(), onUpdate() and onAppWidgetOptionsChanged() have been defined unlike the previous widget tutorial where only onUpdate() was defined. 

  • onEnabled(): An instance of AlarmManager is created here to start the repeating timer and register the intent with the AlarmManager.  As this method gets called at the very first instance of widget installation, it helps to set repeating alarm  only once.
  • onDisabled(): In this method, alarm is canceled because this method gets called as soon as the very last instance of widget is removed/uninstalled and we don't want to leave the registered alarm even when it's not being used.
  • onUpdate(): This method updates the time on remote TextView.
  • onAppWidgetOptionsChanged(): This method gets called when the widget is resized.

package com.rakesh.widgetalarmmanagerexample;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.widget.RemoteViews;
import android.widget.Toast;

public class TimeWidgetProvider extends AppWidgetProvider {

 @Override
 public void onDeleted(Context context, int[] appWidgetIds) {
  Toast.makeText(context, "TimeWidgetRemoved id(s):"+appWidgetIds, Toast.LENGTH_SHORT).show();
  super.onDeleted(context, appWidgetIds);
 }

 @Override
 public void onDisabled(Context context) {
  Toast.makeText(context, "onDisabled():last widget instance removed", Toast.LENGTH_SHORT).show(); 
  Intent intent = new Intent(context, AlarmManagerBroadcastReceiver.class);
  PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
  AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
  alarmManager.cancel(sender);
  super.onDisabled(context);
 }

 @Override
 public void onEnabled(Context context) {
  super.onEnabled(context);
  AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
  Intent intent = new Intent(context, AlarmManagerBroadcastReceiver.class);
  PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
  //After after 3 seconds
  am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+ 100 * 3, 1000 , pi);
 }

 @Override
 public void onUpdate(Context context, AppWidgetManager appWidgetManager,
   int[] appWidgetIds) {
  ComponentName thisWidget = new ComponentName(context,
    TimeWidgetProvider.class);

  for (int widgetId : appWidgetManager.getAppWidgetIds(thisWidget)) {

   //Get the remote views
   RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
     R.layout.time_widget_layout);
   // Set the text with the current time.
   remoteViews.setTextViewText(R.id.tvTime, Utility.getCurrentTime("hh:mm:ss a"));
   appWidgetManager.updateAppWidget(widgetId, remoteViews);
  }
 }

 @Override
 public void onAppWidgetOptionsChanged(Context context,
   AppWidgetManager appWidgetManager, int appWidgetId,
   Bundle newOptions) {
  //Do some operation here, once you see that the widget has change its size or position.
  Toast.makeText(context, "onAppWidgetOptionsChanged() called", Toast.LENGTH_SHORT).show();
 }
}


Broadcast receiver is defined to handle the intent registered with alarm. This broadcast receiver gets called every second because repeating alarm has been set in the AppWidgetProvider classs for 1 second. Here, onReceive() method has been defined which updates the widget with the current time and getCurrentTime() has been used to get the current time.
package com.rakesh.widgetalarmmanagerexample;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
import android.widget.RemoteViews;
import android.widget.Toast;

public class AlarmManagerBroadcastReceiver extends BroadcastReceiver {

 @Override
 public void onReceive(Context context, Intent intent) {
  PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
  PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "YOUR TAG");
  //Acquire the lock
  wl.acquire();

  //You can do the processing here update the widget/remote views.
  RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
    R.layout.time_widget_layout);
  remoteViews.setTextViewText(R.id.tvTime,  Utility.getCurrentTime("hh:mm:ss a"));
  ComponentName thiswidget = new ComponentName(context, TimeWidgetProvider.class);
  AppWidgetManager manager = AppWidgetManager.getInstance(context);
  manager.updateAppWidget(thiswidget, remoteViews);
  //Release the lock
  wl.release();
 }
}

It's always a good idea to keep utility methods in some utility class which can be accessed from other packages. getCurrentTime() has been defined in the Uitility class. This method is used in AppWidgetProvider and BroadcastReciever classes. 
package com.rakesh.widgetalarmmanagerexample;

import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Utility {
  public static String getCurrentTime(String timeformat){
      Format formatter = new SimpleDateFormat(timeformat);
         return formatter.format(new Date());
     }
}

In Android manifest file, we need to include WAKE_LOCK permission because wake lock is used in broadcast receiver. AlarmManagerBroadcastReceiver has been registered as broadcast receiver. Remaining part is simple to understand.
  <manifest android:versioncode="1" android:versionname="1.0" 
      package="com.rakesh.widgetalarmmanagerexample" 
      xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-sdk android:minsdkversion="16" android:targetsdkversion="16"/>

<uses-permission android:name="android.permission.WAKE_LOCK"/>
    <application android:icon="@drawable/ic_launcher" 
          android:label="@string/app_name">
        <activity android:label="@string/title_activity_widget_alarm_manager" 
                android:name=".WidgetAlarmManagerActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <receiver android:icon="@drawable/ic_launcher" 
             android:label="@string/app_name"
             android:name=".TimeWidgetProvider">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
            </intent-filter>
            <meta-data android:name="android.appwidget.provider"  
                android:resource="@xml/widget_metadata"/>
        </receiver>
        <receiver android:name=".AlarmManagerBroadcastReceiver"/>
    </application>
</manifest>

Once the code is executed, the widget gets registered. When you install widget on homescreen, it appears as shown below.
Android Homescreen time widget

you can download source code from here.

Related tutorial:



Your valuable comments are always welcomed. It will help to improve my post and understanding.

"By three methods we may learn wisdom: First, by reflection, which is noblest; Second, by imitation, which is easiest; and third by experience, which is the bitterest."
By : Confucius

Wednesday, June 27, 2012

How to find Android default screen orientation.


Recently while developing my personal project, I had a requirement to find the default screen orientation of device. Tablet default screen orientation is landscape whereas Mobile phone default screen orientation is portrait. 
Well after a little bit of research I found that getRotation method can fetch me the default orientation. This method can be used in the following way: 
this.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()
               .getRotation()
 If this method returns Surface.ROTATION_0 (no rotation) then it means that the current screen orienation is the default screen orientation.  For example, if the tablet is currently in  landscape orientation then this method returns Surface.ROTATION_0(value 0x00000000) else it returns either  Surface.ROTATION_90 or Surface.ROTATION_270.
This arises one more question as how to determine the current orientation of the screen. It can be determined by the following method.
this.getResources().getConfiguration().orientation
The return value can be either of these
Configuration.ORIENTATION_LANDSCAPE
Configuration.ORIENTATION_PORTRAIT
Configuration.ORIENTATION_SQUARE
These values themselves suggest the orientation of the screen. 

Your valuable comments are always welcomed. It will help to improve my post and understanding.

"By three methods we may learn wisdom: First, by reflection, which is noblest; Second, by imitation, which is easiest; and third by experience, which is the bitterest."
By : Confucius

Wednesday, June 13, 2012

Application to send SMS on Android Platform

I have been playing around with Android application in past. I thought of writing a simple application which can send a SMS.
Android has provided android.telephony.SmsManager class which has exposed different methods for sending SMS. If the message size is less than 160 character then we can use the the following method.
sendTextMessage(String destinationAddress, String scAddress,
        String text, PendingIntent sentIntent, PendingIntent deliveryIntent)
If you just want to send the message and not bothered about the send result then just pass the destinalAddress(MDN) and text(Message). 

Here is the code snippet for main Activity class.
package com.rakesh.simpleSms;

import com.rakesh.broadcastreceiver.DeliverSMSBroadcastReceiver;
import com.rakesh.broadcastreceiver.OutgoingSMSBroadcastReceiver;

import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

public class SimpleSMSAppActivity extends Activity {
 private EditText etNumber;
 private EditText etMessage;
 private SmsManager manager;
 public static final int  MAX_MESSAGE_SIZE = 160;
 public static final String SMS_SENT = "SMS_SENT";
 public static final String SMS_DELIVERED = "SMS_DELIVERED";
 private final BroadcastReceiver outgoingSMSBR = new OutgoingSMSBroadcastReceiver();
 private final BroadcastReceiver deliverSMSBR = new DeliverSMSBroadcastReceiver();
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  //  btSendMessage = (Button)findViewById(R.id.btSendMessage);
  etNumber = (EditText)findViewById(R.id.etNumber);
  etMessage = (EditText)findViewById(R.id.etMessage);
  manager =  SmsManager.getDefault();
 }

 public void sendMessage(View view){
  String number = etNumber.getText().toString();
  String message = etMessage.getText().toString();
  Log.d("RK","number : "+number+", message : " + message  );

  if(!isNullOrEmpty(number) && !isNullOrEmpty(message)){
   if(message.length() > MAX_MESSAGE_SIZE){

    Toast.makeText(this,"Message is longer then allowed in SMS",Toast.LENGTH_LONG).show();
   } else{
    PendingIntent piSend = PendingIntent.getBroadcast(this, 0, new Intent(SMS_SENT),0);
    PendingIntent piDelivered = PendingIntent.getBroadcast(this, 0, new Intent(SMS_DELIVERED), 0);

    manager.sendTextMessage(number, null, message, piSend, piDelivered);
    etMessage.setText("");
   }
  }
 }

 @Override
 protected void onResume() {
  registerReceiver(outgoingSMSBR, new IntentFilter(SMS_SENT));

  registerReceiver(deliverSMSBR, new IntentFilter(SMS_DELIVERED));

  super.onResume();
 }

 @Override
 protected void onPause() {
  unregisterReceiver(outgoingSMSBR);
  unregisterReceiver(deliverSMSBR);
  super.onPause();
 }

 private boolean isNullOrEmpty(String string){
  return string == null || string.isEmpty();
 }
}

and two broadcast receiver classes are as following.

OutgoingSMSBroadcastReceiver.java
 
public class OutgoingSMSBroadcastReceiver extends BroadcastReceiver {

 @Override
 public void onReceive(Context context, Intent intent) {
  
  switch(getResultCode()){
  
   case Activity.RESULT_OK:
      Toast.makeText(context, "SMS sent", 
                 Toast.LENGTH_SHORT).show();
      Log.d("RK","RESULT_OK");
         break;
      case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
          Toast.makeText(context, "Generic failure", 
                  Toast.LENGTH_SHORT).show();
          Log.d("RK","RESULT_ERROR_GENERIC_FAILURE");
          break;
      case SmsManager.RESULT_ERROR_NO_SERVICE:
          Toast.makeText(context, "No service", 
                  Toast.LENGTH_SHORT).show();
          Log.d("RK","RESULT_ERROR_NO_SERVICE");
          break;
      case SmsManager.RESULT_ERROR_NULL_PDU:
          Toast.makeText(context, "Null PDU", 
                  Toast.LENGTH_SHORT).show();
          Log.d("RK","RESULT_ERROR_NULL_PDU");
          break;
      case SmsManager.RESULT_ERROR_RADIO_OFF:
          Toast.makeText(context, "Radio off", 
                  Toast.LENGTH_SHORT).show();
          Log.d("RK","RESULT_ERROR_RADIO_OFF");
          break;
  }
 }
}
DeliverSMSBroadcastReceiver.java
package com.rakesh.broadcastreceiver;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;

public class DeliverSMSBroadcastReceiver extends BroadcastReceiver {

 @Override
 public void onReceive(Context context, Intent intent) {
 
          switch (getResultCode())
            {
             case Activity.RESULT_OK:
                Toast.makeText(context, "SMS delivered", 
                        Toast.LENGTH_SHORT).show();
                Log.d("RK","RESULT_OK=> DELIVER");
                break;
             case Activity.RESULT_CANCELED:
                Toast.makeText(context, "SMS not delivered", 
                        Toast.LENGTH_SHORT).show();
                Log.d("RK","RESULT_CANCELED");
                break;                        
            }
 }
}
Make sure you have provided the right permission to application in manifest file.

<manifest android:versioncode="1"   
 android:versionname="1.0" package="com.rakesh.simpleSms" 
 xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-sdk android:minsdkversion="10">
    
 <uses-permission android:name="android.permission.SEND_SMS">
 
    <application android:debuggable="true" android:icon="@drawable/ic_launcher" 
         android:label="@string/app_name">
        
        <activity android:label="@string/app_name" android:name=".SimpleSMSAppActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN">
                <category android:name="android.intent.category.LAUNCHER">
            </category></action></intent-filter>
        </activity>
    </application>
 
</uses-permission></uses-sdk>
You can find the source code here.

Please provide your valuable comments to improve this blog.

"By three methods we may learn wisdom: First, by reflection, which is noblest; Second, by imitation, which is easiest; and third by experience, which is the bitterest."
By : Confucius