Apr 29, 2011

Android: WebView, Detect HTML Element on Click

Android WebView allow us to display web pages inside the application. Also allowed to  interact with web content, there are several reasons that you might want to use WebView in your applications. It is powerful enough to execute JavaScript. It allow us to load HTML content as String and also display Web Page from domain/URL.

Here I am going to teach you how to detect user's action. Suppose you want to take specific action when user click on image or button or link then it is possible.

We can detect following HTML elements as per Android API Document.

int ANCHOR_TYPE HitTestResult for hitting a HTML::a tag
int EDIT_TEXT_TYPE HitTestResult for hitting an edit text area
int EMAIL_TYPE HitTestResult for hitting an email address
int GEO_TYPE HitTestResult for hitting a map address
int IMAGE_ANCHOR_TYPE HitTestResult for hitting a HTML::a tag which contains HTML::img
int IMAGE_TYPE HitTestResult for hitting an HTML::img tag
int PHONE_TYPE HitTestResult for hitting a phone number
int SRC_ANCHOR_TYPE HitTestResult for hitting a HTML::a tag with src=http
int SRC_IMAGE_ANCHOR_TYPE HitTestResult for hitting a HTML::a tag with src=http + HTML::img
int UNKNOWN_TYPE Default HitTestResult, where the target is unknown
 
Src : http://developer.android.com/reference/android/webkit/WebView.HitTestResult.html

Here are many HTML element missing. like RadioButton, CheckBox etc.. I can not detect radio button or check box click event.

continue reading Android: WebView, Detect HTML Element on Click

Apr 28, 2011

Android: Send Image via Bluetooth

I assume that you have experience of developing Bluetooth application in Android. Android Bluetooth API  is not supporting OBEX directly, means I can not push any file directly to any device. Android Bluetooth API provide basic functionalities like discovery, connection and data transfer using streams (InputStream and OutputStream).

Transferring file using Bluetooth need lot of coding. We need to manage device discovery, connection, IO etc.

Now I found very simple way to send file using Bluetooth. Android has build-in Bluetooth application which allow us to send file across the devices.  Build-in Bluetooth Application use SharedPerference to manage queue for Incoming and Outgoing files.

I find the way to use same technique. Android Bluetooth application use ContentProvider to manage communication between storage and user interface. so I found the way that we can use it's functionality 

Here is the code, Following 6 line allow you to send file using bluetooth,  you required only two things 1. URI of file which you want to send 2. DeviceAddress.



  1. ContentValues values = new ContentValues();
  2. values.put(BluetoothShare.URI, "content://" + uritoSend);
  3. values.put(BluetoothShare.DESTINATION, deviceAddress);
  4. values.put(BluetoothShare.DIRECTION, BluetoothShare.DIRECTION_OUTBOUND);
  5. Long ts = System.currentTimeMillis();
  6. values.put(BluetoothShare.TIMESTAMP, ts);
Description of above code.
1. Create object of ContentValue
2. put URI of file which you want to send
3. put DeviceAdddress, destination device address
4. put Direction, set outbound means you want to send the file.
5. time stamp which will display at Notification bar
6. put time stamp.

Note: Above code is useful only if we can have URI of file which we want to send. It is perfectly work for Images because we can get URI of images available in Gallery but If we want to send file from SDCard then it difficult because we can not get URI of file available in SDCard.

BluetoothShare.java
import android.provider.BaseColumns;
import android.net.Uri;

/**
 * Exposes constants used to interact with the Bluetooth Share manager's content
 * provider.
 */

public final class BluetoothShare implements BaseColumns {
private BluetoothShare() {
}
/**
 * The permission to access the Bluetooth Share Manager
 */
public static final String PERMISSION_ACCESS = "android.permission.ACCESS_BLUETOOTH_SHARE";

/**
 * The content:// URI for the data table in the provider
 */
public static final Uri CONTENT_URI = Uri.parse("content://com.android.bluetooth.opp/btopp");

/**
 * Broadcast Action: this is sent by the Bluetooth Share component to
 * transfer complete. The request detail could be retrieved by app * as _ID
 * is specified in the intent's data.
 */
public static final String TRANSFER_COMPLETED_ACTION = "android.btopp.intent.action.TRANSFER_COMPLETE";

/**
 * This is sent by the Bluetooth Share component to indicate there is an
 * incoming file need user to confirm.
 */
public static final String INCOMING_FILE_CONFIRMATION_REQUEST_ACTION = "android.btopp.intent.action.INCOMING_FILE_NOTIFICATION";

/**
 * This is sent by the Bluetooth Share component to indicate there is an
 * incoming file request timeout and need update UI.
 */
public static final String USER_CONFIRMATION_TIMEOUT_ACTION = "android.btopp.intent.action.USER_CONFIRMATION_TIMEOUT";

/**
 * The name of the column containing the URI of the file being
 * sent/received.
 */
public static final String URI = "uri";

/**
 * The name of the column containing the filename that the incoming file
 * request recommends. When possible, the Bluetooth Share manager will
 * attempt to use this filename, or a variation, as the actual name for the
 * file.
 */
public static final String FILENAME_HINT = "hint";

/**
 * The name of the column containing the filename where the shared file was
 * actually stored.
 */
public static final String _DATA = "_data";

/**
 * The name of the column containing the MIME type of the shared file.
 */
public static final String MIMETYPE = "mimetype";

/**
 * The name of the column containing the direction (Inbound/Outbound) of the
 * transfer. See the DIRECTION_* constants for a list of legal values.
 */
public static final String DIRECTION = "direction";

/**
 * The name of the column containing Bluetooth Device Address that the
 * transfer is associated with.
 */
public static final String DESTINATION = "destination";

/**
 * The name of the column containing the flags that controls whether the
 * transfer is displayed by the UI. See the VISIBILITY_* constants for a
 * list of legal values.
 */
public static final String VISIBILITY = "visibility";

/**
 * The name of the column containing the current user confirmation state of
 * the transfer. Applications can write to this to confirm the transfer. the
 * USER_CONFIRMATION_* constants for a list of legal values.
 */
public static final String USER_CONFIRMATION = "confirm";

/**
 * The name of the column containing the current status of the transfer.
 * Applications can read this to follow the progress of each download. See
 * the STATUS_* constants for a list of legal values.
 */
public static final String STATUS = "status";

/**
 * The name of the column containing the total size of the file being
 * transferred.
 */
public static final String TOTAL_BYTES = "total_bytes";

/**
 * The name of the column containing the size of the part of the file that
 * has been transferred so far.
 */
public static final String CURRENT_BYTES = "current_bytes";

/**
 * The name of the column containing the timestamp when the transfer is
 * initialized.
 */
public static final String TIMESTAMP = "timestamp";

/**
 * This transfer is outbound, e.g. share file to other device.
 */
public static final int DIRECTION_OUTBOUND = 0;

/**
 * This transfer is inbound, e.g. receive file from other device.
 */
public static final int DIRECTION_INBOUND = 1;

/**
 * This transfer is waiting for user confirmation.
 */
public static final int USER_CONFIRMATION_PENDING = 0;

/**
 * This transfer is confirmed by user.
 */
public static final int USER_CONFIRMATION_CONFIRMED = 1;

/**
 * This transfer is auto-confirmed per previous user confirmation.
 */
public static final int USER_CONFIRMATION_AUTO_CONFIRMED = 2;

/**
 * This transfer is denied by user.
 */
public static final int USER_CONFIRMATION_DENIED = 3;

/**
 * This transfer is timeout before user action.
 */
public static final int USER_CONFIRMATION_TIMEOUT = 4;

/**
 * This transfer is visible and shows in the notifications while in progress
 * and after completion.
 */
public static final int VISIBILITY_VISIBLE = 0;

/**
 * This transfer doesn't show in the notifications.
 */
public static final int VISIBILITY_HIDDEN = 1;

/**
 * Returns whether the status is informational (i.e. 1xx).
 */
public static boolean isStatusInformational(int status) {
    return (status >= 100 && status < 200);
}

/**
 * Returns whether the transfer is suspended. (i.e. whether the transfer
 * won't complete without some action from outside the transfer manager).
 */
public static boolean isStatusSuspended(int status) {
    return (status == STATUS_PENDING);
}

/**
 * Returns whether the status is a success (i.e. 2xx).
 */
public static boolean isStatusSuccess(int status) {
    return (status >= 200 && status < 300);
}

/**
 * Returns whether the status is an error (i.e. 4xx or 5xx).
 */
public static boolean isStatusError(int status) {
    return (status >= 400 && status < 600);
}

/**
 * Returns whether the status is a client error (i.e. 4xx).
 */
public static boolean isStatusClientError(int status) {
    return (status >= 400 && status < 500);
}

/**
 * Returns whether the status is a server error (i.e. 5xx).
 */
public static boolean isStatusServerError(int status) {
    return (status >= 500 && status < 600);
}

/**
 * Returns whether the transfer has completed (either with success or
 * error).
 */
public static boolean isStatusCompleted(int status) {
    return (status >= 200 && status < 300) || (status >= 400 && status < 600);
}

/**
 * This transfer hasn't stated yet
 */
public static final int STATUS_PENDING = 190;

/**
 * This transfer has started
 */
public static final int STATUS_RUNNING = 192;

/**
 * This transfer has successfully completed. Warning: there might be other
 * status values that indicate success in the future. Use isSucccess() to
 * capture the entire category.
 */
public static final int STATUS_SUCCESS = 200;

/**
 * This request couldn't be parsed. This is also used when processing
 * requests with unknown/unsupported URI schemes.
 */
public static final int STATUS_BAD_REQUEST = 400;

/**
 * This transfer is forbidden by target device.
 */
public static final int STATUS_FORBIDDEN = 403;

/**
 * This transfer can't be performed because the content cannot be handled.
 */
public static final int STATUS_NOT_ACCEPTABLE = 406;

/**
 * This transfer cannot be performed because the length cannot be determined
 * accurately. This is the code for the HTTP error "Length Required", which
 * is typically used when making requests that require a content length but
 * don't have one, and it is also used in the client when a response is
 * received whose length cannot be determined accurately (therefore making
 * it impossible to know when a transfer completes).
 */
public static final int STATUS_LENGTH_REQUIRED = 411;

/**
 * This transfer was interrupted and cannot be resumed. This is the code for
 * the OBEX error "Precondition Failed", and it is also used in situations
 * where the client doesn't have an ETag at all.
 */
public static final int STATUS_PRECONDITION_FAILED = 412;

/**
 * This transfer was canceled
 */
public static final int STATUS_CANCELED = 490;

/**
 * This transfer has completed with an error. Warning: there will be other
 * status values that indicate errors in the future. Use isStatusError() to
 * capture the entire category.
 */
public static final int STATUS_UNKNOWN_ERROR = 491;

/**
 * This transfer couldn't be completed because of a storage issue.
 * Typically, that's because the file system is missing or full.
 */
public static final int STATUS_FILE_ERROR = 492;

/**
 * This transfer couldn't be completed because of no sdcard.
 */
public static final int STATUS_ERROR_NO_SDCARD = 493;

/**
 * This transfer couldn't be completed because of sdcard full.
 */
public static final int STATUS_ERROR_SDCARD_FULL = 494;

/**
 * This transfer couldn't be completed because of an unspecified un-handled
 * OBEX code.
 */
public static final int STATUS_UNHANDLED_OBEX_CODE = 495;

/**
 * This transfer couldn't be completed because of an error receiving or
 * processing data at the OBEX level.
 */
public static final int STATUS_OBEX_DATA_ERROR = 496;

/**
 * This transfer couldn't be completed because of an error when establishing
 * connection.
 */
public static final int STATUS_CONNECTION_ERROR = 497;

}


AndroidManifast.xml
<uses-permission android:name="android.permission.BLUETOOTH"/>

<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>








continue reading Android: Send Image via Bluetooth

Apr 27, 2011

Android InDepth : SharedPreference


1. Introduction

SharedPreference is used to store settings/preferences. It stores data as key/value pairs. It share data between activities but not across the processes.

Shared Preference is stored in /data/data/[package name]/shared_prefs/[SP Name].xml.

In Device data/data folder is not accessible but we can access data/data folder in Emulator. Using DDMS allow access to every folders including data/data folder. It is possible to pull  the Shared Preference  xml file to PC. If we stuck in any problem related to Shared Preference then we can transfer xml file to PC for observation.


2. Implementation


Let's Create simple example of SharedPreference. SharedPreference is Interface. We do not need to create object of SharedPreference. It created with the Activity. I will explain how SharedPreference Object will crate in this tutorial. Activity has method named "getSharedPreference()" we can retrieve object like following.

2.1 Retrieving object of SharedPreference
SharedPreference pref = getSharedPreference("MyPRef",MODE_PRIVATE);
Method has two parameter Name and Mode, Name is used as XML file name. 

  • MODE_PRIVATE is the operating mode for the preferences. It is the default mode and means the created file will be accessed by only the calling application. 
  • MODE_WORLD_READABLE other application can read the created file but can not modify it. 
  • MODE_WORLD_WRITEABLE other applications also have write permissions for the created file. 
First mode is default we can implement in this example. but what about other two options.  I found following post in "StackOverFlow.com"


"As I checked in APIs description for getSharedPreferences(String, int),Second attribute is defining accessibility mode and can take 0 or MODE_PRIVATE for the default operation, MODE_WORLD_READABLE and MODE_WORLD_WRITEABLE to control permissions.

But there is this small note in API description:

Note: currently this class (android.content.SharedPreferences) does not support use across multiple processes. This will be added later.

Moreover in Mark L. Murphy book "beginning Android 2" he mentioned:

(Eventually, preferences might be shareable across applications, but that is not supported as of the time of this writing)

Im so confused! does this mean that MODE_WORLD_READABLE and MODE_WORLD_WRITEABLE of getSharedPrefrences is there but NOT SUPPORTED YET in latest API level???"
Source : Here

2.2 Create object of Editor

Editor is interface declared inside the SharedPreference class. so that To access Editor class we need to write following syntax, "pref" is object of SharedPreference.

SharedPreferences.Editor edit = pref.edit();


2.2 Put value in SharedPreference

The following data types are supported by the SharedPreferences class:
  • Boolean values
  • Float values
  • Integer values
  • Long values
  • String values
Putting value in SharedPreference using Editor object is very simple, It's same as we are using Map Collection class. Here I put one value of each data type. 

           edit.putBoolean("Boolean_Value", true);
        edit.putFloat("Float_value", 12.5F);
        edit.putInt("Int_value", 500);
        edit.putLong("Long_Value", 1234567890);
        edit.putString("String_Value", "Hello SharedPreference");

SharedPreference is not support to put object inside it but If you can convert your object in String then It is possible. Support you want to store small image in SharedPreference then It is possible using Base64. just convert your image in Base64 and put it as String. but same technique is not possible with object of any class.

2.3 Commit the values

Commit your preferences changes back from this Editor to the SharedPreferences object it is editing. This atomically performs the requested modifications, replacing whatever is currently in the SharedPreferences.

        edit.commit();

Note that when two editors are modifying preferences at the same time, the last one to call commit wins.

If you don't care about the return value and you're using this from your application's main thread, consider using apply() instead.

2.4 Retrieving values


You don’t need an Editor to simply read preferences. Instead, retrieve the SharedPreferences object and use the appropriate method to retrieve a preference by name:


        boolean b = pref.getBoolean("Boolean_Value",false);
        float f = pref.getFloat("Float_Value", 0);
        int i = pref.getInt("Int_Value", 0);
        long l = pref.getLong("Long_Value", 0);
        String s = pref.getString("String_Value", "");


Each of these methods has two parameters: the preference key string and a default value to return if the preference is undefined.

2.5 Remove And Clear

Editor class has two method remove and clear. as name suggest it is used to remove specific key and clear is used to remove all values.

       // Remove value
        edit.remove("Boolean_Value");
        edit.commit();
        
        // Clear All value
        edit.clear();
        edit.commit();

2.5. Full Source Code


package com.kpbird.mysp;

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

public class MySP extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        // fetch object of SharedPreference
        SharedPreferences pref = getSharedPreferences("MyPref", MODE_PRIVATE);
        // Create object of Editor
        SharedPreferences.Editor edit = pref.edit();
        // Put values 
        edit.putBoolean("Boolean_Value", true);
        edit.putFloat("Float_value", 12.5F);
        edit.putInt("Int_value", 500);
        edit.putLong("Long_Value", 1234567890);
        edit.putString("String_Value", "Hello SharedPreference");
        // Commit the data
        edit.commit();
        
        
        //Retreive 
        boolean b = pref.getBoolean("Boolean_Value",false);
        float f = pref.getFloat("Float_Value", 0);
        int i = pref.getInt("Int_Value", 0);
        long l = pref.getLong("Long_Value", 0);
        String s = pref.getString("String_Value", "");
        
    }
}


continue reading Android InDepth : SharedPreference