Sunday, 1 March 2015

Android Example: Progress Bar Tutorial (with secondary progress)



Progress bars are used to show progress of a task. In this example, we will show you a simple application to illustrate the use of progress bar in Android development. It mainly use the class android.widget.ProgressBar.

In this example, there is a secondary progress displayable on a progress bar which is useful for displaying intermediate progress, such as the buffer level during a streaming playback progress bar.

activity_main.xml This is the XML file for the layout of the application.
<?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" 
    /> 
<ProgressBar 
android:id="@+id/firstBar" 
style="?android:attr/progressBarStyleHorizontal" 
android:layout_width="200dp" 
android:layout_height="wrap_content" 
android:visibility="gone" 
/> 
<ProgressBar 
android:id="@+id/secondBar" 
style="?android:attr/progressBarStyle" 
android:layout_width="wrap_content" 
android:layout_height="wrap_content" 
android:visibility="gone" 
/> 
<Button 
android:id="@+id/myButton" 
android:layout_width="wrap_content" 
android:layout_height="wrap_content" 
android:text="begin"/> 
</LinearLayout> 


Activity01.java This is the main Activity class.
package com.easyinfogeek.progress;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;

public class Activity01 extends Activity {
 
 private ProgressBar firstBar = null;
 private ProgressBar secondBar = null;
 private Button myButton;
 private int i = 0;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        firstBar = (ProgressBar)findViewById(R.id.firstBar);
        secondBar = (ProgressBar)findViewById(R.id.secondBar);
        myButton = (Button)findViewById(R.id.myButton);
        myButton.setOnClickListener(new ButtonListener());
        
    }
    
    class ButtonListener implements OnClickListener{
  @Override
  public void onClick(View v) {
   if (i == 0 || i == 10) {
    //make the progress bar visible
    firstBar.setVisibility(View.VISIBLE);
    firstBar.setMax(150);
    secondBar.setVisibility(View.VISIBLE);
   }else if ( i< firstBar.getMax() ) {
    //Set first progress bar value
    firstBar.setProgress(i);
    //Set the second progress bar value
    firstBar.setSecondaryProgress(i + 10);
   }else {

    firstBar.setProgress(0);

    firstBar.setSecondaryProgress(0);

    i = 0;
    firstBar.setVisibility(View.GONE);
    secondBar.setVisibility(View.GONE);
   }
   i = i + 10;
  }
    }
}
Wednesday, 11 February 2015

Android Example: Develope Drawing and Graphic Apps


In this example, we will show you how to create a simple drawing pad app in Android. You can change your pen style and color in the application. You can also saved your drawing after painting. It mainly make use of the android.graphics package. We can see the source code here:

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.easyinfogeek.drawingpad"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.easyinfogeek.drawingpad.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>


Activity class and View Class
MainActivity.java
package com.easyinfogeek.drawingpad;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.graphics.Color;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
import android.view.Window;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {
 

 private DrawPadView hbView;

 private AlertDialog dialog;
 private View dialogView;
 private TextView shouWidth;
 private SeekBar widthSb;
 private int paintWidth;
  
 private void initView(){
  dialogView = getLayoutInflater().inflate(R.layout.dialog_width_set, null);
  shouWidth = (TextView) dialogView.findViewById(R.id.textView1);
  widthSb = (SeekBar) dialogView.findViewById(R.id.seekBar1);
  widthSb.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
   
   @Override
   public void onStopTrackingTouch(SeekBar seekBar) {
    
   }
   
   @Override
   public void onStartTrackingTouch(SeekBar seekBar) {
    
   }
   
   @Override
   public void onProgressChanged(SeekBar seekBar, int progress,
     boolean fromUser) {
    shouWidth.setText("Current Width:"+(progress+1));
    paintWidth = progress+1;
   }
  });
  hbView = (DrawPadView)findViewById(R.id.drawPadView1);
  dialog = new AlertDialog.Builder(this).setIcon(android.R.drawable.ic_dialog_info).setTitle("Set the size of your Pen").
    setView(dialogView).setPositiveButton("Confirm", new OnClickListener() {
     
     @Override
     public void onClick(DialogInterface dialog, int which) {
      hbView.setPaintWidth(paintWidth);
     }
    }).setNegativeButton("Cancel", null).create();
 }

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
 
  requestWindowFeature(Window.FEATURE_NO_TITLE);
  setContentView(R.layout.activity_main);
  initView();
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  SubMenu colorSm = menu.addSubMenu(1, 1, 1, "Select Pen color");
  colorSm.add(2, 200, 200, "red");
  colorSm.add(2, 210, 210, "green");
  colorSm.add(2, 220, 220, "blue");
  colorSm.add(2, 230, 230, "purple");
  colorSm.add(2, 240, 240, "yellow");
  colorSm.add(2, 250, 250, "black");
  menu.add(1, 2, 2, "Set pen size");
  SubMenu widthSm = menu.addSubMenu(1, 3, 3, "Set Pen style");
  widthSm.add(3, 300, 300, "Stoke");
  widthSm.add(3, 301, 301, "Fill ");
  menu.add(1, 4, 4, "Clear Drawing");
  menu.add(1, 5, 5, "Save drawing");
  menu.add(1, 6, 6, "Exit");
  return true;
 }
 
 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  int index = item.getItemId();
  switch(index){
  case 200:
   hbView.setColor(Color.RED);
   break;
  case 210:
   hbView.setColor(Color.GREEN);
   break;
  case 220:
   hbView.setColor(Color.BLUE);
   break;
  case 230:
   hbView.setColor(Color.MAGENTA);
   break;
  case 240:
   hbView.setColor(Color.YELLOW);
   break;
  case 250:
   hbView.setColor(Color.BLACK);
   break;
  case 2:
   dialog.show();
   break;
  case 300:
   hbView.setStyle(DrawPadView.PEN);
   break;
  case 301:
   hbView.setStyle(DrawPadView.PAIL);
   break;
  case 4:
   hbView.clearScreen();
   break;
  case 5:
   if(SaveViewUtil.saveScreen(hbView)){
    Toast.makeText(this, "Save drawing succeed!", 0).show();
   }else{
    Toast.makeText(this, "Save drawing fail. Please check your SD card", 0).show();
   }
   break;
  case 6:
   finish();
   break;
  }
  return true;
 }
 

}


DrawPadView.java
package com.easyinfogeek.drawingpad;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;



public class DrawPadView extends View {


 private Bitmap cacheBitmap;

 private Canvas cacheCanvas;

 private Paint paint;

 private Paint BitmapPaint;

 private Path path;

 private int height;

 private int width;
 
 /** Last saved X-coordinate */
 private float pX;
 /** Last saved Y-coordinate*/
 private float pY;
 
 /** Initial color */
 private int paintColor = Color.RED;
 
 private static Paint.Style paintStyle = Paint.Style.STROKE;
 /** Paint Point size */
 private static int paintWidth = 3;
 
 private Canvas canvas;
 
 
 /** get the height and width */
 @Override
 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  height = h;
  width = w;
  init();
 }
 
 private void init(){
  cacheBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
  cacheCanvas = new Canvas(cacheBitmap);
  paint = new Paint(Paint.ANTI_ALIAS_FLAG);
  path = new Path();
  BitmapPaint = new Paint();
  updatePaint();
 }
 
 private void updatePaint(){
  paint.setColor(paintColor);
  paint.setStyle(paintStyle);
  paint.setStrokeWidth(paintWidth);
 }
 
 public DrawPadView(Context context, AttributeSet attrs) {
  super(context, attrs);
 }
 
 public DrawPadView(Context context){
  super(context);
 }
 
 @Override
 public boolean onTouchEvent(MotionEvent event) {
  int action = event.getAction();
  switch (action) {
  case MotionEvent.ACTION_DOWN:
   path.moveTo(event.getX(), event.getY());
   pX = event.getX();
   pY = event.getY();
   break;
  case MotionEvent.ACTION_MOVE:
   path.quadTo(pX, pY, event.getX(), event.getY());
   pX = event.getX();
   pY = event.getY();
   break;
  case MotionEvent.ACTION_UP:
   cacheCanvas.drawPath(path, paint);
   path.reset();
   break;
  }
  invalidate();
  
  return true;
 }
 
 @Override
 protected void onDraw(Canvas canvas) {
  this.canvas = canvas;
  BitmapPaint = new Paint();
  canvas.drawBitmap(cacheBitmap, 0,0, BitmapPaint);
  canvas.drawPath(path, paint);
  
 }
 
 
 public void setColor(int color){
  paintColor = color;
  updatePaint();
 }
 
 
 public void setPaintWidth(int width){
  paintWidth = width;
  updatePaint();
 }
 
 public static final int PEN = 1;
 public static final int PAIL = 2;
 

 public void setStyle(int style){
  switch(style){
  case PEN:
   paintStyle = Paint.Style.STROKE;
   break;
  case PAIL:
   paintStyle = Paint.Style.FILL;
   break;
  }
  updatePaint();
 }
 
 /** clear your drawing*/
 public void clearScreen(){
  if(canvas != null){
   Paint backPaint = new Paint();
   backPaint.setColor(Color.WHITE);
   canvas.drawRect(new Rect(0, 0, width, height), backPaint);
   cacheCanvas.drawRect(new Rect(0, 0, width, height), backPaint);
  }
  invalidate();
 }
 
}

Other XML file for layout:
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <com.example.huatuban.DrawPadView
        android:id="@+id/drawPadView1"
        android:background="#ffffffff"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>


menu_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="setColor" />

    <RadioButton
        android:id="@+id/radioButton1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="blue"
        android:button="@null"
        android:background="@drawable/selector_blueselector"
         />
    
    <Button android:background="@drawable/menu_blue"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
        android:text="hehe"/>

</LinearLayout>


dialog_width_set.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Set the width" />

    <SeekBar
        android:id="@+id/seekBar1"
        android:layout_width="match_parent"
        android:max="9"
        android:progress="2"
        android:layout_height="wrap_content" />

</LinearLayout>




Utility Class for save image
SaveViewUtil.java
package com.easyinfogeek.drawingpad;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.os.Environment;
import android.view.View;

public class SaveViewUtil {
 
 private static final File rootDir = new File(Environment.getExternalStorageDirectory()+File.separator+"huaban/");

 /** Save picture to file */
 public static boolean saveScreen(View view){
  //determine if SDCARD is available
  if(!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){
   return false;
  }
  if(!rootDir.exists()){
   rootDir.mkdir();
  }
  view.setDrawingCacheEnabled(true);
  view.buildDrawingCache();
  Bitmap bitmap = view.getDrawingCache();
  try {
   bitmap.compress(CompressFormat.JPEG, 100, new FileOutputStream(new File(rootDir,System.currentTimeMillis()+".jpg")));
   return true;
  } catch (FileNotFoundException e) {
   e.printStackTrace();
   return false;
  }finally{
   view.setDrawingCacheEnabled(false);
   bitmap = null;
  }
 }
}




Monday, 9 February 2015

Android Development Tips: Invoking different Android system Activity / Apps 2 (Others)

In this post, I will continue summarize some methods to invoke different Android built-in system activity/ Apps.

Invoke Google Search
Intent intent = new Intent();   
intent.setAction(Intent.ACTION_WEB_SEARCH);   
intent.putExtra(SearchManager.QUERY,"searchString")   
startActivity(intent);   
Invoke Browser
Uri uri = Uri.parse("http://www.google.com");   
Intent it   = new Intent(Intent.ACTION_VIEW,uri);   
startActivity(it);   
Invoke Google Map
Uri uri = Uri.parse("geo:38.899533,-77.036476");   
Intent it = new Intent(Intent.Action_VIEW,uri);   
startActivity(it);   
Plan a route in Google Map
Uri uri = Uri.parse("http://maps.google.com/maps?f=dsaddr=startLat%20startLng&daddr=endLat%20endLng&hl=en");   
Intent it = new Intent(Intent.ACTION_VIEW,URI);   
startActivity(it);  
Sending SMS
Uri uri = Uri.parse("smsto:0800000123");     
Intent it = new Intent(Intent.ACTION_SENDTO, uri);     
it.putExtra("sms_body", "The SMS text");     
startActivity(it);   
String body="this is sms demo";   
Intent mmsintent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts("smsto", number, null));   
mmsintent.putExtra(Messaging.KEY_ACTION_SENDTO_MESSAGE_BODY, body);   
mmsintent.putExtra(Messaging.KEY_ACTION_SENDTO_COMPOSE_MODE, true);   
mmsintent.putExtra(Messaging.KEY_ACTION_SENDTO_EXIT_ON_SENT, true);   
startActivity(mmsintent);<span style="font-family:Simsun;white-space: normal; background-color: rgb(255, 255, 255);"> </span>  
Sending MMS
Uri uri = Uri.parse("content://media/external/images/media/23");     
Intent it = new Intent(Intent.ACTION_SEND);     
it.putExtra("sms_body", "some text");     
it.putExtra(Intent.EXTRA_STREAM, uri);     
it.setType("image/png");     
startActivity(it);   
StringBuilder sb = new StringBuilder();   
sb.append("file://");   
sb.append(fd.getAbsoluteFile());   
Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts("mmsto", number, null));   
// Below extra datas are all optional.   
intent.putExtra(Messaging.KEY_ACTION_SENDTO_MESSAGE_SUBJECT, subject);   
intent.putExtra(Messaging.KEY_ACTION_SENDTO_MESSAGE_BODY, body);   
intent.putExtra(Messaging.KEY_ACTION_SENDTO_CONTENT_URI, sb.toString());   
intent.putExtra(Messaging.KEY_ACTION_SENDTO_COMPOSE_MODE, composeMode);   
intent.putExtra(Messaging.KEY_ACTION_SENDTO_EXIT_ON_SENT, exitOnSent);   
startActivity(intent);   
Sending Email
Uri uri = Uri.parse("mailto:xxx@abc.com");   
Intent it = new Intent(Intent.ACTION_SENDTO, uri);   
startActivity(it);   
Intent it = new Intent(Intent.ACTION_SEND);     
it.putExtra(Intent.EXTRA_EMAIL, "me@abc.com");     
it.putExtra(Intent.EXTRA_TEXT, "The email body text");     
it.setType("text/plain");     
startActivity(Intent.createChooser(it, "Choose Email Client"));   
Intent it=new Intent(Intent.ACTION_SEND);       
String[] tos={"me@abc.com"};       
String[] ccs={"you@abc.com"};       
it.putExtra(Intent.EXTRA_EMAIL, tos);       
it.putExtra(Intent.EXTRA_CC, ccs);       
it.putExtra(Intent.EXTRA_TEXT, "The email body text");       
it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");       
it.setType("message/rfc822");       
startActivity(Intent.createChooser(it, "Choose Email Client"));     
  
Intent it = new Intent(Intent.ACTION_SEND);     
it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");     
it.putExtra(Intent.EXTRA_STREAM, "file:///sdcard/mysong.mp3");     
sendIntent.setType("audio/mp3");     
startActivity(Intent.createChooser(it, "Choose Email Client"));   

Invoke Media Player
Intent it = new Intent(Intent.ACTION_VIEW);   
Uri uri = Uri.parse("file:///sdcard/song.mp3");   
it.setDataAndType(uri, "audio/mp3");   
startActivity(it);   
Uri uri = Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI, "1");     
Intent it = new Intent(Intent.ACTION_VIEW, uri);     
startActivity(it);   
Uninstall APK
Uri uri = Uri.fromParts("package", strPackageName, null);     
Intent it = new Intent(Intent.ACTION_DELETE, uri);     
startActivity(it);   
Uninstall APK
Uri installUri = Uri.fromParts("package", "xxx", null);   
returnIt = new Intent(Intent.ACTION_PACKAGE_ADDED, installUri);   
Invoke Camera
<1>Intent i = new Intent(Intent.ACTION_CAMERA_BUTTON, null);   
          this.sendBroadcast(i);   
    <2>long dateTaken = System.currentTimeMillis();   
         String name = createName(dateTaken) + ".jpg";   
         fileName = folder + name;   
         ContentValues values = new ContentValues();   
         values.put(Images.Media.TITLE, fileName);   
         values.put("_data", fileName);   
         values.put(Images.Media.PICASA_ID, fileName);   
         values.put(Images.Media.DISPLAY_NAME, fileName);   
         values.put(Images.Media.DESCRIPTION, fileName);   
         values.put(Images.ImageColumns.BUCKET_DISPLAY_NAME, fileName);   
         Uri photoUri = getContentResolver().insert(   
                   MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);   
             
         Intent inttPhoto = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);   
         inttPhoto.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);   
         startActivityForResult(inttPhoto, 10);   
Open photo gallery
Intent i = new Intent();   
        i.setType("image/*");   
        i.setAction(Intent.ACTION_GET_CONTENT);   
        startActivityForResult(i, 11);   
Invoke recorder
Intent mi = new Intent(Media.RECORD_SOUND_ACTION);   
         startActivity(mi); 
Application list
Uri uri = Uri.parse("market://details?id=app_id");          
Intent it = new Intent(Intent.ACTION_VIEW, uri);          
startActivity(it);          
//where app_id is the application ID, find the ID           
//by clicking on your application on Market home           
//page, and notice the ID from the address bar<span style="font-family:Simsun;white-space: normal; background-color: rgb(255, 255, 255);">    </span>  

Sunday, 8 February 2015

Android Development Tips: Invoking different Android system Activity / Apps 1 (Phone / Dialing related)


When developing Android application, we always need to invoke other system applcation (e.g. contact, phone dialer, camera,etc) In this post, I will summarize some method to invoke different phone and dialing related system activity.
1. Start the phone dialer
Intent intent =new Intent();  
intent.setAction("android.intent.action.CALL_BUTTON");  
startActivity(intent);  
OR
Uri uri = Uri.parse("tel:xxxxxx");   
Intent intent = new Intent(Intent.ACTION_DIAL, uri);     
startActivity(intent); 
2. Go to Dialer Applciation
Intent intent= new Intent("android.intent.action.DIAL");   
intent.setClassName("com.android.contacts","com.android.contacts.DialtactsActivity");  
3. Open Phone Contacts List
Intent intent = new Intent();   
intent.setAction(Intent.ACTION_VIEW);   
intent.setData(Contacts.People.CONTENT_URI);   
startActivity(intent);   
4. Pick a Phone Contact
Intent intent = new Intent();   
intent.setAction(Intent.ACTION_PICK);   
intent.setData(Contacts.People.CONTENT_URI);   
startActivity(intent);   
5. Edit a phone contact
Intent intent=new Intent(Intent.ACTION_EDIT,Uri.parse("content://com.android.contacts/contacts/"+"1"));  
startActivity(intent);  
6. Add a new phone contact
Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);  
            intent.setType("vnd.android.cursor.item/person");  
            intent.setType("vnd.android.cursor.item/contact");  
            intent.setType("vnd.android.cursor.item/raw_contact");  
            intent.putExtra(android.provider.ContactsContract.Intents.Insert.NAME, name);  
            intent.putExtra(android.provider.ContactsContract.Intents.Insert.COMPANY,company);  
            intent.putExtra(android.provider.ContactsContract.Intents.Insert.PHONE, tel);  
            intent.putExtra(android.provider.ContactsContract.Intents.Insert.PHONE_TYPE, 3);  
7. Invoke send SMS and MMS UI
Intent intent = new Intent(Intent.ACTION_VIEW);  
                intent.setType("vnd.android-dir/mms-sms");  
                startActivity(intent);  

Saturday, 7 February 2015

Android Tutorial: Custom Audio Capture Button (Whatsapp / WeChat style)


The Android multimedia framework includes support for capturing and encoding a variety of common audio formats, so that you can easily integrate audio into your applications.

The following is an example of Android Audio Capture function. It is a record button similar to that of Whatsapp.

The following is the source code for the custom control.
1. Custom Record button. The record dialog will pop up.

/**
 * Record button. It will popup record dialog.
 */
public class RecordButton extends Button {
    private static final int MIN_INTERVAL_TIME = 700; // Minimum record time
    private static final int MAX_INTERVAL_TIME = 60000; // Maximum record time
    private RecordButtonUtil mAudioUtil;
    private Handler mVolumeHandler; //  Change the volumne image

    public RecordButton(Context context) {
        super(context);
        mVolumeHandler = new ShowVolumeHandler(this);
        mAudioUtil = new RecordButtonUtil();
        initSavePath();
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (mAudioFile == null) {
            return false;
        }
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            initlization();
            break;
        case MotionEvent.ACTION_UP:
            if (event.getY() < -50) {
                cancelRecord();
            } else {
                finishRecord();
            }
            break;
        case MotionEvent.ACTION_MOVE:

            break;
        }
        return true;
    }

    /** initialize dialog and recorder */
    private void initlization() {
        mStartTime = System.currentTimeMillis();
        if (mRecordDialog == null) {
            mRecordDialog = new Dialog(getContext());
            mRecordDialog.setOnDismissListener(onDismiss);
        }
        mRecordDialog.show();
        startRecording();
    }

    /** Finish recording */
    private void finishRecord() {
        stopRecording();
        mRecordDialog.dismiss();
        long intervalTime = System.currentTimeMillis() - mStartTime;
        if (intervalTime < MIN_INTERVAL_TIME) {
            AppContext.showToastShort(R.string.record_sound_short);
            File file = new File(mAudioFile);
            file.delete();
            return;
        }
        if (mFinishedListerer != null) {
            mFinishedListerer.onFinishedRecord(mAudioFile,
                    (int) ((System.currentTimeMillis() - mStartTime) / 1000));
        }
    }
    // Cancel recording manually
    private void cancelRecord() {
        stopRecording();
        mRecordDialog.dismiss();
        File file = new File(mAudioFile);
        file.delete();
        if (mFinishedListerer != null) {
            mFinishedListerer.onCancleRecord();
        }
    }

    // Start Recording
    private void startRecording() {
        mAudioUtil.setAudioPath(mAudioFile);
        mAudioUtil.recordAudio();
        mThread = new ObtainDecibelThread();
        mThread.start();

    }
    // Stop recording
    private void stopRecording() {
        if (mThread != null) {
            mThread.exit();
            mThread = null;
        }
        if (mAudioUtil != null) {
            mAudioUtil.stopRecord();
        }
    }

    /******************************* inner class ****************************************/
    private class ObtainDecibelThread extends Thread {
        private volatile boolean running = true;

        public void exit() {
            running = false;
        }
        @Override
        public void run() {
            while (running) {
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (System.currentTimeMillis() - mStartTime >= MAX_INTERVAL_TIME) {
                    // if the recording exceed maximum length
                    mVolumeHandler.sendEmptyMessage(-1);
                }
                if (mAudioUtil != null && running) {
                    // If user is still recording
                    int volumn = mAudioUtil.getVolumn();
                    if (volumn != 0)
                        mVolumeHandler.sendEmptyMessage(volumn);
                } else {
                    exit();
                }
            }
        }
    }
    private final OnDismissListener onDismiss = new OnDismissListener() {
        @Override
        public void onDismiss(DialogInterface dialog) {
            stopRecording();
        }
    };
    static class ShowVolumeHandler extends Handler {
        private final WeakReference<RecordButton> mOuterInstance;
        public ShowVolumeHandler(RecordButton outer) {
            mOuterInstance = new WeakReference<RecordButton>(outer);
        }
        @Override
        public void handleMessage(Message msg) {
            RecordButton outerButton = mOuterInstance.get();
            if (msg.what != -1) {
                // >0 current volumne
                if (outerButton.mVolumeListener != null) {
                    outerButton.mVolumeListener.onVolumeChange(mRecordDialog,
                            msg.what);
                }
            } else {
                // -1 means recording time exceed limit
                outerButton.finishRecord();
            }
        }
    }

    /** Volumne change Listener */
    public interface OnVolumeChangeListener {
        void onVolumeChange(Dialog dialog, int volume);
    }
    public interface OnFinishedRecordListener {

        public void onCancleRecord();

        public void onFinishedRecord(String audioPath, int recordTime);
    }
}

2. Utility Class for recording button

/**
 * Utility class for record button
 * 
 */
public class RecordButtonUtil {
    public static final String AUDOI_DIR = Environment
            .getExternalStorageDirectory().getAbsolutePath() + "/oschina/audio"; // audio file path

    private String mAudioPath; 
    private boolean mIsRecording;
    private boolean mIsPlaying;
    private OnPlayListener listener;
 
    // initialize the recorder
    private void initRecorder() {
        mRecorder = new MediaRecorder();
        mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mRecorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB);
        mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
        mRecorder.setOutputFile(mAudioPath);
        mIsRecording = true;
    }

    /** start recording and save the file */
    public void recordAudio() {
        initRecorder();
        try {
            mRecorder.prepare();
        } catch (IOException e) {
            e.printStackTrace();
        }
        mRecorder.start();
    }

    /** get the volumne  */
    public int getVolumn() {
        int volumn = 0;
        // recording
        if (mRecorder != null && mIsRecording) {
            volumn = mRecorder.getMaxAmplitude();
            if (volumn != 0)
                volumn = (int) (10 * Math.log(volumn) / Math.log(10)) / 7;
        }
        return volumn;
    }

    /** stop recording */
    public void stopRecord() {
        if (mRecorder != null) {
            mRecorder.stop();
            mRecorder.release();
            mRecorder = null;
            mIsRecording = false;
        }
    }

    public void startPlay(String audioPath) {
        if (!mIsPlaying) {
            if (!StringUtils.isEmpty(audioPath)) {
                mPlayer = new MediaPlayer();
                try {
                    mPlayer.setDataSource(audioPath);
                    mPlayer.prepare();
                    mPlayer.start();
                    if (listener != null) {
                        listener.starPlay();
                    }
                    mIsPlaying = true;
                    mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                        @Override
                        public void onCompletion(MediaPlayer mp) {
                            if (listener != null) {
                                listener.stopPlay();
                            }
                            mp.release();
                            mPlayer = null;
                            mIsPlaying = false;
                        }
                    });
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                AppContext.showToastShort(R.string.record_sound_notfound);
            }
        } // end playing
    }
    public interface OnPlayListener {
      
        void stopPlay();

      
        void starPlay();
    }
}

3. Touch event in the activity class
public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            initlization();
            break;
        case MotionEvent.ACTION_UP:
            if (mIsCancel && event.getY() < -50) {
                cancelRecord();
            } else {
                finishRecord();
            }
            mIsCancel = false;
            break;
        case MotionEvent.ACTION_MOVE:

            break;
        }
        return true;
    }

Thursday, 5 February 2015

Android Development Example : IP address input control


In recent development projcet, one of my friends have encountered a case that she needed to create a input control for user to type in IP address. The screen layout is like this:
The following is the source code for the custom control. It basically contains 4 editText.


package com.easyinfogeek.view;  
  
import android.content.Context;  
import android.content.SharedPreferences;  
import android.content.SharedPreferences.Editor;  
import android.text.Editable;  
import android.text.TextUtils;  
import android.text.TextWatcher;  
import android.util.AttributeSet;  
import android.view.LayoutInflater;  
import android.view.View;  
import android.widget.EditText;  
import android.widget.LinearLayout;  
import android.widget.Toast;  
  
import com.easyinfogeek.R;  
  
/** 
 * IP input control
 *  
 * @author Shela
 *  
 *         
 */  
public class IPEditText extends LinearLayout {  
  
    private EditText mFirstIP;  
    private EditText mSecondIP;  
    private EditText mThirdIP;  
    private EditText mFourthIP;  
  
    private String mText;  
    private String mText1;  
    private String mText2;  
    private String mText3;  
    private String mText4;  
  
    private SharedPreferences mPreferences;  
  
    public IPEditText(Context context, AttributeSet attrs) {  
        super(context, attrs);  
  
        /** 
         * Initialize
         */  
        View view = LayoutInflater.from(context).inflate(  
                R.layout.custom_my_edittext, this);  
        mFirstIP = (EditText)findViewById(R.id.ip_first);  
        mSecondIP = (EditText)findViewById(R.id.ip_second);  
        mThirdIP = (EditText)findViewById(R.id.ip_third);  
        mFourthIP = (EditText)findViewById(R.id.ip_fourth);  
  
        mPreferences = context.getSharedPreferences("config_IP",  
                Context.MODE_PRIVATE);  
  
        OperatingEditText(context);  
    }  
  
    /** 
     * Get the content of EditText.
     * Whenever the EditText is filled with 3 digit, the cursor will move to next EditText.
     * 
     */  
    private void OperatingEditText(final Context context) {  
        mFirstIP.addTextChangedListener(new TextWatcher() {  
  
            @Override  
            public void onTextChanged(CharSequence s, int start, int before,  
                    int count) {  
                /** 
                 * Whenever the EditText is filled with 3 digit, the cursor will move to next EditText.
                 */  
                if (s != null && s.length() > 0) {  
                    if (s.length() > 2 || s.toString().trim().contains(".")) {  
                        if (s.toString().trim().contains(".")) {  
                            mText1 = s.toString().substring(0, s.length() - 1);  
                            mFirstIP.setText(mText1);  
                        } else {  
                            mText1 = s.toString().trim();  
                        }  
  
                        if (Integer.parseInt(mText1) > 255) {  
                            Toast.makeText(context, "Please input valid IP address",  
                                    Toast.LENGTH_LONG).show();  
                            return;  
                        }  
  
                        Editor editor = mPreferences.edit();  
                        editor.putInt("IP_FIRST", mText1.length());  
                        editor.commit();  
  
                        mSecondIP.setFocusable(true);  
                        mSecondIP.requestFocus();  
                    }  
                }  
  
            }  
  
            @Override  
            public void beforeTextChanged(CharSequence s, int start, int count,  
                    int after) {  
  
            }  
  
            @Override  
            public void afterTextChanged(Editable s) {  
  
            }  
        });  
  
        mSecondIP.addTextChangedListener(new TextWatcher() {  
  
            @Override  
            public void onTextChanged(CharSequence s, int start, int before,  
                    int count) {  
                /** 
                 * Check if the IP address is valid.
                 * set focus to next EditText.
                 */  
                if (s != null && s.length() > 0) {  
                    if (s.length() > 2 || s.toString().trim().contains(".")) {  
                        if (s.toString().trim().contains(".")) {  
                            mText2 = s.toString().substring(0, s.length() - 1);  
                            mSecondIP.setText(mText2);  
                        } else {  
                            mText2 = s.toString().trim();  
                        }  
  
                        if (Integer.parseInt(mText2) > 255) {  
                            Toast.makeText(context, "Please input valid IP address",  
                                    Toast.LENGTH_LONG).show();  
                            return;  
                        }  
  
                        Editor editor = mPreferences.edit();  
                        editor.putInt("IP_SECOND", mText2.length());  
                        editor.commit();  
  
                        mThirdIP.setFocusable(true);  
                        mThirdIP.requestFocus();  
                    }  
                }  
  
                /** 
                 *  When user deletes the input, set focus to previous EditText
                 */  
                if (start == 0 && s.length() == 0) {  
                    mFirstIP.setFocusable(true);  
                    mFirstIP.requestFocus();  
                    mFirstIP.setSelection(mPreferences.getInt("IP_FIRST", 0));  
                }  
  
            }  
  
            @Override  
            public void beforeTextChanged(CharSequence s, int start, int count,  
                    int after) {  
  
            }  
  
            @Override  
            public void afterTextChanged(Editable s) {  
  
            }  
        });  
  
        mThirdIP.addTextChangedListener(new TextWatcher() {  
  
            @Override  
            public void onTextChanged(CharSequence s, int start, int before,  
                    int count) {  
                /** 
                 * Check if the IP address is valid.
                 * set focus to next EditText.
                 */  
                if (s != null && s.length() > 0) {  
                    if (s.length() > 2 || s.toString().trim().contains(".")) {  
                        if (s.toString().trim().contains(".")) {  
                            mText3 = s.toString().substring(0, s.length() - 1);  
                            mThirdIP.setText(mText3);  
                        } else {  
                            mText3 = s.toString().trim();  
                        }  
  
                        if (Integer.parseInt(mText3) > 255) {  
                            Toast.makeText(context, "Please input valid IP address",  
                                    Toast.LENGTH_LONG).show();  
                            return;  
                        }  
  
                        Editor editor = mPreferences.edit();  
                        editor.putInt("IP_THIRD", mText3.length());  
                        editor.commit();  
  
                        mFourthIP.setFocusable(true);  
                        mFourthIP.requestFocus();  
                    }  
                }  
  
                /** 
                 * When user deletes the input, set focus to previous EditText
                 */  
                if (start == 0 && s.length() == 0) {  
                    mSecondIP.setFocusable(true);  
                    mSecondIP.requestFocus();  
                    mSecondIP.setSelection(mPreferences.getInt("IP_SECOND", 0));  
                }  
            }  
  
            @Override  
            public void beforeTextChanged(CharSequence s, int start, int count,  
                    int after) {  
  
            }  
  
            @Override  
            public void afterTextChanged(Editable s) {  
  
            }  
        });  
  
        mFourthIP.addTextChangedListener(new TextWatcher() {  
  
            @Override  
            public void onTextChanged(CharSequence s, int start, int before,  
                    int count) {  
                /** 
                 * Check if the IP address is valid.
                 * set focus to next EditText.
                 */  
                if (s != null && s.length() > 0) {  
                    mText4 = s.toString().trim();  
  
                    if (Integer.parseInt(mText4) > 255) {  
                        Toast.makeText(context, "Please input valid IP address", Toast.LENGTH_LONG)  
                                .show();  
                        return;  
                    }  
  
                    Editor editor = mPreferences.edit();  
                    editor.putInt("IP_FOURTH", mText4.length());  
                    editor.commit();  
                }  
  
                /** 
                 * When user deletes the input, set focus to previous EditText
                 */  
                if (start == 0 && s.length() == 0) {  
                    mSecondIP.setFocusable(true);  
                    mSecondIP.requestFocus();  
                    mSecondIP.setSelection(mPreferences.getInt("IP_THIRD", 0));  
                }  
            }  
  
            @Override  
            public void beforeTextChanged(CharSequence s, int start, int count,  
                    int after) {  
  
            }  
  
            @Override  
            public void afterTextChanged(Editable s) {  
  
            }  
        });  
    }  
  
    public String getText(Context context) {  
        if (TextUtils.isEmpty(mText1) || TextUtils.isEmpty(mText2)  
                || TextUtils.isEmpty(mText3) || TextUtils.isEmpty(mText4)) {  
            Toast.makeText(context, "Please input valid IP address", Toast.LENGTH_LONG).show();  
        }  
        return mText1 + "." + mText2 + "." + mText3 + "." + mText4;  
    }  
} 

Thursday, 2 January 2014

Android Example: Calling Javascript from Android Java coding


In Android application, WebView is the component for display web pages. As Hybrid application are popular now, there are needs of calling javascript method from Android Java coding. We can do this by implement the addJavascriptInterface method in WebView.
The following example demonstarte this:
Step 1: Create a new Android project "JavascriptDemo" in Eclipse. A html web page is created in the assests directory.


Step 2: Modify activity_javascript_demo.xml layout document. Add a button in the WebView
<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="Hello World!!"  
        />  
    <WebView  
        android:id="@+id/webview"  
        android:layout_width="fill_parent"   
        android:layout_height="wrap_content"   
    />  
    <Button  
        android:id="@+id/button"  
        android:layout_width="fill_parent"  
        android:layout_height="wrap_content"  
        android:text="Change the webview content"  
    />  

</LinearLayout>  
Step 3: Create a demo.html file under assest directory.
 <html>  
     <script language="javascript"><!--  
    
  function fillContent(){  
      document.getElementById("content").innerHTML =   
    "This Content is showed by Android invoked Javascript function.";  
  }  
       
 // --></script>    
   <body>  
     <p><a onClick="window.demo.startMap()" href="">Start GoogleMap</a></p>  
     <p id="content"></p>  
     <p>EasyInfoGeek.com</p>  
     <p>Javscript Demo ---- Android and Javascript interaction</p>  
     
   </body>  
 </html>   
Step 4: Modify JavascriptDemo.java
 package com.easyinfogeek.javascriptdemo;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.widget.Button;

public class JavascriptDemo extends Activity {
  private WebView mWebView;  
     private Button mButton;  
     public void onCreate(Bundle savedInstanceState) {  
         super.onCreate(savedInstanceState);  
         setContentView(R.layout.activity_javascript_demo);  
         setupViews();  
     }  
     
     private void setupViews() {  
         mWebView = (WebView) findViewById(R.id.webview);  
         WebSettings mWebSettings = mWebView.getSettings();  
       
         mWebSettings.setJavaScriptEnabled(true);  
       
         mWebView.addJavascriptInterface(new Object() {  
       
             public void startMap() {  
                 Intent mIntent = new Intent();  
                 ComponentName component = new ComponentName(  
                         "com.google.android.apps.maps",  
                         "com.google.android.maps.MapsActivity");  
                 mIntent.setComponent(component);  
                 startActivity(mIntent);  
             }  
         }, "demo");  
       
         mWebView.loadUrl("file:///android_asset/demo.html");  
         mButton = (Button) findViewById(R.id.button);  
         mButton.setOnClickListener(new Button.OnClickListener() {  
             public void onClick(View v) {  
                 mWebView.loadUrl("javascript:fillContent()");  
             }  
         });  
     }  

}