Monday, March 26, 2012

Implementing Broadcast Receiver in Android

broadcast receiver is a component that responds to system-wide broadcast announcements. Many broadcasts originate from the system—for example, a broadcast announcing that the screen has turned off, the battery is low, or a picture was captured. Applications can also initiate broadcasts—for example, to let other applications know that some data has been downloaded to the device and is available for them to use. Although broadcast receivers don't display a user interface, they may create a status bar notification to alert the user when a broadcast event occurs. More commonly, though, a broadcast receiver is just a "gateway" to other components and is intended to do a very minimal amount of work. For instance, it might initiate a service to perform some work based on the event.

               We can simply implement broadcast receivers in applications .If you don't need to send broadcasts across applications, consider using this class with LocalBroadcastManager instead of the more general facilities described below. This will give you a much more efficient implementation (no cross-process communication needed) and allow you to avoid thinking about any security issues related to other applications being able to receive or send your broadcasts. 


Here a simple example for registering and sending a broadcast.



For receiving a broadcast
@Override
public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 IntentFilter filter = new IntentFilter("LOGOUT_BROADCAST");
     registerReceiver(logoutReceiver, filter);

}

private BroadcastReceiver logoutReceiver = new BroadcastReceiver() {
  @Override
  public void onReceive(Context arg0, Intent arg1) {
                      // to do 
  }
};
@Override
 protected void onDestroy() {
  super.onDestroy();
  unregisterReceiver(logoutReceiver);
 }
For sending a broadcast
Intent intent = new Intent("LOGOUT_BROADCAST",null);
context.sendBroadcast(intent);

Wednesday, March 21, 2012

ImageView zooming in Android

The common way to show a big image was enable the  user to zoom in, zoom out and pan  that image . A simple method is load the image in a web view. it will automatically handle the zooming. Also there are so many other ways to do the same. Please go through the following links.

 1. https://github.com/MikeOrtiz/TouchImageView 

 2. https://github.com/a85/WebComicViewer/blob/master/src/com/rickreation/ui/ZoomableImageView.java 

 3. http://code.google.com/p/android-multitouch-controller/

Monday, March 19, 2012

Formatting currency value in Edittext

When we work with the currency   we need to use ',' separator in appropriate places  .  For example 1500 as 1,500. For formatting the currency value, we can use NumberFormat Class . Also we need to add a textchange listener to that edit text. Format the value while we get a call in afterTextChanged() method in addTextChangedListener . A simple example below

mDishPrice.addTextChangedListener(new TextWatcher() {
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
 }

 @Override
 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
 }

 @Override
 public void afterTextChanged(Editable s) {
  /***
   * No need to continue the function if there is nothing to
   * format
   ***/
  if (s.length() == 0){
   return;
                }

  /*** Now the number of digits in price is limited to 8 ***/
  String value = s.toString().replaceAll(",", "");
  if (value.length() > 8) {
   value = value.substring(0, 8);
  }
  String formattedPrice = getFormatedCurrency(value);
  if (!(formattedPrice.equalsIgnoreCase(s.toString()))) {
   /***
    * The below given line will call the function recursively
    * and will ends at this if block condition
    ***/
   mDishPrice.setText(formattedPrice);
   mDishPrice.setSelection(mDishPrice.length());
  }
 }
});
/**
 * 
 * @param value not formated amount
 * @return Formated string of amount (##,##,##,###).
 */
public static String getFormatedCurrency(String value) {
 try {
  NumberFormat formatter = new DecimalFormat("##,##,##,###");
  return formatter.format(Double.parseDouble(value));
 } catch (Exception e) {
  e.printStackTrace();
 }
 return "";
}

Wednesday, March 14, 2012

Keyboard raising issue when tabview at bottom of Android

There is an issue when placing a edittext in a tabview at bottom. when we tap on edit box the soft keyboard pops up and it move the whole view to upward (means the bottom tab also). When  we want to show the keyboard over the tabs at bottom itself. To solve this issue you may need to adjust the windowSoftInputMode in your manifest. This controls how the screen shifts when the soft keyboard is shown. This page has more info on the various input modes.   We can solve it as follows.


In AndroidManifest.xml


<activity
             android:name="TabActivity" android:windowSoftInputMode="adjustPan" >  
</activity>

Sunday, March 11, 2012

Injecting a javascript for getting html of a webpage in Android

To get the source code of html page, we can use javascript . For this first we have to enable the javascript interface of the web view. Then provide a custom webview client for that view. We will get a onPage finished call after loading a url. And in this method we can inject a javascript to get a html. An example below

WebSettings settings = webview.getSettings();
settings.setJavaScriptEnabled(true);
settings.setSavePassword(false);
webview.addJavascriptInterface(new MyJavaScriptInterface(), "HTMLOUT");
webview.setWebViewClient(new WebViewClient() {
 @Override
 public boolean shouldOverrideUrlLoading(WebView view, String url) {
  view.loadUrl(url);
  return true;
 }
 public void onPageFinished(WebView view, String url) {
  Log.i("Web view", "Finished loading URL: " + url);
//  killProgressDialog();
  webview.loadUrl("javascript:window.HTMLOUT.showHTML(document.getElementById('oauth_pin').innerHTML)");
 }

 @Override
 public void onPageStarted(WebView view, String url, Bitmap favicon) {
//  showProgressDialog();
  super.onPageStarted(view, url, favicon);
 }
 @Override
 public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
//  killProgressDialog();
  Toast.makeText(getBaseContext(),"Loading error", Toast.LENGTH_SHORT).show();
 }
});


class MyJavaScriptInterface {
 public void showHTML(String html) {
                Log.i("HTML" ,html);                         
        }
}

Wednesday, March 7, 2012

Leaked window Exception When using Progress Dialog in Android

Views have a reference to their parent Context (taken from constructor argument). If you leave an Activity without destroying Dialogs and other dynamically created Views, they still hold this reference to your Activity (if you created with this as Context: like new ProgressDialog(this)), so it cannot be collected by the GC, causing a memory leak. To solve this issue , dismiss method of the dialog should be called in on destroy method of that activity.
@Override
protected void onDestroy() {
    runOnUiThread(new Runnable() {
       @Override
       public void run() {
        if (mDialog.isShowing()) {
          mDialog.dismiss();
        }
       }
    });
    super.onDestroy();
 }

Tuesday, March 6, 2012

Converting an inputStream to String in utf-8

Sometimes we need to check the response of the http request by converting the stream to a string.  A simple method with which  we can do it in UTF-8 format  is  follows.
public static String readStream(InputStream in) throws Exception {

  if(in == null){
     return "";
  }

  int ch;
  ByteArrayOutputStream bos = new ByteArrayOutputStream();
  while ((ch = in.read()) != -1) {
   bos.write(ch);
  }
  in.close();
  return new String(bos.toByteArray(), "UTF-8");

}

Monday, March 5, 2012

Add images to gallery dynamically in Android


To add an image into the  android gallery we can use   MediaScannerConnection  class. The system scans the SD card when it is mounted to find any new image (and other) files.So sometimes we need to restart the phone to get updated. To solve this   we can  programmatically add a file,  using this class.

public void saveImageBitmap(byte[] sourceImageData, Context context) {
  Bitmap scaledBitmap = null;
  try {
   ContentValues image = new ContentValues();
   image.put(Media.DISPLAY_NAME, "sample_" + System.currentTimeMillis());
   image.put(Media.MIME_TYPE, "image/jpeg");
   Uri uri = context.getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, image); 
   Bitmap bitmap = BitmapFactory.decodeByteArray(sourceImageData, 0, sourceImageData.length);
   Bitmap rotateBitmap = null;
   Matrix matrix = new Matrix();
   rotateBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
 
   OutputStream ops = context.getContentResolver().openOutputStream(uri);
   rotateBitmap.compress(Bitmap.CompressFormat.JPEG, 90, ops);
   ops.close();
   Cursor c = context.getContentResolver().query(uri, null, null, null, null);
   c.moveToFirst();
   String imagePath = c.getString(1);
   c.close();
   SingleScanMediaFile mScanner = new SingleScanMediaFile(context, imagePath);
          mScanner.onScanCompleted(imagePath, Uri.fromFile(new File(imagePath)));
  } catch (Exception e) {
   e.printStackTrace();
        }
  
} 


 public static class SingleScanMediaFile implements MediaScannerConnectionClient {
     private MediaScannerConnection mMediaScanner;
     private String uri; 
    SingleScanMediaFile (Context c, String uri) {
         this.uri = uri;
         mMediaScanner = new MediaScannerConnection(c, this);
         mMediaScanner.connect();
    } 
   
   @Override public void onMediaScannerConnected() {
         Log.i("Sample", "MEDIA SCANNER CONNECTED");
         try { 
              mMediaScanner.scanFile(uri, null);
         } catch (Exception e) {
             e.printStackTrace();
             mMediaScanner.disconnect(); 
         }
   }
  @Override public void onScanCompleted(String path, Uri uri) {
        Log.i("sample", "MEDIA SCANING COMPLETED");
        mMediaScanner.disconnect(); 
   } 
 }   

Escaping single quotes when using SQLite in Android

A verycommon problem while using sqlite and content providers are single quotes in arguements of query. Eventhough  we are not bothered about the same, it may lead to some problems  while executing the query. A simple approach to solve this issue is to use  content values and  selectionArgs.   Some examples are given below.


String sql = "select COUNT(*) FROM  table name WHERE parameter=?"; // parameter - column name
 mDB.rawQuery(sql , new String[]{param value} );

ContentValues values = new ContentValues();
values.put("categoryId", category.getCategoryId());
mDB.insert(table name , "NULL", values);


ContentValues values = new ContentValues();
values.put("registeredDate", regDate);
mDB.update(table name, values, "postId=?", new String[]{postId});

Saturday, March 3, 2012

Android : ListView inside a ScrollView

If there is a requirement  to place listview inside a scrollview , we cant implement it directly because of their vertical scroll property . To achieve this , after calling adpater.notifyDataSetChanged() , find the width and height of the listview  and invoke  requestLayout function. By doing this the performance of the list view become poor because we are changing listview as a normal linearlayout. It becomes a normal view group and child.




public static void setListViewHeightBasedOnChildren(ListView listView) {
  ListAdapter listAdapter = listView.getAdapter();
  if (listAdapter == null) {
   // pre-condition
   return;
  }

  int totalHeight = 0;
  int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(),
    MeasureSpec.AT_MOST);
  for (int i = 0; i < listAdapter.getCount(); i++) {
   View listItem = listAdapter.getView(i, null, listView);
   listItem.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
   totalHeight += listItem.getMeasuredHeight();
  }

  ViewGroup.LayoutParams params = listView.getLayoutParams();
  params.height = totalHeight
    + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
  listView.setLayoutParams(params);
  listView.requestLayout();
 }

Friday, March 2, 2012

UTF-8 Encoding of parameters in POST request

We should consider  encoding of  the parameters  which we sent on  http request.. Otherwise when a parameter  such as in japaneese language then request may not be a successful one .In an http post request we can do it as below.

ArrayList<namevaluepair> nameValuePairs = new ArrayList<namevaluepair>();
nameValuePairs.add(new BasicNameValuePair("parameter","parameter value"));
URL url = new URL(" url string ");

AbstractHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url.toURI());
httpPost.addHeader("Date", dateCurrent);
int nResponse = 0;
HttpResponse response = null;
try {
         httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs , "UTF-8"));
         response = httpClient.execute(httpPost);
        nResponse = response.getStatusLine().getStatusCode();
        if (nResponse == HttpURLConnection.HTTP_OK) {
          InputStream instream = response.getEntity().getContent();
                              // Process the stream
        }else if (nResponse == HttpURLConnection.HTTP_UNAUTHORIZED) {
        String res = readStream(response.getEntity().getContent());
        Log.i("Response", res);
                            // Process the error stream.
       }
   }  catch (Exception e) {
 e.printStackTrace();
}
return null;
}

Progress Dialog issue when clicking default search button in Android

When we are using a Non-cancelable progress dialog , There a chance to dismiss when a  when a user click in default search button of Anroid phone.. To prevent this , Override keylistner of the progress dialog and consume that event.
For example :

mDialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
  @Override
  public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
   if (keyCode == KeyEvent.KEYCODE_SEARCH && event.getRepeatCount() == 0) {
    return true; // Pretend we processed it
   }
  return false; // Any other keys are still processed as normal
  }
});