Showing posts with label tutorial. Show all posts
Showing posts with label tutorial. Show all posts

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

Friday, July 6, 2012

Tutorial on Android AlaramManager

While writing an application, need arises to schedule execution of code in future. You may require AlarmManager to schedule your work at a specified time. AlarmManager accesses to system alarm and schedules the execution of code even when the application is not running.

Project Information:  Meta-information about the project.

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

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

AlarmManager:

AlarmManager has access to the system alarm services. With the help of AlarmManager you can schedule execution of code in future. AlarmManager object can't instantiate directly however it can be retrieved by calling Context.getSystemService(Context.ALARM_SERVICE). AlarmManager is always registered with intent. When an alarm goes off, the Intent which has been registered with AlarmManager, is broadcasted by the system automatically. This intent starts the target application if it is not  running. It is recommended to use AlarmManager when you want your application code to be run at a specific time, even if your application is not currently running. For other timing operation handler should be used because it is easy to use. Handler is covered in other tutorial.

Method Description
set() Schedules an alarm for one time.
setInexactRepeating() Schedules an alarm with inexact repeating. Trigger time doesn't follow any strict restriction.
setRepeating() Schedules an alarm with exact repeating time.
setTime() Sets the system's wall clock time.
setTimeZone() Sets the system's default time zone.
Check out the AlarmManager documention for more info.

In this tutorial let's learn to create one-time timer and the repeating timer, and also to cancel the repeating timer. Here timer and alarm have been used interchangeably, but in this tutorial context both of them have the same meaning.

Example Code:

Let's create three buttons start repeating timer, cancel repeating timer and one-time timer in the layout file. These buttons are attached with methods i.e startRepeatingTimer, cancelRepeatingTimer and onetimeTimer respecitively. These methods will be defined in the Activity class. The layout file is shown below(activity_alarm_manager.xml).
 <linearlayout android:layout_height="match_parent" 
    android:layout_width="match_parent" android:orientation="vertical" 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools">

    <button android:id="@+id/btStart" android:layout_height="wrap_content" 
      android:layout_width="match_parent" android:onclick="startRepeatingTimer" 
      android:padding="@dimen/padding_medium" android:text="@string/btStart"   
      tools:context=".WidgetAlarmManagerActivity"/>
    <button android:id="@+id/btCancel" android:layout_height="wrap_content" 
      android:layout_width="match_parent" android:onclick="cancelRepeatingTimer"  
      android:padding="@dimen/padding_medium" android:text="@string/btCancel" 
      tools:context=".WidgetAlarmManagerActivity"/>
     <button android:id="@+id/btOneTime" android:layout_height="wrap_content" 
     android:layout_width="match_parent" android:onclick="onetimeTimer" 
     android:padding="@dimen/padding_medium" android:text="@string/btOneTime"   
     tools:context=".WidgetAlarmManagerActivity"/>
   </linearlayout>

We are going to define the BroadcastReciever which handles the intent registered with AlarmManager. In the given class onReceive() method has been defined. This method gets invoked as soon as intent is received. Once we receive the intent we try to get the extra parameter associated with this intent. This extra parameter is user-defined i.e ONE_TIME, basically indicates whether this intent was associated with one-time timer or the repeating one. Once the ONE_TIME parameter value has been extracted, Toast message is  displayed accordingly. Helper methods have also been defined, which can be used from other places with the help of objects i.e setAlarm(), cancelAlarm() and onetimeTimer() methods. These methods can also be defined somewhere else to  do operation on the timer i.e set, cancel, etc. To keep this tutorial simple, we have defined it in BroadcastReceiver.


setAlarm(): This method sets the repeating alarm by use of setRepeating() method. setRepeating() method needs four arguments:

  1. type of alarm, 
  2. trigger time: set it to the current time
  3. interval in milliseconds: in this example we are passing 5 seconds ( 1000 * 5 milliseconds)
  4. pending intent: It will get registered with this alarm. When the alarm gets triggered the pendingIntent will be broadcasted.

cancelAlarm(): This method cancels the previously registered alarm by calling cancel() method. cancel() method takes pendingIntent as an argument. The pendingIntent should be matching one, only then the cancel() method can remove the alarm from the system.

onetimeTimer(): This method creates an one-time alarm. This can be achieved by calling set() method. set() method takes three arguments:

  1. type of alarm
  2. trigger time 
  3. pending intent


package com.rakesh.alarmmanagerexample;

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

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.PowerManager;
import android.widget.Toast;

public class AlarmManagerBroadcastReceiver extends BroadcastReceiver {

 final public static String ONE_TIME = "onetime";

 @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.
         Bundle extras = intent.getExtras();
         StringBuilder msgStr = new StringBuilder();
         
         if(extras != null && extras.getBoolean(ONE_TIME, Boolean.FALSE)){
          //Make sure this intent has been sent by the one-time timer button.
          msgStr.append("One time Timer : ");
         }
         Format formatter = new SimpleDateFormat("hh:mm:ss a");
         msgStr.append(formatter.format(new Date()));

         Toast.makeText(context, msgStr, Toast.LENGTH_LONG).show();
         
         //Release the lock
         wl.release();
         
 }

 public void SetAlarm(Context context)
    {
        AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(context, AlarmManagerBroadcastReceiver.class);
        intent.putExtra(ONE_TIME, Boolean.FALSE);
        PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
        //After after 5 seconds
        am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 5 , pi); 
    }

    public void CancelAlarm(Context context)
    {
        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);
    }

    public void setOnetimeTimer(Context context){
     AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(context, AlarmManagerBroadcastReceiver.class);
        intent.putExtra(ONE_TIME, Boolean.TRUE);
        PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
        am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), pi);
    }
}


Given below is the manifest file. Here, WAKE_LOCK permission is required because the wake lock is being used while processing in onReceive() method present in AlarmManagerBroadcastReceiver class. AlarmManagerBroadcastReceiver has been registered as broadcast receiver.
<manifest android:versioncode="1" android:versionname="1.0" 
       package="com.rakesh.alarmmanagerexample" 
       xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-sdk android:minsdkversion="10" android:targetsdkversion="15"/>
    
<uses-permission android:name="android.permission.WAKE_LOCK"/>
    <application android:icon="@drawable/ic_launcher" 
       android:label="@string/app_name" android:theme="@style/AppTheme">
        <activity android:label="@string/title_activity_alarm_manager" 
           android:name="com.rakesh.alarmmanagerexample.AlarmManagerActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN">

                <category android:name="android.intent.category.LAUNCHER">
            </category>
           </action>
          </intent-filter>
        </activity>
        <receiver android:name="com.rakesh.alarmmanagerexample.AlarmManagerBroadcastReceiver">
        </receiver>
    </application>
</manifest>

Now let's define the activity class which defines some methods. These methods are going to handle the button clicks. Here in this class we create an instance of AlarmManagerBroadcastReciever which will help us to access setAlarm(), cancelAlarm() and setOnetime(). Rest of the code is easy to understand.

package com.rakesh.alarmmanagerexample;

import com.rakesh.alarmmanagerexample.R;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
import android.support.v4.app.NavUtils;

public class AlarmManagerActivity extends Activity {

 private AlarmManagerBroadcastReceiver alarm;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_alarm_manager);
        alarm = new AlarmManagerBroadcastReceiver();
    }
    
    @Override
 protected void onStart() {
  super.onStart();
 }

    public void startRepeatingTimer(View view) {
     Context context = this.getApplicationContext();
     if(alarm != null){
      alarm.SetAlarm(context);
     }else{
      Toast.makeText(context, "Alarm is null", Toast.LENGTH_SHORT).show();
     }
    }
    
    public void cancelRepeatingTimer(View view){
     Context context = this.getApplicationContext();
     if(alarm != null){
      alarm.CancelAlarm(context);
     }else{
      Toast.makeText(context, "Alarm is null", Toast.LENGTH_SHORT).show();
     }
    }
    
    public void onetimeTimer(View view){
     Context context = this.getApplicationContext();
     if(alarm != null){
      alarm.setOnetimeTimer(context);
     }else{
      Toast.makeText(context, "Alarm is null", Toast.LENGTH_SHORT).show();
     }
    }
    
 @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_widget_alarm_manager, menu);
        return true;
    }
}
Once you are done with the coding, just execute the project and you will find the similar kind of application running in your emulator.
AlarmManagerExample is installed in application list AlarmManager:Onetime timer is triggered

Please download AlarmManagerExample code, if you need reference code.
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

Thursday, July 5, 2012

How to search class in jar files using Jarscan

Suppose you are working on a project and want to include a library jar file which has specific java class. But at the same time you don't have much idea about which jar file to include and you are given with a lot of jar files to choose from. How would you figure out which jar file is the most suitable one.
Well here comes Jarscan to rescue. Jarscan is an executable jar file which scans the jar/zip file and lists jar files which contains the desired class.

Prerequisite:
  • Java 1.4 or higher version should be installed in your system. If your system doesn't have it then you can download it from here.  
  • Jarscan which can be downloaded from here.
Here is the command example below:
java -jar jarscan.jar -help                  #This provides help, how to use jarscan.
java -jar jarscan.jar                        #This works as the command above.
#The following command looks for Activity class root from current directory. 
java -jar jarscan.jar -dir . -class Activity  
You can even search classes through database of libraries online hereIf you want more information about Jarscan you can find it here.

You can try the online services here.

Java class file decompilation

What if you are interested to know more about the class methods, variable, etc. and the only thing that you have is the class file. Don't worry, there is a way to know about these methods, variables etc. even without source file. Javap can help you parsing the class file and providing the information about the  desired class. Javap executable comes with java package. Most of the people either aren't aware of it or don't use it because they rely more on IDE(e.g Eclpse)/build system. Here we are going to use the javap command option for the following class.
 
package com.rakesh.simplewidget;
import android.appwidget.AppWidgetManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.Toast;


public class ConnectivityReceiver extends BroadcastReceiver {

 @Override
 public void onReceive(Context context, Intent intent) {
  NetworkInfo info = (NetworkInfo)intent.getExtras().get(ConnectivityManager.EXTRA_NETWORK_INFO);
  
  if(info.getType() == ConnectivityManager.TYPE_MOBILE){
   
   RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
     R.layout.widget_layout);
   
   if(info.isConnectedOrConnecting()){
    Toast.makeText(context, "Data packet enabled", Toast.LENGTH_SHORT).show();
    Log.d("RK","Mobile data is enabled");
    remoteViews.setTextColor(R.id.BtEnableDisable, Color.GREEN);
    remoteViews.setTextViewText(R.id.BtEnableDisable, "Enabled");
   }else{
    Toast.makeText(context, "Data packet disabled", Toast.LENGTH_SHORT).show();
    Log.e("RK","Mobile data is disconnected");
    remoteViews.setTextColor(R.id.BtEnableDisable, Color.BLACK);
    remoteViews.setTextViewText(R.id.BtEnableDisable,"Disabled");
   }
   
   ComponentName thiswidget = new ComponentName(context, SimpleWidgetAppWidgetProvider.class);
   AppWidgetManager manager = AppWidgetManager.getInstance(context);
   manager.updateAppWidget(thiswidget, remoteViews);
   
  }
 }

}
Compile the java file and then run the commands below.
 
# Sanity check. If you don't get below message after executing javap command
# then include the java installation folder path in system path.
$javap      
No classes were specified on the command line.  Try -help. 
                                                           
$javap -help      #This command lists all the options available with javap
Usage: javap <options> <classes>...

where options include:
   -c                        Disassemble the code
   -classpath <pathlist>     Specify where to find user class files
   -extdirs <dirs>           Override location of installed extensions
   -help                     Print this usage message
   -J<flag>                  Pass <flag> directly to the runtime system
   -l                        Print line number and local variable tables
   -public                   Show only public classes and members
   -protected                Show protected/public classes and members
   -package                  Show package/protected/public classes
                             and members (default)
   -private                  Show all classes and members
   -s                        Print internal type signatures
   -bootclasspath <pathlist> Override location of class files loaded
                             by the bootstrap class loader
   -verbose                  Print stack size, number of locals and args for methods
                             If verifying, print reasons for failure

#This command decompile the ConnectivityReceiver class file
$javap -c ConnectivityReceiver   
Compiled from "ConnectivityReceiver.java"
public class com.rakesh.simplewidget.ConnectivityReceiver extends android.content.BroadcastReceiver{
public com.rakesh.simplewidget.ConnectivityReceiver();
  Code:
   0: aload_0
   1: invokespecial #8; //Method android/content/BroadcastReceiver."<init>":()V
   4: return

public void onReceive(android.content.Context, android.content.Intent);
  Code:
   0: aload_2
   1: invokevirtual #16; //Method android/content/Intent.getExtras:()Landroid/os/Bundle;
   4: ldc #22; //String networkInfo
   6: invokevirtual #24; //Method android/os/Bundle.get:(Ljava/lang/String;)Ljava/lang/Object;
   9: checkcast #30; //class android/net/NetworkInfo
   12: astore_3
   13: aload_3
   14: invokevirtual #32; //Method android/net/NetworkInfo.getType:()I
   17: ifne 144
   20: new #36; //class android/widget/RemoteViews
   23: dup
   24: aload_1
   25: invokevirtual #38; //Method android/content/Context.getPackageName:()Ljava/lang/String;
   28: ldc #44; //int 2130903041
   30: invokespecial #45; //Method android/widget/RemoteViews."<init>":(Ljava/lang/String;I)V
   33: astore 4
   35: aload_3
   36: invokevirtual #48; //Method android/net/NetworkInfo.isConnectedOrConnecting:()Z
   39: ifeq 81
   42: aload_1
   43: ldc #52; //String Data packet enabled
   45: iconst_0
   46: invokestatic #54; //Method android/widget/Toast.makeText:(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
   49: invokevirtual #60; //Method android/widget/Toast.show:()V
   52: ldc #63; //String RK
   54: ldc #65; //String Mobile data is enabled
   56: invokestatic #67; //Method android/util/Log.d:(Ljava/lang/String;Ljava/lang/String;)I
   59: pop
   60: aload 4
   62: ldc #73; //int 2131099649
   64: ldc #74; //int -16711936
   66: invokevirtual #75; //Method android/widget/RemoteViews.setTextColor:(II)V
   69: aload 4
   71: ldc #73; //int 2131099649
   73: ldc #79; //String Enabled
   75: invokevirtual #81; //Method android/widget/RemoteViews.setTextViewText:(ILjava/lang/CharSequence;)V
   78: goto 117
   81: aload_1
   82: ldc #85; //String Data packet disabled
   84: iconst_0
   85: invokestatic #54; //Method android/widget/Toast.makeText:(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
   88: invokevirtual #60; //Method android/widget/Toast.show:()V
   91: ldc #63; //String RK
   93: ldc #87; //String Mobile data is disconnected
   95: invokestatic #89; //Method android/util/Log.e:(Ljava/lang/String;Ljava/lang/String;)I
   98: pop
   99: aload 4
   101: ldc #73; //int 2131099649
   103: ldc #92; //int -16777216
   105: invokevirtual #75; //Method android/widget/RemoteViews.setTextColor:(II)V
   108: aload 4
   110: ldc #73; //int 2131099649
   112: ldc #93; //String Disabled
   114: invokevirtual #81; //Method android/widget/RemoteViews.setTextViewText:(ILjava/lang/CharSequence;)V
   117: new #95; //class android/content/ComponentName
   120: dup
   121: aload_1
   122: ldc #97; //class com/rakesh/simplewidget/SimpleWidgetAppWidgetProvider
   124: invokespecial #99; //Method android/content/ComponentName."<init>":(Landroid/content/Context;Ljava/lang/Class;)V
   127: astore 5
   129: aload_1
   130: invokestatic #102; //Method android/appwidget/AppWidgetManager.getInstance:(Landroid/content/Context;)Landroid/appwidget/AppWidgetManager;
   133: astore 6
   135: aload 6
   137: aload 5
   139: aload 4
   141: invokevirtual #108; //Method android/appwidget/AppWidgetManager.updateAppWidget:(Landroid/content/ComponentName;Landroid/widget/RemoteViews;)V
   144: return
}

#This command lists the line number and local variables
$ javap -l ConnectivityReceiver   
Compiled from "ConnectivityReceiver.java"
public class com.rakesh.simplewidget.ConnectivityReceiver extends android.content.BroadcastReceiver{
public com.rakesh.simplewidget.ConnectivityReceiver();
  LineNumberTable: 
   line 15: 0

  LocalVariableTable: 
   Start  Length  Slot  Name   Signature
   0      5      0    this       Lcom/rakesh/simplewidget/ConnectivityReceiver;


public void onReceive(android.content.Context, android.content.Intent);
  LineNumberTable: 
   line 19: 0
   line 21: 13
   line 23: 20
   line 24: 28
   line 23: 30
   line 26: 35
   line 27: 42
   line 28: 52
   line 29: 60
   line 30: 69
   line 32: 81
   line 33: 91
   line 34: 99
   line 35: 108
   line 38: 117
   line 39: 129
   line 40: 135
   line 43: 144

  LocalVariableTable: 
   Start  Length  Slot  Name   Signature
   0      145      0    this       Lcom/rakesh/simplewidget/ConnectivityReceiver;
   0      145      1    context       Landroid/content/Context;
   0      145      2    intent       Landroid/content/Intent;
   13      132      3    info       Landroid/net/NetworkInfo;
   35      109      4    remoteViews       Landroid/widget/RemoteViews;
   129      15      5    thiswidget       Landroid/content/ComponentName;
   135      9      6    manager       Landroid/appwidget/AppWidgetManager;


}

#This command prints internal type signatures 
$ javap -s ConnectivityReceiver   
Compiled from "ConnectivityReceiver.java"
public class com.rakesh.simplewidget.ConnectivityReceiver extends android.content.BroadcastReceiver{
public com.rakesh.simplewidget.ConnectivityReceiver();
  Signature: ()V
public void onReceive(android.content.Context, android.content.Intent);
  Signature: (Landroid/content/Context;Landroid/content/Intent;)V
}

#This command shows package/protected/public classes and members (default) 
$ javap -package ConnectivityReceiver 
Compiled from "ConnectivityReceiver.java"
public class com.rakesh.simplewidget.ConnectivityReceiver extends android.content.BroadcastReceiver{
    public com.rakesh.simplewidget.ConnectivityReceiver();
    public void onReceive(android.content.Context, android.content.Intent);
}


#Similar way you can also use -public, -protected -private etc. options


Related topic:
Android/java source code browsing

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 3, 2012

Android widget tutorial

Android widgets are small application which can be embedded inside another application such as Home screen. It can be used to show updated data to the user. You can embed these widgets in  an application. These widgets get updated periodically based either on their periodicity set in the widget xml configuration file or by the use of Alarm-manager. Widgets can also be updated asynchronously from Broadcast receiver. The tutorial given below explains the procedure to update the widget from broadcast receiver. But before that you must be aware of certain basics about widget. You can also find the related documentation here.

Basic building blocks

  • AppWidgetProviderInfo object
  • AppWidgetProvider 
  • Widget View layout 

AppWidgetProviderInfo object:

It provides meta-data about the widget for e.g widget initial layout, its min-height, min-width, update frequency and AppWidgetProvider class. It should be defined in xml file.

AppWidgetProvider:

It provides interfaces and ways to interact with the widget. The callback methods get called based on the broadcast events. These events get triggered as soon as the widget is added, removed, enabled,  disabled or update interval lapses.

Widget ViewLayout:

View layout is basically written in the xml file. This is the initial layout of the widget. There are very  few View components available. The RemoteView Object can support the following layout classes:
  • FrameLayout
  • GridLayout (Available on API 16)
  • LinearLayout
  • RelativeLayout
and following widget classes
  • AnalogClock
  • Button
  • Chronometer
  • FrameLayout
  • ImageButton
  • ImageView
  • ProgressBar
  • TextView
  • ViewFlipper
  • ViewStub (Available on API 16)
Project Information:  Meta-information about the project.
Platform Version : Android API Level 10.
IDE : Eclipse Helios Service Release 2
Emulator: Android 4.0.4
Prerequisite: Preliminary knowledge of Android application framework, Intent Broadcast receiver and Service.

Now 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 10 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. The next step is to define the widget layout xml file. The  same can be created with the help of Android XML file generator dialog window which can be  accessed through these menu and sub-menu options Eclipse>File>new>Android XML File. Since we have to create Layout file so we need to select Layout for Resource Type. The project field is automatically populated with project name. In File field enter the suitable xml file name. Don't forget to put the ".xml" file extension otherwise the dialog window will show error. In the root element list select the layout  for the widget. For this tutorial Linear Layout has been selected as shown in the picture below.

Content of widget_layout.xml file. You can ignore the "android:background" attribute field for LinearLayout and button, since this field has been used here to customize the background color and the size.
 <linearlayout android:background="@drawable/background"
       android:gravity="center" android:layout_height="match_parent" 
       android:layout_margin="4dp" android:layout_width="match_parent"  
       android:orientation="vertical"   
       xmlns:android="http://schemas.android.com/apk/res/android">
   <button android:background="@drawable/button_shape" 
     android:id="@+id/BtEnableDisable" 
     android:layout_height="wrap_content" android:layout_width="100dp" 
     android:text="@string/strWidgetBtEnableDisable">
</button></linearlayout>

The next step is to define widget meta data. This xml file basically represents the AppWidgetProviderInfo object. As mentioned earlier this file contains information about the widget for e.g min-width, min-height, update frequency etc. Here the update frequency has been set as 0 because we want to asynchronously update the widget. The minimum frequency allowed by Android system is 30min(30X60X100 miliseconds). If the update frequency is less than 180,000 miliseconds Android may ignore  this value. This file also contains the widget layout file name which is widget_background.xml in this case. For creating this file you can use the Android XML file dialog as explained in the above steps. But make sure that you select the Resource Type as AppWiget Provider. The content of widget_metadata.xml file is as following. 
 
<appwidget-provider android:initiallayout="@layout/widget_layout" 
     android:minheight="40dp" android:minwidth="130dp" 
     android:updateperiodmillis="0" 
     xmlns:android="http://schemas.android.com/apk/res/android">
</appwidget-provider>
In order to customize the widget background and shape you need to define the xml and include it in widget_layout.xml file. To create this file use Android XML file dialog as mentioned in the previous steps but for customization file select Resource Type as Drawable and Root element as Shape. You can put the following content in background.xml.
  <shape android:id="@+id/Corners" 
           xmlns:android="http://schemas.android.com/apk/res/android">
    <gradient android:angle="45" android:endcolor="#997f7f7f"
      android:startcolor="#99111111">
       <padding android:bottom="1dp" android:left="4dp"
             android:right="4dp" android:top="1dp">
        <corners android:radius="7dp">
          <stroke android:color="#FFFFFFFF" android:width="2dp">
          </stroke>
        </corners>
      </padding>
    </gradient>
</shape>

If you want to customize the button then you should define another customization file for button and include that in layout file. If you are not keen to customize the button or widget then go to the next step. Content of button_shape.xml
  <shape android:id="@+id/shapeBt" 
          xmlns:android="http://schemas.android.com/apk/res/android">
   <gradient android:angle="45" android:endcolor="#FFFAFAFA" 
           android:startcolor="#FFFFFFFF">
    <padding android:bottom="1dp" android:left="4dp" 
          android:right="4dp" android:top="1dp">
     <corners android:radius="7dp">
      <stroke android:color="#FFFFFFFF" android:width="2dp">
        <size android:height="35dp" android:width="90dp">
        </size>
      </stroke>
     </corners>
   </padding>
 </gradient>
</shape>
SimpleWidgetAppWigetProvider class extends AppWidgetProvider class. The methods defined in the SimpleWidgetAppWidgetProvider determine the behavior of the the widget. These methods get called based on the events triggered.
Methods present in AppWidgetProvider:

  • onReceive(): This method gets called for every broadcast and before every other callback method present in AppWidgetProvider. In most of the cases you don't need to implement this method. 
  • onEnabled(): This method gets called at the very first instance when the widget gets created. This method is similar to onCreate() method present in Activity class. If some initialization is required for your widget then  this is the right place to do it.
  • onDisabled(): This method gets called when the very last instance is removed from the container.
  • onUpdate(): This method gets called to update the widget. It gets called even when you create an instance of widget, thus it makes some initial setup. This method gets called at interval defined by updatePeriodMillis attribute in widget-meta info.  
  • onDeleted(): As the name suggests, this method gets called whenever an instance is removed/deleted.
You will notice that Service gets invoked by startService()  method call and passing intent object as  a parameter in startService().

package com.rakesh.simplewidget;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;


public class SimpleWidgetAppWidgetProvider extends AppWidgetProvider {

 public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {

  final int N = appWidgetIds.length;
  ComponentName thisWidget = new ComponentName(context,
    SimpleWidgetAppWidgetProvider.class);
  int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);

  // Build the intent to call the service
  Intent intent = new Intent(context.getApplicationContext(),
    UpdateWidgetService.class);
  intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, allWidgetIds);

  // Update the widgets via the service
  context.startService(intent);
}

UpdateWidgetService class extends the service class. Here onStart() method has been defined which  does the actual job(here we are trying to enable/disable the packet data) and then it tries to update the remote view with the help of updateAppWidget() method call. PendingIntent and setOnClickPendingIntent() method help to attach action listener to the button.
package com.rakesh.simplewidget;


import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.telephony.TelephonyManager;
import android.widget.RemoteViews;

public class UpdateWidgetService extends Service {

 @Override
 public void onStart(Intent intent, int startId) {

  AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this
    .getApplicationContext());

  int[] allWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);

  ComponentName thisWidget = new ComponentName(getApplicationContext(),
    SimpleWidgetAppWidgetProvider.class);

  for (int widgetId : allWidgetIds) {
   RemoteViews remoteViews = new RemoteViews(this
     .getApplicationContext().getPackageName(),
     R.layout.widget_layout);

   EnableDisableConnectivity edConn = new EnableDisableConnectivity(this.getApplicationContext());
   edConn.enableDisableDataPacketConnection(!checkConnectivityState(this.getApplicationContext()));

   // Register an onClickListener
   Intent clickIntent = new Intent(this.getApplicationContext(),
     SimpleWidgetAppWidgetProvider.class);

   clickIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
   clickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS,
     allWidgetIds);

   PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, clickIntent,
     PendingIntent.FLAG_UPDATE_CURRENT);
   remoteViews.setOnClickPendingIntent(R.id.BtEnableDisable, pendingIntent);
   appWidgetManager.updateAppWidget(widgetId, remoteViews);
  }
  stopSelf();

  super.onStart(intent, startId);
 }

 @Override
 public IBinder onBind(Intent intent) {
  return null;
 }

 private boolean checkConnectivityState(Context context){
  final TelephonyManager telephonyManager = (TelephonyManager) context
    .getSystemService(Context.TELEPHONY_SERVICE);
  return telephonyManager.getDataState() == TelephonyManager.DATA_CONNECTED;

 }
}

Since this tutorial is about how to update the widget when CONNECTIVITY_CHANGE intent is received, so here ConnectivityReceiver class has been defined which extends the BroadcastReceiver class. When application receives CONNECTIVITY_CHANGE intent it calls onReceive() method. In onReceive() method we try to get the remote view and then change the text and color of the button with the help of setTetViewText() and setTextColor() method respectively.

package com.rakesh.simplewidget;
import android.appwidget.AppWidgetManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.Toast;


public class ConnectivityReceiver extends BroadcastReceiver {

 @Override
 public void onReceive(Context context, Intent intent) {
  NetworkInfo info = (NetworkInfo)intent.getExtras().get(ConnectivityManager.EXTRA_NETWORK_INFO);
  
  if(info.getType() == ConnectivityManager.TYPE_MOBILE){
   
   RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
     R.layout.widget_layout);
   
   if(info.isConnectedOrConnecting()){
    Toast.makeText(context, "Data packet enabled", Toast.LENGTH_SHORT).show();
    Log.d("RK","Mobile data is enabled");
    remoteViews.setTextColor(R.id.BtEnableDisable, Color.GREEN);
    remoteViews.setTextViewText(R.id.BtEnableDisable, "Enabled");
   }else{
    Toast.makeText(context, "Data packet disabled", Toast.LENGTH_SHORT).show();
    Log.e("RK","Mobile data is disconnected");
    remoteViews.setTextColor(R.id.BtEnableDisable, Color.BLACK);
    remoteViews.setTextViewText(R.id.BtEnableDisable,"Disabled");
   }
   
   ComponentName thiswidget = new ComponentName(context, SimpleWidgetAppWidgetProvider.class);
   AppWidgetManager manager = AppWidgetManager.getInstance(context);
   manager.updateAppWidget(thiswidget, remoteViews);
   
  }
 }

}
Below is the Android manifest file which defines the application components and their permissions.
<manifest android:versioncode="1" android:versionname="1.0" 
      package="com.rakesh.simplewidget"  
      xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-sdk android:minsdkversion="10">
    
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE">
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE">

    &t;application android:icon="@drawable/widget_icon" 
            android:label="@string/app_name">
        <activity android:label="@string/app_name" 
              android:name=".SimpleWidgetExampleActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN">

                <category android:name="android.intent.category.LAUNCHER">
            </category></action></intent-filter>
        </activity>
        
        <receiversxml android:icon="@drawable/widget_icon"
             android:label="@string/app_name" 
             android:name=".SimpleWidgetAppWidgetProvider">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE">
            </action></intent-filter>
            <meta-data android:name="android.appwidget.provider" 
                 android:resource="@xml/widget_metadata">
        

        <service android:name=".UpdateWidgetService">
        <receiver android:name=".ConnectivityReceiver">
            <intent-filter>
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE">
            </action></intent-filter>
        </receiver>
    </service></meta-data></receiversxml></application>

     </uses-permission>
     </uses-permission>
   </uses-sdk>
</manifest>

You may have noticed that the AppwidgetProvider class has registered APPWIDGET_UPDATE intent. The class shown below is a helper class which basically enables/disables the packet data connection state. You can skip this part because it does not have much relevance to widget. But I have provided this code for those who may be interested in enabling/disabling packet data connection.

package com.rakesh.simplewidget;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import android.content.Context;
import android.net.ConnectivityManager;
import android.telephony.TelephonyManager;
import android.util.Log;

public class EnableDisableConnectivity {
 private Context mContext;
 public EnableDisableConnectivity(Context context){
  this.mContext = context;
 }
 public boolean enableDataPacketConnection(){
  return enableDisableDataPacketConnection(true);
 }
 public boolean disableDataPacketConnection(){
  return enableDisableDataPacketConnection(false);
 }

 public boolean enableDisableDataPacketConnection(boolean enable){
  boolean result = false;
  Method dataConnSwitchmethod;
  Class telephonyManagerClass;
  Object ITelephonyStub;
  Class ITelephonyClass;
  final ConnectivityManager conman = 
         (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
  try{
   final Class conmanClass = Class.forName(conman.getClass().getName());
   final Field iConnectivityManagerField = conmanClass.getDeclaredField("mService");
   iConnectivityManagerField.setAccessible(true);
   final Object iConnectivityManager = iConnectivityManagerField.get(conman);
   final Class iConnectivityManagerClass = Class.forName(iConnectivityManager.getClass().getName());
   final Method setMobileDataEnabledMethod = 
      iConnectivityManagerClass.getDeclaredMethod("setMobileDataEnabled", Boolean.TYPE);
   setMobileDataEnabledMethod.setAccessible(true);
   setMobileDataEnabledMethod.invoke(iConnectivityManager, enable);
   result = true;
  }catch(Exception e){
   Log.e("Error", "here is an exception "+e.getMessage());
   result =false;
  }
  return result;
 }

 private boolean checkConnectivityState(){
  final TelephonyManager telephonyManager = (TelephonyManager) mContext
    .getSystemService(Context.TELEPHONY_SERVICE);
  return telephonyManager.getDataState() == TelephonyManager.DATA_CONNECTED;

 }
}

On executing this code you will notice that one icon named Data packet widget has been deployed     and appears in the application list as shown in Fig 1. If you want to check whether widget has been recognized by Android  ,then you need to check the widgets tab(Fig. 2) on Android 15. For Android version lower than 15, you need to long-press on the home-screen and then you will see the list of widgets available. Select the  data-packet-widget it will get deployed on home-screen. Once the widget is deployed you will see the widget on home-screen as shown in Fig 3.
Application tab which shows installed applications.
1. Applications tab
Widgets tab shows what all widgets are available.
2. Widgets tab
Home screen which shows that Data-packet widget is installed on  home screen.
3. Installed widget
If you want to explore the new features of widgets introduced in Android 4.1, watch the video below.

If you want to download the source code you can find it here. In next Widget tutorial we will learn how to use AlarmManger to update the widget if the periodicity of update is less than 30 mins.

Related tutorial:

Tutorial on Android Widget with AlarmManager
Tutorial on Android AlaramManager

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

Saturday, June 30, 2012

How to access SQLite database file in Android.

As we know that Android has inbuilt database called SQLite where application can store their data. SQLite was mainly developed for embedded devices. I am not going to discuss here about SQLite database but I am going to demonstrate how Android developer can access the SQLite database. This might be helpful while debugging the code especially to store application data in SQLite database tables. You can access the SQLite database file in emulator or rooted device.

Ways of accessing SQLite database file:

  • Copying from Phone/Emulator to your laptop
  • Accessing via Android shell and Sqlite commands.

Copying from phone/Emulator to your laptop:

You can easily copy the database file by just executing the command given below. But before that make sure  ...<android-sdk>/platform-tools/ is in environment path otherwise this command can executed only in .../platform-tools/ directory.
$adb shell /data/data/your.package.name/databases/databasefilename.db 
Database file can also be downloaded by Eclipse. If you have already installed the ADT plugin then it will be easier to browse the Android Emulator files. In Eclipse menu Window > Open Perspective > Other > DDMS . If the device/emulator is connected to your system, DDMS perspective shown in picture will appear. 
Eclipse Android file browser for SQLite database file access
Eclipse android file browser
DDMS perspective button marked as 1 in the picture: Once you select this perspective click the "File Explorer"(Which is marked as 2 in above picture) tab you will see the list of folder in the window. You can browse /data/data/your.package.name/database  where you will see a list of database files. Once you select the desired database file, "disket icon" on the upper-right corner of the window will get activated(which is marked as 4 in the above picture). Once you press this icon, the Eclipse will ask you to browse the place where you want to download the database file. 
Database table can be browsed with help of sqlite GUI or Mozilla browser if this extension is installed in your Mozilla browser.


Accessing via Android shell and Sqlite commands:

The following command is used for accessing file either from rooted device or emulator. 
$adb devices               #This command lists all the devices attached to your system
List of devices attached 
emulator-5554 device     #This emulator is the one which was running on my system.

$adb shell       #This allows you to access Android shell.
$ls              #This command lists all directories present in the current directory
.
.
data             #Sqlite database files are present in this directory
sdcard
sys
system
.
.
$cd data/data   #Now you need to find your package name here. eg com.rakesh.android.test

$cd com.rakesh.android.test/databases
$ls
mylist.db
$sqlite3 mylist.db
sqlite> .help        #This command lists the commands available in SQLite.
sqlite>.tables       #This command lists the tables present in the SQLite database.
sqlite>.schema       #This command shows the schema of the database.
sqlite>select * from myTable  #You can also run the queries in similar way.
sqlite>.exit         #This command exits you from SQLite command prompt.
$                    #Press Ctrl+C to come out of Android shell

For more commands and info about SQLite, please visit this site www.sqlite.org


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

Monday, June 18, 2012

Handy git commands

Clearcase was my first version control software. I used it for 2 years and eventually I liked it since most of the commands are really simple to understand. In these two years I used to debug the code on debugging branch. Once I was done with the fix, I renamed the branch to follow the standard specified by my company. The command below was really handy to rename the branch.
 [cmd-context] $rename replica:old_branch_name new_brach_name 
But when I migrated to Git version control, I couldn't get head around git. It took a while to discover that even git has command to rename the branch which is as following.
$ git branch -m old-branch-name new-branch-name 
This kind of practice leaves a lot of branches in your local and remote repo and sometimes you wonder to clean this up.
$git push origin :debug-branch 
The above command will delete debug-branch on the origin remote and below is the command used to delete the branch present in local repo.
$ git branch -D debug-branch 
This command can also be used with -d option. The only difference between these two commands is that -D forces the delete process but -d doesn't.
If you have made some changes in a file and now you don't want those changes. you can run the following command to do that.
$ git checkout <file-name>  
There are instances when you staged the file but now you want to unstage the file. For this use the below command.
$ git reset HEAD <file-name> ...  



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