Jul 30, 2012

Force MediaScannerConnection to rescan updated media file

MediaScannerConnection provides a way for applications to pass a newly created or downloaded media file to the media scanner service. The media scanner service will read metadata from the file and add the file to the media content provider. The MediaScannerConnectionClient provides an interface for the media scanner service to return the Uri for a newly scanned file to the client of the MediaScannerConnection class.

MediaScannerConnectionClient provide an interface for notifying clients of MediaScannerConnection when a connection to the MediaScanner service has been established and when the scanning of a file has completed.


In the article "Set latitude and longitude in Exif, setAttribute() and saveAttributes()", the updated GPS Tags in Exif cannot be recognized by build-in Gallery app after updated, untill system system re-boot! It's because the system MediaStore not yet known it. In order to force MediaStore to re-scan the updated file, we can call pass the updated media file to MediaScannerConnection.

 public static void scanFile(Context context, String path, String mimeType ) {
  Client client = new Client(path, mimeType);
     MediaScannerConnection connection = new MediaScannerConnection(context, client);
     
     client.connection = connection;
     connection.connect();
 }

 private static final class Client implements MediaScannerConnectionClient {
     private final String path;
     private final String mimeType;
     MediaScannerConnection connection;

     public Client(String path, String mimeType) {
         this.path = path;
         this.mimeType = mimeType;
     }
     
     @Override
     public void onMediaScannerConnected() {
         connection.scanFile(path, mimeType);
     }

     @Override
     public void onScanCompleted(String path, Uri uri) {
         connection.disconnect();    
     }
 }


Call scanFile(<context>, <path>, null) to scan the file.
If mimeType is null, then the mimeType will be inferred from the file extension.

Reference: http://stackoverflow.com/questions/5107823/force-scan-files-after-taking-photo


Jul 25, 2012

DialogFragment with interface to pass data back to activity

The articles "Create custom dialog with EditText" and "Pass back data from dialog to activity" introduced custom Dialog in pre-Honeycomb way.

Honeycomb introduced Fragments to support reusing portions of UI and logic across multiple activities in an app. In parallel, the showDialog / dismissDialog methods in Activity are being deprecated in favor of DialogFragments. (reference: http://android-developers.blogspot.hk/2012/05/using-dialogfragments.html)

This article show how to modify last article "Pass back data from dialog to activity" to do the same function in DialogFragment way, with interface to pass data from DialogFragment to main activity.

DialogFragment with interface to pass data back to activity

DialogFragment with interface to pass data back to activity


To use android.app.DialogFragment, android:minSdkVersion="11" is needed to be specified in AndroidManifest.xml.

MyDialogFragment.java
package com.AndroidCustomDialog;

import android.app.DialogFragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

/*
 *  To use android.app.DialogFragment, 
 *  android:minSdkVersion="11" is needed to be specified in AndroidManifest.xml
 */
public class MyDialogFragment extends DialogFragment{
 
 TextView customDialog_TextView;
 EditText customDialog_EditText;
 Button customDialog_Update, customDialog_Dismiss;
 
 static MyDialogFragment newInstance() {
  return new MyDialogFragment(); 
 }

 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container,
   Bundle savedInstanceState) {
  View dialogView = inflater.inflate(R.layout.customlayout, container, false);
  
  customDialog_TextView = (TextView)dialogView.findViewById(R.id.dialogtextview);
  customDialog_Update = (Button)dialogView.findViewById(R.id.dialogupdate);
  customDialog_Dismiss = (Button)dialogView.findViewById(R.id.dialogdismiss);
  customDialog_Update.setOnClickListener(customDialog_UpdateOnClickListener);
  customDialog_Dismiss.setOnClickListener(customDialog_DismissOnClickListener);
  
  customDialog_EditText = (EditText)dialogView.findViewById(R.id.dialogedittext);
  
  return dialogView;
 }
 
 
 private Button.OnClickListener customDialog_UpdateOnClickListener
  = new Button.OnClickListener(){
 
  @Override
  public void onClick(View arg0) {
   // TODO Auto-generated method stub
   customDialog_TextView.setText(customDialog_EditText.getText().toString());
  }  
 };

 private Button.OnClickListener customDialog_DismissOnClickListener
  = new Button.OnClickListener(){
 
  @Override
  public void onClick(View arg0) {
   // TODO Auto-generated method stub
   EditDialogListener activity = (EditDialogListener) getActivity();
            activity.updateResult(customDialog_EditText.getText().toString());
            
   dismiss(); 
  } 
 };
 
 public interface EditDialogListener {
        void updateResult(String inputText);
    }

}


/res/layout/customlayout.xml.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/customdialog"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:padding="10dp">
<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/ic_launcher"/>
<TextView
    android:id="@+id/dialogtextview"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>
<EditText
    android:id="@+id/dialogedittext"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"/>
<Button
    android:id="@+id/dialogupdate"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="Update"/>
<Button
    android:id="@+id/dialogdismiss"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="Dismiss"/>
</LinearLayout>


MainActivity.java
package com.AndroidCustomDialog;

import com.AndroidCustomDialog.MyDialogFragment.EditDialogListener;
import android.os.Bundle;
import android.app.Activity;
import android.app.DialogFragment;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity implements EditDialogListener{
 
 String result = "";
 TextView textReturned;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        textReturned = (TextView)findViewById(R.id.textreturned);
        
        Button buttonStartDialog = (Button)findViewById(R.id.startdialog);
        buttonStartDialog.setOnClickListener(new Button.OnClickListener(){
         
         @Override
         public void onClick(View arg0) {
          // TODO Auto-generated method stub
          //showDialog(CUSTOM_DIALOG_ID); 
          
          DialogFragment newFragment = MyDialogFragment.newInstance();
             newFragment.show(getFragmentManager(), "dialog");
             
         }});
    }

 public void updateResult(String inputText) {
  result = inputText;
  textReturned.setText(result);
  
 }
    
}


/res/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
<TextView
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/hello_world"/>
<Button
    android:id="@+id/startdialog"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text=" Start Dialog "/>
<TextView
    android:id="@+id/textreturned"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"/>
</LinearLayout>


Jul 24, 2012

Pass back data from dialog to activity

In the article "Create custom dialog with EditText", a dialog with user editable field (EditText) was implemented. To pass back the user enter data from dialog to activity, we can create a global variable. Because both the main activity and the dialog are in the same class, such that both can access the global variable directly.

Pass back data from dialog to activity


Main code in MainActivity.java.
package com.AndroidCustomDialog;

import android.os.Bundle;
import android.app.Activity;
import android.app.Dialog;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends Activity {
 
 static final int CUSTOM_DIALOG_ID = 0;
  
 TextView customDialog_TextView;
 EditText customDialog_EditText;
 Button customDialog_Update, customDialog_Dismiss;
 
 String result = "";
 TextView textReturned;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        textReturned = (TextView)findViewById(R.id.textreturned);
        
        Button buttonStartDialog = (Button)findViewById(R.id.startdialog);
        buttonStartDialog.setOnClickListener(new Button.OnClickListener(){
         
         @Override
         public void onClick(View arg0) {
          // TODO Auto-generated method stub
          showDialog(CUSTOM_DIALOG_ID); 
         }});
    }
    
    private Button.OnClickListener customDialog_UpdateOnClickListener
     = new Button.OnClickListener(){
     
     @Override
     public void onClick(View arg0) {
      // TODO Auto-generated method stub
      customDialog_TextView.setText(customDialog_EditText.getText().toString());
      
      result = customDialog_EditText.getText().toString();
      textReturned.setText(result);
     } 
    };
    
    private Button.OnClickListener customDialog_DismissOnClickListener
     = new Button.OnClickListener(){
     
     @Override
     public void onClick(View arg0) {
      // TODO Auto-generated method stub
      dismissDialog(CUSTOM_DIALOG_ID); 
     } 
    };
     
    @Override
    protected Dialog onCreateDialog(int id) {
     // TODO Auto-generated method stub
     Dialog dialog = null;;
     
     switch(id) {
     case CUSTOM_DIALOG_ID:
      dialog = new Dialog(MainActivity.this);
      
      dialog.setContentView(R.layout.customlayout);
      dialog.setTitle("Custom Dialog");
      
      customDialog_EditText = (EditText)dialog.findViewById(R.id.dialogedittext);
      customDialog_TextView = (TextView)dialog.findViewById(R.id.dialogtextview);
      customDialog_Update = (Button)dialog.findViewById(R.id.dialogupdate);
      customDialog_Dismiss = (Button)dialog.findViewById(R.id.dialogdismiss);
      customDialog_Update.setOnClickListener(customDialog_UpdateOnClickListener);
      customDialog_Dismiss.setOnClickListener(customDialog_DismissOnClickListener);
      break; 
     }
     return dialog; 
    }
    
}


/res/layout/customlayout.xml, the layout of the dialog.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/customdialog"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:padding="10dp">
<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/ic_launcher"/>
<TextView
    android:id="@+id/dialogtextview"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>
<EditText
    android:id="@+id/dialogedittext"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"/>
<Button
    android:id="@+id/dialogupdate"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="Update"/>
<Button
    android:id="@+id/dialogdismiss"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="Dismiss"/>
</LinearLayout>


Main layout, /res/layout/activity_main.xml.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
<TextView
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/hello_world"/>
<Button
    android:id="@+id/startdialog"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text=" Start Dialog "/>
<TextView
    android:id="@+id/textreturned"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"/>
</LinearLayout>


Next:
- DialogFragment with interface to pass data back to activity


Jul 15, 2012

Tailor made app for Google Patents Search with WebView

Google provide a nice service, Google Patents (http://www.google.com/patents). With Google Patents, you can now search the full text of the U.S. patent corpus and find patents that interest you.

It's a simple tailor made app to provide a short-cut to Google Patents.

Google Patents Search


package com.example.googlepatents;

import android.os.Bundle;
import android.app.Activity;
import android.view.Window;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class MainActivity extends Activity {

 String GooglePatentsPath = "http://www.google.com/patents";
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        WebView webView = new WebView(this);
        
        getWindow().requestFeature(Window.FEATURE_PROGRESS);
        setContentView(webView);
        
        WebSettings webSettings = webView.getSettings();
        webSettings.setJavaScriptEnabled(true);  //enable JavaScript execution
        webSettings.setBuiltInZoomControls(true); //enable built-in zoom
        webSettings.setUseWideViewPort(true);  //use the wide viewport
        webSettings.setLoadWithOverviewMode(true); //loads with overview mode
        
        webView.setWebViewClient(new MyWebViewClient());
        
        webView.loadUrl(GooglePatentsPath);
      
        final Activity activity = this;
        webView.setWebChromeClient(new WebChromeClient() {
        
         public void onProgressChanged(WebView view, int progress) {
          activity.setProgress(progress * 100);  
         }});
    }

    public class MyWebViewClient extends WebViewClient {
     
     @Override
     public boolean shouldOverrideUrlLoading(WebView view, String url) {
      view.loadUrl(url);
      return true;
      }
      }

}


Note: Permission of "android.permission.INTERNET" is needed.


Jul 12, 2012

Display image in WebView

If you are so lazy as me! Display image in WebView is a good choice.

Display image in WebView


package com.example.androidwebviewphoto;

import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.webkit.WebView;

public class MainActivity extends Activity {
 
 WebView webView;
 String imagePath = "/tmp/testphoto.jpg";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setContentView(R.layout.activity_main);
        
        webView = new WebView(this);
        setContentView(webView);
        
        String fullUrl = "file://" 
          + Environment.getExternalStorageDirectory().getAbsolutePath().toString() 
          + "/" 
          + imagePath;
        webView.loadUrl(fullUrl);
        webView.getSettings().setBuiltInZoomControls(true);
        webView.getSettings().setUseWideViewPort(true);
        webView.getSettings().setLoadWithOverviewMode(true);

    }
    
}


Infolinks In Text Ads