# Introduction to Android programming



## JGuru (May 25, 2016)

*Introduction to Android programming*
Lets get started programming in Android!!. I give some android useful examples  with complete source code.  I'm not a android programmer. But learning android is easy for a Java programmer!!
Let's start !!
Threads Handler Demo

```
package com.commonsware.android.threads;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;a
import android.os.Message;
import android.widget.ProgressBar;
import java.util.concurrent.atomic.AtomicBoolean;

public class HandlerDemo extends Activity {
  ProgressBar bar;
  Handler handler=new Handler() {
    @Override
    public void handleMessage(Message msg) {
      bar.incrementProgressBy(5);
    }
  };
  AtomicBoolean isRunning=new AtomicBoolean(false);
  
  @Override
  public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    setContentView(R.layout.main);
    bar=(ProgressBar)findViewById(R.id.progress);
  }
  
  public void onStart() {
    super.onStart();
    bar.setProgress(0);
    
    Thread background=new Thread(new Runnable() {
      public void run() {
        try {
          for (int i=0;i<20 && isRunning.get();i++) {
            Thread.sleep(1000);
            handler.sendMessage(handler.obtainMessage());
          }
        }
        catch (Throwable t) {
          // just end the background thread
        }
      }
    });
    
    isRunning.set(true);
    background.start();
  }
  
  public void onStop() {
    super.onStop();
    isRunning.set(false);
  }
}


//res\layout\main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="*schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  >
  <ProgressBar android:id="@+id/progress"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />
</LinearLayout>



Using AsyncTask
/***
  Copyright (c) 2008-2009 CommonsWare, LLC
  
  Licensed under the Apache License, Version 2.0 (the "License"); you may
  not use this file except in compliance with the License. You may obtain
  a copy of the License at
    *www.apache.org/licenses/LICENSE-2.0
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

package com.commonsware.android.async;

import android.app.ListActivity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.widget.ArrayAdapter;
import android.widget.Toast;
import java.util.ArrayList;

public class AsyncDemo extends ListActivity {
  private static String[] items={"lorem", "ipsum", "dolor",
                                  "sit", "amet", "consectetuer",
                                  "adipiscing", "elit", "morbi",
                                  "vel", "ligula", "vitae",
                                  "arcu", "aliquet", "mollis",
                                  "etiam", "vel", "erat",
                                  "placerat", "ante",
                                  "porttitor", "sodales",
                                  "pellentesque", "augue",
                                  "purus"};
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    setListAdapter(new ArrayAdapter<String>(this,
                        android.R.layout.simple_list_item_1,
                        new ArrayList()));
    
    new AddStringTask().execute();
  }
  
  class AddStringTask extends AsyncTask<Void, String, Void> {
    @Override
    protected Void doInBackground(Void... unused) {
      for (String item : items) {
        publishProgress(item);
        SystemClock.sleep(200);
      }
      
      return(null);
    }
    
    @Override
    protected void onProgressUpdate(String... item) {
      ((ArrayAdapter)getListAdapter()).add(item[0]);
    }
    
    @Override
    protected void onPostExecute(Void unused) {
      Toast
        .makeText(AsyncDemo.this, "Done!", Toast.LENGTH_SHORT)
        .show();
    }
  }
}



//res\layout\main.xml
<?xml version="1.0" encoding="utf-8"?>
<ListView
  xmlns:android="*schemas.android.com/apk/res/android"
  android:id="@android:id/list"
  android:layout_width="fill_parent" 
  android:layout_height="fill_parent"
  android:drawSelectorOnTop="false"
/>
```
Use SQLiteDatabase

```
package app.Test;

import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.widget.TextView;

public class appTest extends Activity {
  private static String[] FROM = { "ID", "TIME", "TITLE", };
  private static String ORDER_BY = "TIME DESC";

  private EventsData events;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    events = new EventsData(this);
    try {
      addEvent("Hello, Android!");
      Cursor cursor = getEvents();
      showEvents(cursor);
    } finally {
      events.close();
    }
  }

  private void addEvent(String string) {
    SQLiteDatabase db = events.getWritableDatabase();
    ContentValues values = new ContentValues();
    values.put("titme", System.currentTimeMillis());
    values.put("title", string);
    db.insertOrThrow("event", null, values);
  }

  private Cursor getEvents() {
    SQLiteDatabase db = events.getReadableDatabase();
    Cursor cursor = db.query("event", FROM, null, null, null, null,ORDER_BY);
    startManagingCursor(cursor);
    return cursor;
  }

  private void showEvents(Cursor cursor) {
    StringBuilder builder = new StringBuilder("Saved events:\n");
    while (cursor.moveToNext()) {
      long id = cursor.getLong(0);
      long time = cursor.getLong(1);
      String title = cursor.getString(2);
      builder.append(id).append(": ");
      builder.append(time).append(": ");
      builder.append(title).append("\n");
    }
    // Display on the screen
    TextView text = (TextView) findViewById(R.id.empty);
    text.setText(builder);
  }

}

class EventsData extends SQLiteOpenHelper {
  private static final String DATABASE_NAME = "events.db";
  private static final int DATABASE_VERSION = 1;

  /** Create a helper object for the Events database */
  public EventsData(Context ctx) {
    super(ctx, DATABASE_NAME, null, DATABASE_VERSION);
  }

  @Override
  public void onCreate(SQLiteDatabase db) {
    db.execSQL("CREATE TABLE event (id INTEGER PRIMARY KEY AUTOINCREMENT, time INTEGER,title TEXT NOT NULL);");
  }

  @Override
  public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    db.execSQL("DROP TABLE IF EXISTS event");
    onCreate(db);
  }
}
//main.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout
   xmlns:android="*schemas.android.com/apk/res/android"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent">
   <!-- Note built-in ids for 'list' and 'empty' -->
   <ListView
      android:id="@+id/list"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"/>
   <TextView
      android:id="@+id/empty"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="@string/empty" />
</LinearLayout>
//strings.xml

<?xml version="1.0" encoding="utf-8"?>

<resources>
   <string name="app_name">Events</string>
   <string name="empty">No events!</string>
</resources>
```
 
Read the created file and display to the screen

```
package app.test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class Test extends Activity {

    private static final String FILENAME = "data.txt";
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TextView tv = new TextView(this);
        setContentView(tv);
        
        try {
            FileOutputStream mOutput = openFileOutput(FILENAME, Activity.MODE_PRIVATE);
            String data = "THIS DATA WRITTEN TO A FILE";
            mOutput.write(data.getBytes());
            mOutput.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        try {
            FileInputStream mInput = openFileInput(FILENAME);
            byte[] data = new byte[128];
            mInput.read(data);
            mInput.close();
            
            String display = new String(data);
            tv.setText(display.trim());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        deleteFile(FILENAME);    
    }
}
```
Frame based animation

```
package app.test;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.ComponentName;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;


 class FrameAnimationActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.frame_animations_layout);
        this.setupButton();
    }

    private void setupButton()
    {
       Button b = (Button)this.findViewById(R.id.startFAButtonId);
       b.setOnClickListener(
             new Button.OnClickListener(){
                public void onClick(View v)
                {
                   parentButtonClicked(v);
                }
             });
    }
    private void parentButtonClicked(View v)
    {
      animate();
    }    
    private void animate()
    {
       ImageView imgView = (ImageView)findViewById(R.id.imageView);
       imgView.setVisibility(ImageView.VISIBLE);
       imgView.setBackgroundResource(R.drawable.frame_animation);

       AnimationDrawable frameAnimation = 
         (AnimationDrawable) imgView.getBackground();

       if (frameAnimation.isRunning())
       {
           frameAnimation.stop();
       }
       else
       {
           frameAnimation.stop();
           frameAnimation.start();
       }
    }
}
public class Test extends Activity 
{
  Menu myMenu = null;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) 
    {
      //call the parent to attach any system level menus
      super.onCreateOptionsMenu(menu);
      
      this.myMenu = menu;

      MenuInflater mi = this.getMenuInflater();
      mi.inflate(R.menu.main_menu,menu);
      
      return true;
    }
    
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) 
    {
        handleMenus(item);
      return true;
    }
    private void handleMenus(MenuItem item)
    {
    this.appendMenuItemText(item);
    if (item.getItemId() == R.id.menu_clear)
    {
      this.emptyText();
    }
    else if (item.getItemId() == R.id.menu_list_animation)
    {
      Intent intent = new Intent(this, FrameAnimationActivity.class);
      startActivity(intent);
    }
    }
    
    private TextView getTextView()
    {
         TextView tv = 
           (TextView)this.findViewById(R.id.textViewId);
         return tv;
    }
    public void appendText(String text)
    {
         TextView tv = 
           (TextView)this.findViewById(R.id.textViewId);
         tv.setText(tv.getText() + text);
    }
    public void appendMenuItemText(MenuItem menuItem)
    {
      String title = menuItem.getTitle().toString();
         TextView tv = 
           (TextView)this.findViewById(R.id.textViewId);
         tv.setText(tv.getText() + "\n" + title + ":" + menuItem.getItemId());
    }
    private void emptyText()
    {
         TextView tv = 
           (TextView)this.findViewById(R.id.textViewId);
         tv.setText("");
    }    
}

//main.xml

<menu xmlns:android="*schemas.android.com/apk/res/android">
<!-- This group uses the default category. -->
<group android:id="@+id/menuGroup_Main">

    <item android:id="@+id/menu_list_animation"
        android:orderInCategory="1"
        android:title="Animate Frame" />
        
    <item android:id="@+id/menu_clear"
        android:orderInCategory="10"
        android:title="clear" />
</group>
</menu>
```
Download Manager Demo

```
package app.test;

import java.io.FileInputStream;

import android.app.Activity;
import android.app.DownloadManager;
import android.app.DownloadManager.Request;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.ImageView;

public class Test extends Activity {
  private static final String DL_ID = "downloadId";
  private SharedPreferences prefs;
  private DownloadManager dm;
  private ImageView imageView;
  
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        imageView = new ImageView(this);
        setContentView(imageView);
        prefs = PreferenceManager.getDefaultSharedPreferences(this);
        dm = (DownloadManager)getSystemService(DOWNLOAD_SERVICE);
    }
    @Override
    public void onResume() {
      super.onResume();
        if(!prefs.contains(DL_ID)) {
          Uri resource = Uri.parse("*asdf.com/big.jpg");
          DownloadManager.Request request = new DownloadManager.Request(resource);
          request.setAllowedNetworkTypes(Request.NETWORK_MOBILE | Request.NETWORK_WIFI);
          request.setAllowedOverRoaming(false);
          request.setTitle("Download Sample");
          long id = dm.enqueue(request);
          prefs.edit().putLong(DL_ID, id).commit();
        } else {
          queryDownloadStatus();
        }
        registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
    }
    @Override
    public void onPause() {
      super.onPause();
      unregisterReceiver(receiver);
    }
    private BroadcastReceiver receiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
      queryDownloadStatus();
    }
    };
    private void queryDownloadStatus() {
      DownloadManager.Query query = new DownloadManager.Query();
      query.setFilterById(prefs.getLong(DL_ID, 0));
      Cursor c = dm.query(query);
      if(c.moveToFirst()) {
        int status = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
        Log.d("DM Sample","Status Check: "+status);
        switch(status) {
        case DownloadManager.STATUS_PAUSED:
        case DownloadManager.STATUS_PENDING:
        case DownloadManager.STATUS_RUNNING:
          break;
        case DownloadManager.STATUS_SUCCESSFUL:
          try {
            ParcelFileDescriptor file = dm.openDownloadedFile(prefs.getLong(DL_ID, 0));
            FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(file);
            imageView.setImageBitmap(BitmapFactory.decodeStream(fis));
          } catch (Exception e) {
            e.printStackTrace();
          }
          break;
        case DownloadManager.STATUS_FAILED:
          dm.remove(prefs.getLong(DL_ID, 0));
          prefs.edit().clear().commit();
          break;
        }
      }
    }
}
```
Using MediaPlayer to play MP3 file

```
package app.Test;

import android.app.Activity;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.view.KeyEvent;

public class appTest extends Activity {
     private MediaPlayer up;

     
     @Override
     public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        up = MediaPlayer.create(this, R.raw.up);
     }
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
        MediaPlayer mp;
        switch (keyCode) {
        case KeyEvent.KEYCODE_DPAD_UP:
           mp = up;
           break;
        default:
           return super.onKeyDown(keyCode, event);
        }
        mp.seekTo(0); 
        mp.start();
        return true;
     }
}
```

Take a snapshot

```
package app.test;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.List;

import android.app.Activity;
import android.content.ContentValues;
import android.content.res.Configuration;
import android.hardware.Camera;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore.Images.Media;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Toast;

public class Test extends Activity implements OnClickListener,
    SurfaceHolder.Callback, Camera.PictureCallback {
  SurfaceView cameraView;
  SurfaceHolder surfaceHolder;
  Camera camera;
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    cameraView = (SurfaceView) this.findViewById(R.id.CameraView);
    surfaceHolder = cameraView.getHolder();
    surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    surfaceHolder.addCallback(this);
    cameraView.setFocusable(true);
    cameraView.setFocusableInTouchMode(true);
    cameraView.setClickable(true);
    cameraView.setOnClickListener(this);
  }
  public void onClick(View v) {
    camera.takePicture(null, null, this);
  }
  public void onPictureTaken(byte[] data, Camera camera) {
    Uri imageFileUri = getContentResolver().insert(
        Media.EXTERNAL_CONTENT_URI, new ContentValues());
    try {
      OutputStream imageFileOS = getContentResolver().openOutputStream(
          imageFileUri);
      imageFileOS.write(data);
      imageFileOS.flush();
      imageFileOS.close();
    } catch (Exception e) {
      Toast t = Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT);
      t.show();
    }
    camera.startPreview();
  }

  public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    camera.startPreview();
  }

  public void surfaceCreated(SurfaceHolder holder) {
    camera = Camera.open();
    try {
      camera.setPreviewDisplay(holder);
      Camera.Parameters parameters = camera.getParameters();
      if (this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
        parameters.set("orientation", "portrait");
        camera.setDisplayOrientation(90);
      }
      List<String> colorEffects = parameters.getSupportedColorEffects();
      Iterator<String> cei = colorEffects.iterator();
      while (cei.hasNext()) {
        String currentEffect = cei.next();
        if (currentEffect.equals(Camera.Parameters.EFFECT_SOLARIZE)) {
          parameters.setColorEffect(Camera.Parameters.EFFECT_SOLARIZE);
          break;
        }
      }
      camera.setParameters(parameters);
    } catch (IOException exception) {
      camera.release();
    }
  }
  public void surfaceDestroyed(SurfaceHolder holder) {
    camera.stopPreview();
    camera.release();
  }
}

//layout/main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="*schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<SurfaceView android:id="@+id/CameraView" 
             android:layout_width="fill_parent" 
             android:layout_height="fill_parent">
</SurfaceView>
</LinearLayout>
```
Get CPU information

```
package app.test;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
import android.telephony.TelephonyManager;
import android.util.DisplayMetrics;
import android.util.Log;

class CMDExecute {

  public synchronized String run(String[] cmd, String workdirectory)
      throws IOException {
    String result = "";

    try {
      ProcessBuilder builder = new ProcessBuilder(cmd);
      // set working directory
      if (workdirectory != null)
        builder.directory(new File(workdirectory));
      builder.redirectErrorStream(true);
      Process process = builder.start();
      InputStream in = process.getInputStream();
      byte[] re = new byte[1024];
      while (in.read(re) != -1) {
        System.out.println(new String(re));
        result = result + new String(re);
      }
      in.close();

    } catch (Exception ex) {
      ex.printStackTrace();
    }
    return result;
  }

}

public class Main {
  private static StringBuffer buffer;

  // cpu info
  public static String fetch_cpu_info() {
    String result = null;
    CMDExecute cmdexe = new CMDExecute();
    try {
      String[] args = { "/system/bin/cat", "/proc/cpuinfo" };
      result = cmdexe.run(args, "/system/bin/");
      Log.i("result", "result=" + result);
    } catch (IOException ex) {
      ex.printStackTrace();
    }
    return result;
  }

}
```

Using DoBackgroundTask

```
package app.test;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.Timer;
import java.util.TimerTask;

import android.app.Activity;
import android.app.IntentService;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

class MyIntentService extends IntentService {

  public MyIntentService() {
    super("MyIntentServiceName");
  }
  @Override
  protected void onHandleIntent(Intent intent) {
    try {
      int result = DownloadFile(new URL("*a.com/b.pdf"));
      Log.d("IntentService", "Downloaded " + result + " bytes");
      Intent broadcastIntent = new Intent();
      broadcastIntent.setAction("FILE_DOWNLOADED_ACTION");
      getBaseContext().sendBroadcast(broadcastIntent);

    } catch (MalformedURLException e) {
      e.printStackTrace();
    }
  }

  private int DownloadFile(URL url) {
    try {
      Thread.sleep(5000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    return 100;
  }
}

class MyService extends Service {
  int counter = 0;
  public URL[] urls;

  static final int UPDATE_INTERVAL = 1000;
  private Timer timer = new Timer();

  private final IBinder binder = new MyBinder();

  public class MyBinder extends Binder {
    MyService getService() {
      return MyService.this;
    }
  }

  @Override
  public IBinder onBind(Intent arg0) {
    return binder;
  }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
    Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();

    try {
      int result = DownloadFile(new URL("*amazon.com"));
      Toast.makeText(getBaseContext(), "Downloaded " + result + " bytes",
          Toast.LENGTH_LONG).show();
    } catch (MalformedURLException e) {
      e.printStackTrace();
    }

    try {
      new DoBackgroundTask().execute(new URL("*a.com/a.pdf"),
          new URL("*b.com/b.pdf"),
          new URL("*c.com/c.pdf"),
          new URL("*d.net/d.pdf"));

    } catch (MalformedURLException e) {
      e.printStackTrace();
    }
    doSomethingRepeatedly();

    Object[] objUrls = (Object[]) intent.getExtras().get("URLs");
    URL[] urls = new URL[objUrls.length];
    for (int i = 0; i < objUrls.length - 1; i++) {
      urls[i] = (URL) objUrls[i];
    }
    new DoBackgroundTask().execute(urls);

    return START_STICKY;
  }

  private void doSomethingRepeatedly() {
    timer.scheduleAtFixedRate(new TimerTask() {
      public void run() {
        Log.d("MyService", String.valueOf(++counter));
        try {
          Thread.sleep(4000);
          Log.d("MyService", counter + " Finished");

        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }, 0, UPDATE_INTERVAL);
  }

  @Override
  public void onDestroy() {
    super.onDestroy();
    if (timer != null) {
      timer.cancel();
    }
    Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show();
  }

  private int DownloadFile(URL url) {
    try {
      Thread.sleep(5000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    return 100;
  }

  private class DoBackgroundTask extends AsyncTask<URL, Integer, Long> {
    protected Long doInBackground(URL... urls) {
      int count = urls.length;
      long totalBytesDownloaded = 0;
      for (int i = 0; i < count; i++) {
        totalBytesDownloaded += DownloadFile(urls[i]);
        publishProgress((int) (((i + 1) / (float) count) * 100));
      }
      return totalBytesDownloaded;
    }

    protected void onProgressUpdate(Integer... progress) {
      Log.d("Downloading files", String.valueOf(progress[0])
          + "% downloaded");
      Toast.makeText(getBaseContext(),
          String.valueOf(progress[0]) + "% downloaded",
          Toast.LENGTH_LONG).show();
    }

    protected void onPostExecute(Long result) {
      Toast.makeText(getBaseContext(), "Downloaded " + result + " bytes",
          Toast.LENGTH_LONG).show();
      stopSelf();
    }
  }
}

public class Test extends Activity {
  IntentFilter intentFilter;
  private MyService serviceBinder;
  Intent i;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    intentFilter = new IntentFilter();
    intentFilter.addAction("FILE_DOWNLOADED_ACTION");
    registerReceiver(intentReceiver, intentFilter);

    Button btnStart = (Button) findViewById(R.id.btnStartService);
    btnStart.setOnClickListener(new View.OnClickListener() {
      public void onClick(View v) {

        Intent intent = new Intent(getBaseContext(), MyService.class);
        try {
          URL[] urls = new URL[] { new URL("*a.com/a.pdf"),
              new URL("*b.com/b.pdf"),
              new URL("*c.com/c.pdf"),
              new URL("*d.com/d.pdf") };
          intent.putExtra("URLs", urls);

        } catch (MalformedURLException e) {
          e.printStackTrace();
        }
        startService(intent);

        startService(new Intent(getBaseContext(), MyService.class));
        startService(new Intent("app.test.MyService"));
        startService(new Intent(getBaseContext(), MyIntentService.class));

        i = new Intent(Test.this, MyService.class);
        bindService(i, connection, Context.BIND_AUTO_CREATE);
      }
    });

    Button btnStop = (Button) findViewById(R.id.btnStopService);
    btnStop.setOnClickListener(new View.OnClickListener() {
      public void onClick(View v) {
        stopService(new Intent(getBaseContext(), MyService.class));
      }
    });
  }

  private ServiceConnection connection = new ServiceConnection() {
    public void onServiceConnected(ComponentName className, IBinder service) {
      serviceBinder = ((MyService.MyBinder) service).getService();
      try {
        URL[] urls = new URL[] { new URL("*a.com/a.pdf"),
            new URL("*b.com/b.pdf"),
            new URL("*c.com/c.pdf"),
            new URL("*d.net/d.pdf") };
        serviceBinder.urls = urls;
      } catch (MalformedURLException e) {
        e.printStackTrace();
      }
      startService(i);
    }

    public void onServiceDisconnected(ComponentName className) {
      serviceBinder = null;
    }
  };
  private BroadcastReceiver intentReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
      Toast.makeText(getBaseContext(), "File downloaded!",
          Toast.LENGTH_LONG).show();
    }
  };
}

//main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="*schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<Button android:id="@+id/btnStartService"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content"
    android:text="Start Service" />
        
<Button android:id="@+id/btnStopService"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content"
    android:text="Stop Service" />
        
</LinearLayout>
```
Get memory information

```
package app.test;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
import android.telephony.TelephonyManager;
import android.util.DisplayMetrics;
import android.util.Log;

class CMDExecute {

  public synchronized String run(String[] cmd, String workdirectory)
      throws IOException {
    String result = "";

    try {
      ProcessBuilder builder = new ProcessBuilder(cmd);
      // set working directory
      if (workdirectory != null)
        builder.directory(new File(workdirectory));
      builder.redirectErrorStream(true);
      Process process = builder.start();
      InputStream in = process.getInputStream();
      byte[] re = new byte[1024];
      while (in.read(re) != -1) {
        System.out.println(new String(re));
        result = result + new String(re);
      }
      in.close();

    } catch (Exception ex) {
      ex.printStackTrace();
    }
    return result;
  }

}

public class Main {
  private static StringBuffer buffer;

  public static String getMemoryInfo(Context context) {
    StringBuffer memoryInfo = new StringBuffer();
    final ActivityManager activityManager = (ActivityManager) context
        .getSystemService(Context.ACTIVITY_SERVICE);

    ActivityManager.MemoryInfo outInfo = new ActivityManager.MemoryInfo();
    activityManager.getMemoryInfo(outInfo);
    memoryInfo.append("\nTotal Available Memory :")
        .append(outInfo.availMem >> 10).append("k");
    memoryInfo.append("\nTotal Available Memory :")
        .append(outInfo.availMem >> 20).append("M");
    memoryInfo.append("\nIn low memory situation:").append(
        outInfo.lowMemory);

    String result = null;
    CMDExecute cmdexe = new CMDExecute();
    try {
      String[] args = { "/system/bin/cat", "/proc/meminfo" };
      result = cmdexe.run(args, "/system/bin/");
    } catch (IOException ex) {
      Log.i("fetch_process_info", "ex=" + ex.toString());
    }

    return memoryInfo.toString() + "\n\n" + result;
  }
}
```
Voice recognition demo

```
package app.test;

import java.util.ArrayList;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.speech.RecognizerIntent;
import android.widget.TextView;
import android.widget.Toast;

public class Test extends Activity {
    private static final int REQUEST_RECOGNIZE = 100;
    TextView tv;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        tv = new TextView(this);
        setContentView(tv);
        
        Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
        intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
        intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "Tell Me Your Name");
        try {
            startActivityForResult(intent, REQUEST_RECOGNIZE);
        } catch (ActivityNotFoundException e) {
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle("Not Available");
            builder.setMessage("No recognition software installed.Download one?");
            builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    Intent marketIntent = new Intent(Intent.ACTION_VIEW);
                    marketIntent.setData(Uri.parse("market://details?id=com.google.android.voicesearch"));
                }
            });
            builder.setNegativeButton("No", null);
            builder.create().show();
        }
    }
   
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if(requestCode == REQUEST_RECOGNIZE && resultCode == Activity.RESULT_OK) {
            ArrayList<String> matches = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
            StringBuilder sb = new StringBuilder();
            for(String piece : matches) {
                sb.append(piece);
                sb.append('\n');
            }
            tv.setText(sb.toString());
        } else {
            Toast.makeText(this, "Operation Canceled", Toast.LENGTH_SHORT).show();
        }
    }
}
```
Text to speech demo

```
package app.test;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnInitListener;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class Test extends Activity implements OnInitListener {
  private EditText words = null;
  private Button speakBtn = null;
    private static final int REQ_TTS_STATUS_CHECK = 0;
  private static final String TAG = "TTS Demo";
    private TextToSpeech mTts;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        words = (EditText)findViewById(R.id.wordsToSpeak);
        speakBtn = (Button)findViewById(R.id.speak);

        Intent checkIntent = new Intent();
        checkIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
        startActivityForResult(checkIntent, REQ_TTS_STATUS_CHECK);
    }
    
    public void doSpeak(View view) {
    mTts.speak(words.getText().toString(), TextToSpeech.QUEUE_ADD, null);
  };
  
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQ_TTS_STATUS_CHECK) {
            switch (resultCode) {
            case TextToSpeech.Engine.CHECK_VOICE_DATA_PASS:
                mTts = new TextToSpeech(this, this);
                break;
            case TextToSpeech.Engine.CHECK_VOICE_DATA_BAD_DATA:
            case TextToSpeech.Engine.CHECK_VOICE_DATA_MISSING_DATA:
            case TextToSpeech.Engine.CHECK_VOICE_DATA_MISSING_VOLUME:
                Intent installIntent = new Intent();
                installIntent.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
                startActivity(installIntent);
                break;
            case TextToSpeech.Engine.CHECK_VOICE_DATA_FAIL:
            default:
                Log.e(TAG, "Got a failure.");
            }
        }
    }
  public void onInit(int status) {
    if( status == TextToSpeech.SUCCESS) {
      speakBtn.setEnabled(true);
    }
  }
  @Override
  public void onPause(){
    super.onPause();
    if( mTts != null)
      mTts.stop();
  }
  @Override
    public void onDestroy(){
        super.onDestroy();
        mTts.shutdown();
    }
}

//main.xml

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

  <EditText android:id="@+id/wordsToSpeak"
    android:hint="Type words to speak here"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"/>

  <Button android:id="@+id/speak"
    android:text="Speak"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:onClick="doSpeak"
  android:enabled="false" />

</LinearLayout>
```
Phone Dialer

```
package com.commonsware.android.dialer;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class DialerDemo extends Activity {
  @Override
  public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    setContentView(R.layout.main);
  
    final EditText number=(EditText)findViewById(R.id.number);
    Button dial=(Button)findViewById(R.id.dial);
  
    dial.setOnClickListener(new Button.OnClickListener() {
      public void onClick(View v) {
        String toDial="tel:"+number.getText().toString();
        
        startActivity(new Intent(Intent.ACTION_DIAL,
                                  Uri.parse(toDial)));
      }
    });
  }
}

//res\layout\main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="*schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
  <LinearLayout 
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    >
    <TextView  
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:text="Number to dial:"
      />
    <EditText android:id="@+id/number"
      android:layout_width="fill_parent" 
      android:layout_height="wrap_content"
      android:cursorVisible="true"
      android:editable="true"
      android:singleLine="true"
    />
  </LinearLayout>
  <Button android:id="@+id/dial"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:text="Dial It!"
  />
</LinearLayout>
```
Using Google Map

```
//AndroidManifest.xml


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="*schemas.android.com/apk/res/android"
      package="com.examples.mapper"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="3" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>
    <uses-permission android:name="android.permission.INTERNET"></uses-permission>

    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".MyActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <uses-library android:name="com.google.android.maps"></uses-library>

    </application>
</manifest>

//main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="*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:gravity="center_horizontal"
    android:text="Map Of Your Location"
  />
  <com.google.android.maps.MapView
    android:id="@+id/map"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:enabled="true"
    android:clickable="true"
    android:apiKey="YOUR_API_KEY_HERE"
  />
</LinearLayout>

package app.test;

import android.os.Bundle;

import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;

public class MyActivity extends MapActivity {

    MapView map;
    MapController controller;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        map = (MapView)findViewById(R.id.map);
        controller = map.getController();
        
        LocationManager manager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
        Location location = manager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
        int lat, lng;
        if(location != null) {
            //Convert to microdegrees
            lat = (int)(location.getLatitude() * 1000000);
            lng = (int)(location.getLongitude() * 1000000);
        } else {
            //Default to Google HQ
            lat = 37427222;
            lng = -122099167;
        }
        GeoPoint mapCenter = new GeoPoint(lat,lng);
        controller.setCenter(mapCenter);
        controller.setZoom(15);
    }
    
    //Required abstract method, return false
    @Override
    protected boolean isRouteDisplayed() {
        return false;
    }
}
```
Clipboard Sample

```
package com.example.android.apis.content;

import com.example.android.apis.R;

import android.app.Activity;
import android.content.ClipboardManager;
import android.content.ClipData;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.AdapterView.OnItemSelectedListener;

public class ClipboardSample extends Activity {
    ClipboardManager mClipboard;

    Spinner mSpinner;
    TextView mMimeTypes;
    EditText mEditText;

    CharSequence mStyledText;
    String mPlainText;

    ClipboardManager.OnPrimaryClipChangedListener mPrimaryChangeListener
            = new ClipboardManager.OnPrimaryClipChangedListener() {
        public void onPrimaryClipChanged() {
            updateClipData();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mClipboard = (ClipboardManager)getSystemService(CLIPBOARD_SERVICE);

        // See res/any/layout/resources.xml for this view layout definition.
        setContentView(R.layout.clipboard);

        TextView tv;

        mStyledText = getText(R.string.styled_text);
        tv = (TextView)findViewById(R.id.styled_text);
        tv.setText(mStyledText);

        mPlainText = mStyledText.toString();
        tv = (TextView)findViewById(R.id.plain_text);
        tv.setText(mPlainText);

        mSpinner = (Spinner) findViewById(R.id.clip_type);
        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
                this, R.array.clip_data_types, android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        mSpinner.setAdapter(adapter);
        mSpinner.setOnItemSelectedListener(
                new OnItemSelectedListener() {
                    public void onItemSelected(
                            AdapterView<?> parent, View view, int position, long id) {
                    }
                    public void onNothingSelected(AdapterView<?> parent) {
                    }
                });

        mMimeTypes = (TextView)findViewById(R.id.clip_mime_types);
        mEditText = (EditText)findViewById(R.id.clip_text);

        mClipboard.addPrimaryClipChangedListener(mPrimaryChangeListener);
        updateClipData();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mClipboard.removePrimaryClipChangedListener(mPrimaryChangeListener);
    }

    public void pasteStyledText(View button) {
        mClipboard.setPrimaryClip(ClipData.newPlainText("Styled Text", mStyledText));
    }

    public void pastePlainText(View button) {
        mClipboard.setPrimaryClip(ClipData.newPlainText("Styled Text", mPlainText));
    }

    public void pasteIntent(View button) {
        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("*www.android.com/"));
        mClipboard.setPrimaryClip(ClipData.newIntent("VIEW intent", intent));
    }

    public void pasteUri(View button) {
        mClipboard.setPrimaryClip(ClipData.newRawUri("URI", Uri.parse("*www.android.com/")));
    }

    void updateClipData() {
        ClipData clip = mClipboard.getPrimaryClip();
        String[] mimeTypes = clip != null ? clip.getDescription().filterMimeTypes("*/*") : null;
        mMimeTypes.setText("");
        if (mimeTypes != null) {
            for (int i=0; i<mimeTypes.length; i++) {
                mMimeTypes.append(mimeTypes[i]);
                mMimeTypes.append("\n");
            }
        }
        if (clip == null) {
            mSpinner.setSelection(0);
            mEditText.setText("");
        } else if (clip.getItemAt(0).getText() != null) {
            mSpinner.setSelection(1);
            mEditText.setText(clip.getItemAt(0).getText());
        } else if (clip.getItemAt(0).getIntent() != null) {
            mSpinner.setSelection(2);
            mEditText.setText(clip.getItemAt(0).getIntent().toUri(0));
        } else if (clip.getItemAt(0).getUri() != null) {
            mSpinner.setSelection(3);
            mEditText.setText(clip.getItemAt(0).getUri().toString());
        } else {
            mSpinner.setSelection(0);
            mEditText.setText("Clip containing no data");
        }
    }
}
//layout/clipboard.xml


<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2007 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          *www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<!--
    Demonstrates clipboard.

    See corresponding Java code:
    com.example.android.apis.content.ClipboardSample
-->

<LinearLayout xmlns:android="*schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout xmlns:android="*schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button android:id="@+id/copy_styled_text"
            android:layout_width="wrap_content" android:layout_height="wrap_content"
            android:onClick="pasteStyledText"
            android:text="@string/copy_text" />

        <TextView
            android:id="@+id/styled_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:textStyle="normal" />

    </LinearLayout>

    <LinearLayout xmlns:android="*schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button android:id="@+id/copy_plain_text"
            android:layout_width="wrap_content" android:layout_height="wrap_content"
            android:onClick="pastePlainText"
            android:text="@string/copy_text" />

        <TextView
            android:id="@+id/plain_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:textStyle="normal" />

    </LinearLayout>

    <LinearLayout xmlns:android="*schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button android:id="@+id/copy_intent"
            android:layout_width="wrap_content" android:layout_height="wrap_content"
            android:onClick="pasteIntent"
            android:text="@string/copy_intent" />

        <Button android:id="@+id/copy_uri"
            android:layout_width="wrap_content" android:layout_height="wrap_content"
            android:onClick="pasteUri"
            android:text="@string/copy_uri" />

    </LinearLayout>

    <Spinner android:id="@+id/clip_type"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:drawSelectorOnTop="true"
        android:prompt="@string/clip_type_prompt"
    />

    <TextView
        android:id="@+id/clip_mime_types"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="0"
        android:textStyle="normal"
        />

    <EditText
        android:id="@+id/clip_text"
        android:layout_width="match_parent"
        android:layout_height="0px"
        android:layout_weight="1"
        android:textStyle="normal"
        />

</LinearLayout>
```
Backup restore

```
package com.example.android.backuprestore;

import android.app.Activity;
import android.app.backup.BackupManager;
import android.app.backup.RestoreObserver;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.RadioGroup;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

/**
 * This example is intended to demonstrate a few approaches that an Android
 * application developer can take when implementing a
 * {@link android.app.backup.BackupAgent BackupAgent}.  This feature, added
 * to the Android platform with API version 8, allows the application to
 * back up its data to a device-provided storage location, transparently to
 * the user.  If the application is uninstalled and then reinstalled, or if
 * the user starts using a new Android device, the backed-up information
 * can be provided automatically when the application is reinstalled.
 *
 * <p>Participating in the backup/restore mechanism is simple.  The application
 * provides a class that extends {@link android.app.backup.BackupAgent}, and
 * overrides the two core callback methods
 * {@link android.app.backup.BackupAgent#onBackup(android.os.ParcelFileDescriptor, android.app.backup.BackupDataOutput, android.os.ParcelFileDescriptor) onBackup()}
 * and
 * {@link android.app.backup.BackupAgent#onRestore(android.app.backup.BackupDataInput, int, android.os.ParcelFileDescriptor) onRestore()}.
 * It also publishes the agent class to the operating system by naming the class
 * with the <code>android:backupAgent</code> attribute of the
 * <code>&lt;application&gt;</code> tag in the application's manifest.
 * When a backup or restore operation is performed, the application's agent class
 * is instantiated within the application's execution context and the corresponding
 * method invoked.  Please see the documentation on the
 * {@link android.app.backup.BackupAgent BackupAgent} class for details about the
 * data interchange between the agent and the backup mechanism.
 *
 * <p>This example application maintains a few pieces of simple data, and provides
 * three different sample agent implementations, each illustrating an alternative
 * approach.  The three sample agent classes are:
 *
 * <p><ol type="1">
 * <li>{@link ExampleAgent} - this agent backs up the application's data in a single
 *     record.  It illustrates the direct "by hand" processes of saving backup state for
 *     future reference, sending data to the backup transport, and reading it from a restore
 *     dataset.</li>
 * <li>{@link FileHelperExampleAgent} - this agent takes advantage of the suite of
 *     helper classes provided along with the core BackupAgent API.  By extending
 *     {@link android.app.backup.BackupHelperAgent} and using the targeted
 *     {link android.app.backup.FileBackupHelper FileBackupHelper} class, it achieves
 *     the same result as {@link ExampleAgent} - backing up the application's saved
 *     data file in a single chunk, and restoring it upon request -- in only a few lines
 *     of code.</li>
 * <li>{@link MultiRecordExampleAgent} - this agent stores each separate bit of data
 *     managed by the UI in separate records within the backup dataset.  It illustrates
 *     how an application's backup agent can do selective updates of only what information
 *     has changed since the last backup.</li></ol>
 *
 * <p>You can build the application to use any of these agent implementations simply by
 * changing the class name supplied in the <code>android:backupAgent</code> manifest
 * attribute to indicate the agent you wish to use.  <strong>Note:</strong> the backed-up
 * data and backup-state tracking of these agents are not compatible!  If you change which
 * agent the application uses, you should also wipe the backup state associated with
 * the application on your handset.  The 'bmgr' shell application on the device can
 * do this; simply run the following command from your desktop computer while attached
 * to the device via adb:
 *
 * <p><code>adb shell bmgr wipe com.example.android.backuprestore</code>
 *
 * <p>You can then install the new version of the application, and its next backup pass
 * will start over from scratch with the new agent.
 */
public class BackupRestoreActivity extends Activity {
    static final String TAG = "BRActivity";

    /**
     * We serialize access to our persistent data through a global static
     * object.  This ensures that in the unlikely event of the our backup/restore
     * agent running to perform a backup while our UI is updating the file, the
     * agent will not accidentally read partially-written data.
     *
     * <p>Curious but true: a zero-length array is slightly lighter-weight than
     * merely allocating an Object, and can still be synchronized on.
     */
    static final Object[] sDataLock = new Object[0];

    /** Also supply a global standard file name for everyone to use */
    static final String DATA_FILE_NAME = "saved_data";

    /** The various bits of UI that the user can manipulate */
    RadioGroup mFillingGroup;
    CheckBox mAddMayoCheckbox;
    CheckBox mAddTomatoCheckbox;

    /** Cache a reference to our persistent data file */
    File mDataFile;

    /** Also cache a reference to the Backup Manager */
    BackupManager mBackupManager;

    /** Set up the activity and populate its UI from the persistent data. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        /** Establish the activity's UI */
        setContentView(R.layout.backup_restore);

        /** Once the UI has been inflated, cache the controls for later */
        mFillingGroup = (RadioGroup) findViewById(R.id.filling_group);
        mAddMayoCheckbox = (CheckBox) findViewById(R.id.mayo);
        mAddTomatoCheckbox = (CheckBox) findViewById(R.id.tomato);

        /** Set up our file bookkeeping */
        mDataFile = new File(getFilesDir(), BackupRestoreActivity.DATA_FILE_NAME);

        /** It is handy to keep a BackupManager cached */
        mBackupManager = new BackupManager(this);

        /**
         * Finally, build the UI from the persistent store
         */
        populateUI();
    }

    /**
     * Configure the UI based on our persistent data, creating the
     * data file and establishing defaults if necessary.
     */
    void populateUI() {
        RandomAccessFile file;

        // Default values in case there's no data file yet
        int whichFilling = R.id.pastrami;
        boolean addMayo = false;
        boolean addTomato = false;

        /** Hold the data-access lock around access to the file */
        synchronized (BackupRestoreActivity.sDataLock) {
            boolean exists = mDataFile.exists();
            try {
                file = new RandomAccessFile(mDataFile, "rw");
                if (exists) {
                    Log.v(TAG, "datafile exists");
                    whichFilling = file.readInt();
                    addMayo = file.readBoolean();
                    addTomato = file.readBoolean();
                    Log.v(TAG, "  mayo=" + addMayo
                            + " tomato=" + addTomato
                            + " filling=" + whichFilling);
                } else {
                    // The default values were configured above: write them
                    // to the newly-created file.
                    Log.v(TAG, "creating default datafile");
                    writeDataToFileLocked(file,
                            addMayo, addTomato, whichFilling);

                    // We also need to perform an initial backup; ask for one
                    mBackupManager.dataChanged();
                }
            } catch (IOException ioe) {
                
            }
        }

        /** Now that we've processed the file, build the UI outside the lock */
        mFillingGroup.check(whichFilling);
        mAddMayoCheckbox.setChecked(addMayo);
        mAddTomatoCheckbox.setChecked(addTomato);

        /**
         * We also want to record the new state when the user makes changes,
         * so install simple observers that do this
         */
        mFillingGroup.setOnCheckedChangeListener(
                new RadioGroup.OnCheckedChangeListener() {
                    public void onCheckedChanged(RadioGroup group,
                            int checkedId) {
                        // As with the checkbox listeners, rewrite the
                        // entire state file
                        Log.v(TAG, "New radio item selected: " + checkedId);
                        recordNewUIState();
                    }
                });

        CompoundButton.OnCheckedChangeListener checkListener
                = new CompoundButton.OnCheckedChangeListener() {
            public void onCheckedChanged(CompoundButton buttonView,
                    boolean isChecked) {
                // Whichever one is altered, we rewrite the entire UI state
                Log.v(TAG, "Checkbox toggled: " + buttonView);
                recordNewUIState();
            }
        };
        mAddMayoCheckbox.setOnCheckedChangeListener(checkListener);
        mAddTomatoCheckbox.setOnCheckedChangeListener(checkListener);
    }

    /**
     * Handy helper routine to write the UI data to a file.
     */
    void writeDataToFileLocked(RandomAccessFile file,
            boolean addMayo, boolean addTomato, int whichFilling)
        throws IOException {
            file.setLength(0L);
            file.writeInt(whichFilling);
            file.writeBoolean(addMayo);
            file.writeBoolean(addTomato);
            Log.v(TAG, "NEW STATE: mayo=" + addMayo
                    + " tomato=" + addTomato
                    + " filling=" + whichFilling);
    }

    /**
     * Another helper; this one reads the current UI state and writes that
     * to the persistent store, then tells the backup manager that we need
     * a backup.
     */
    void recordNewUIState() {
        boolean addMayo = mAddMayoCheckbox.isChecked();
        boolean addTomato = mAddTomatoCheckbox.isChecked();
        int whichFilling = mFillingGroup.getCheckedRadioButtonId();
        try {
            synchronized (BackupRestoreActivity.sDataLock) {
                RandomAccessFile file = new RandomAccessFile(mDataFile, "rw");
                writeDataToFileLocked(file, addMayo, addTomato, whichFilling);
            }
        } catch (IOException e) {
            Log.e(TAG, "Unable to record new UI state");
        }

        mBackupManager.dataChanged();
    }

    /**
     * Click handler, designated in the layout, that runs a restore of the app's
     * most recent data when the button is pressed.
     */
    public void onRestoreButtonClick(View v) {
        Log.v(TAG, "Requesting restore of our most recent data");
        mBackupManager.requestRestore(
                new RestoreObserver() {
                    public void restoreFinished(int error) {
                        /** Done with the restore!  Now draw the new state of our data */
                        Log.v(TAG, "Restore finished, error = " + error);
                        populateUI();
                    }
                }
        );
    }
}



//src\com\example\android\backuprestore\ExampleAgent.java
/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      *www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.android.backuprestore;

import android.app.backup.BackupAgent;
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
import android.os.ParcelFileDescriptor;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;

/**
 * This is the backup/restore agent class for the BackupRestore sample
 * application.  This particular agent illustrates using the backup and
 * restore APIs directly, without taking advantage of any helper classes.
 */
public class ExampleAgent extends BackupAgent {
    /**
     * We put a simple version number into the state files so that we can
     * tell properly how to read "old" versions if at some point we want
     * to change what data we back up and how we store the state blob.
     */
    static final int AGENT_VERSION = 1;

    /**
     * Pick an arbitrary string to use as the "key" under which the
     * data is backed up.  This key identifies different data records
     * within this one application's data set.  Since we only maintain
     * one piece of data we don't need to distinguish, so we just pick
     * some arbitrary tag to use. 
     */
    static final String APP_DATA_KEY = "alldata";

    /** The app's current data, read from the live disk file */
    boolean mAddMayo;
    boolean mAddTomato;
    int mFilling;

    /** The location of the application's persistent data file */
    File mDataFile;

    /** For convenience, we set up the File object for the app's data on creation */
    @Override
    public void onCreate() {
        mDataFile = new File(getFilesDir(), BackupRestoreActivity.DATA_FILE_NAME);
    }

    /**
     * The set of data backed up by this application is very small: just
     * two booleans and an integer.  With such a simple dataset, it's
     * easiest to simply store a copy of the backed-up data as the state
     * blob describing the last dataset backed up.  The state file
     * contents can be anything; it is private to the agent class, and
     * is never stored off-device.
     *
     * <p>One thing that an application may wish to do is tag the state
     * blob contents with a version number.  This is so that if the
     * application is upgraded, the next time it attempts to do a backup,
     * it can detect that the last backup operation was performed by an
     * older version of the agent, and might therefore require different
     * handling.
     */
    @Override
    public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
            ParcelFileDescriptor newState) throws IOException {
        // First, get the current data from the application's file.  This
        // may throw an IOException, but in that case something has gone
        // badly wrong with the app's data on disk, and we do not want
        // to back up garbage data.  If we just let the exception go, the
        // Backup Manager will handle it and simply skip the current
        // backup operation.
        synchronized (BackupRestoreActivity.sDataLock) {
            RandomAccessFile file = new RandomAccessFile(mDataFile, "r");
            mFilling = file.readInt();
            mAddMayo = file.readBoolean();
            mAddTomato = file.readBoolean();
        }

        // If the new state file descriptor is null, this is the first time
        // a backup is being performed, so we know we have to write the
        // data.  If there <em>is</em> a previous state blob, we want to
        // double check whether the current data is actually different from
        // our last backup, so that we can avoid transmitting redundant
        // data to the storage backend.
        boolean doBackup = (oldState == null);
        if (!doBackup) {
            doBackup = compareStateFile(oldState);
        }

        // If we decided that we do in fact need to write our dataset, go
        // ahead and do that.  The way this agent backs up the data is to
        // flatten it into a single buffer, then write that to the backup
        // transport under the single key string.
        if (doBackup) {
            ByteArrayOutputStream bufStream = new ByteArrayOutputStream();

            // We use a DataOutputStream to write structured data into
            // the buffering stream
            DataOutputStream outWriter = new DataOutputStream(bufStream);
            outWriter.writeInt(mFilling);
            outWriter.writeBoolean(mAddMayo);
            outWriter.writeBoolean(mAddTomato);

            // Okay, we've flattened the data for transmission.  Pull it
            // out of the buffering stream object and send it off.
            byte[] buffer = bufStream.toByteArray();
            int len = buffer.length;
            data.writeEntityHeader(APP_DATA_KEY, len);
            data.writeEntityData(buffer, len);
        }

        // Finally, in all cases, we need to write the new state blob
        writeStateFile(newState);
    }

    /**
     * Helper routine - read a previous state file and decide whether to
     * perform a backup based on its contents.
     *
     * @return <code>true</code> if the application's data has changed since
     *   the last backup operation; <code>false</code> otherwise.
     */
    boolean compareStateFile(ParcelFileDescriptor oldState) {
        FileInputStream instream = new FileInputStream(oldState.getFileDescriptor());
        DataInputStream in = new DataInputStream(instream);

        try {
            int stateVersion = in.readInt();
            if (stateVersion > AGENT_VERSION) {
                // Whoops; the last version of the app that backed up
                // data on this device was <em>newer</em> than the current
                // version -- the user has downgraded.  That's problematic.
                // In this implementation, we recover by simply rewriting
                // the backup.
                return true;
            }

            // The state data we store is just a mirror of the app's data;
            // read it from the state file then return 'true' if any of
            // it differs from the current data.
            int lastFilling = in.readInt();
            boolean lastMayo = in.readBoolean();
            boolean lastTomato = in.readBoolean();

            return (lastFilling != mFilling)
                    || (lastTomato != mAddTomato)
                    || (lastMayo != mAddMayo);
        } catch (IOException e) {
            // If something went wrong reading the state file, be safe
            // and back up the data again.
            return true;
        }
    }

    /**
     * Write out the new state file:  the version number, followed by the
     * three bits of data as we sent them off to the backup transport.
     */
    void writeStateFile(ParcelFileDescriptor stateFile) throws IOException {
        FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor());
        DataOutputStream out = new DataOutputStream(outstream);

        out.writeInt(AGENT_VERSION);
        out.writeInt(mFilling);
        out.writeBoolean(mAddMayo);
        out.writeBoolean(mAddTomato);
    }

    /**
     * This application does not do any "live" restores of its own data,
     * so the only time a restore will happen is when the application is
     * installed.  This means that the activity itself is not going to
     * be running while we change its data out from under it.  That, in
     * turn, means that there is no need to send out any sort of notification
     * of the new data:  we only need to read the data from the stream
     * provided here, build the application's new data file, and then
     * write our new backup state blob that will be consulted at the next
     * backup operation.
     * 
     * <p>We don't bother checking the versionCode of the app who originated
     * the data because we have never revised the backup data format.  If
     * we had, the 'appVersionCode' parameter would tell us how we should
     * interpret the data we're about to read.
     */
    @Override
    public void onRestore(BackupDataInput data, int appVersionCode,
            ParcelFileDescriptor newState) throws IOException {
        // We should only see one entity in the data stream, but the safest
        // way to consume it is using a while() loop
        while (data.readNextHeader()) {
            String key = data.getKey();
            int dataSize = data.getDataSize();

            if (APP_DATA_KEY.equals(key)) {
                // It's our saved data, a flattened chunk of data all in
                // one buffer.  Use some handy structured I/O classes to
                // extract it.
                byte[] dataBuf = new byte[dataSize];
                data.readEntityData(dataBuf, 0, dataSize);
                ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf);
                DataInputStream in = new DataInputStream(baStream);

                mFilling = in.readInt();
                mAddMayo = in.readBoolean();
                mAddTomato = in.readBoolean();

                // Now we are ready to construct the app's data file based
                // on the data we are restoring from.
                synchronized (BackupRestoreActivity.sDataLock) {
                    RandomAccessFile file = new RandomAccessFile(mDataFile, "rw");
                    file.setLength(0L);
                    file.writeInt(mFilling);
                    file.writeBoolean(mAddMayo);
                    file.writeBoolean(mAddTomato);
                }
            } else {
                // Curious!  This entity is data under a key we do not
                // understand how to process.  Just skip it.
                data.skipEntityData();
            }
        }

        // The last thing to do is write the state blob that describes the
        // app's data as restored from backup.
        writeStateFile(newState);
    }
}



//src\com\example\android\backuprestore\FileHelperExampleAgent.java
/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      *www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.android.backuprestore;

import java.io.IOException;

import android.app.backup.BackupAgentHelper;
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
import android.app.backup.FileBackupHelper;
import android.os.ParcelFileDescriptor;

/**
 * This agent backs up the application's data using the BackupAgentHelper
 * infrastructure.  In this application's case, the backup data is merely
 * a duplicate of the stored data file; that makes it a perfect candidate
 * for backing up using the {@link android.app.backup.FileBackupHelper} class
 * provided by the Android operating system.
 *
 * <p>"Backup helpers" are a general mechanism that an agent implementation
 * uses by extending {@link BackupAgentHelper} rather than the basic
 * {@link BackupAgent} class.
 *
 * <p>By itself, the FileBackupHelper is properly handling the backup and
 * restore of the datafile that we've configured it with, but it does
 * not know about the potential need to use locking around its access
 * to it.  However, it is straightforward to override
 * {@link #onBackup()} and {@link #onRestore()} to supply the necessary locking
 * around the helper's operation.
 */
public class FileHelperExampleAgent extends BackupAgentHelper {
    /**
     * The "key" string passed when adding a helper is a token used to
     * disambiguate between entities supplied by multiple different helper
     * objects.  They only need to be unique among the helpers within this
     * one agent class, not globally unique.
     */
    static final String FILE_HELPER_KEY = "the_file";

    /**
     * The {@link android.app.backup.FileBackupHelper FileBackupHelper} class
     * does nearly all of the work for our use case:  backup and restore of a
     * file stored within our application's getFilesDir() location.  It will
     * also handle files stored at any subpath within that location.  All we
     * need to do is a bit of one-time configuration: installing the helper
     * when this agent object is created.
     */
    @Override
    public void onCreate() {
        // All we need to do when working within the BackupAgentHelper mechanism
        // is to install the helper that will process and back up the files we
        // care about.  In this case, it's just one file.
        FileBackupHelper helper = new FileBackupHelper(this, BackupRestoreActivity.DATA_FILE_NAME);
        addHelper(FILE_HELPER_KEY, helper);
    }

    /**
     * We want to ensure that the UI is not trying to rewrite the data file
     * while we're reading it for backup, so we override this method to
     * supply the necessary locking.
     */
    @Override
    public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
             ParcelFileDescriptor newState) throws IOException {
        // Hold the lock while the FileBackupHelper performs the backup operation
        synchronized (BackupRestoreActivity.sDataLock) {
            super.onBackup(oldState, data, newState);
        }
    }

    /**
     * Adding locking around the file rewrite that happens during restore is
     * similarly straightforward.
     */
    @Override
    public void onRestore(BackupDataInput data, int appVersionCode,
            ParcelFileDescriptor newState) throws IOException {
        // Hold the lock while the FileBackupHelper restores the file from
        // the data provided here.
        synchronized (BackupRestoreActivity.sDataLock) {
            super.onRestore(data, appVersionCode, newState);
        }
    }
}



//src\com\example\android\backuprestore\MultiRecordExampleAgent.java
/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      *www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.android.backuprestore;

import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;

import android.app.backup.BackupAgent;
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
import android.os.ParcelFileDescriptor;

/**
 * This agent implementation is similar to the {@link ExampleAgent} one, but
 * stores each distinct piece of application data in a separate record within
 * the backup data set.  These records are updated independently: if the user
 * changes the state of one of the UI's checkboxes, for example, only that
 * datum's backup record is updated, not the entire data file.
 */
public class MultiRecordExampleAgent extends BackupAgent {
    // Key strings for each record in the backup set
    static final String FILLING_KEY = "filling";
    static final String MAYO_KEY = "mayo";
    static final String TOMATO_KEY = "tomato";

    // Current live data, read from the application's data file
    int mFilling;
    boolean mAddMayo;
    boolean mAddTomato;

    /** The location of the application's persistent data file */
    File mDataFile;

    @Override
    public void onCreate() {
        // Cache a File for the app's data
        mDataFile = new File(getFilesDir(), BackupRestoreActivity.DATA_FILE_NAME);
    }

    @Override
    public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
            ParcelFileDescriptor newState) throws IOException {
        // First, get the current data from the application's file.  This
        // may throw an IOException, but in that case something has gone
        // badly wrong with the app's data on disk, and we do not want
        // to back up garbage data.  If we just let the exception go, the
        // Backup Manager will handle it and simply skip the current
        // backup operation.
        synchronized (BackupRestoreActivity.sDataLock) {
            RandomAccessFile file = new RandomAccessFile(mDataFile, "r");
            mFilling = file.readInt();
            mAddMayo = file.readBoolean();
            mAddTomato = file.readBoolean();
        }

        // If this is the first backup ever, we have to back up everything
        boolean forceBackup = (oldState == null);

        // Now read the state as of the previous backup pass, if any
        int lastFilling = 0;
        boolean lastMayo = false;
        boolean lastTomato = false;

        if (!forceBackup) {

            FileInputStream instream = new FileInputStream(oldState.getFileDescriptor());
            DataInputStream in = new DataInputStream(instream);

            try {
                // Read the state as of the last backup
                lastFilling = in.readInt();
                lastMayo = in.readBoolean();
                lastTomato = in.readBoolean();
            } catch (IOException e) {
                // If something went wrong reading the state file, be safe and
                // force a backup of all the data again.
                forceBackup = true;
            }
        }

        // Okay, now check each datum to see whether we need to back up a new value.  We'll
        // reuse the bytearray buffering stream for each datum.  We also use a little
        // helper routine to avoid some code duplication when writing the two boolean
        // records.
        ByteArrayOutputStream bufStream = new ByteArrayOutputStream();
        DataOutputStream out = new DataOutputStream(bufStream);

        if (forceBackup || (mFilling != lastFilling)) {
            // bufStream.reset();   // not necessary the first time, but good to remember
            out.writeInt(mFilling);
            writeBackupEntity(data, bufStream, FILLING_KEY);
        }

        if (forceBackup || (mAddMayo != lastMayo)) {
            bufStream.reset();
            out.writeBoolean(mAddMayo);
            writeBackupEntity(data, bufStream, MAYO_KEY);
        }

        if (forceBackup || (mAddTomato != lastTomato)) {
            bufStream.reset();
            out.writeBoolean(mAddTomato);
            writeBackupEntity(data, bufStream, TOMATO_KEY);
        }

        // Finally, write the state file that describes our data as of this backup pass
        writeStateFile(newState);
    }

    /**
     * Write out the new state file:  the version number, followed by the
     * three bits of data as we sent them off to the backup transport.
     */
    void writeStateFile(ParcelFileDescriptor stateFile) throws IOException {
        FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor());
        DataOutputStream out = new DataOutputStream(outstream);

        out.writeInt(mFilling);
        out.writeBoolean(mAddMayo);
        out.writeBoolean(mAddTomato);
    }

    // Helper: write the boolean 'value' as a backup record under the given 'key',
    // reusing the given buffering stream & data writer objects to do so.
    void writeBackupEntity(BackupDataOutput data, ByteArrayOutputStream bufStream, String key)
            throws IOException {
        byte[] buf = bufStream.toByteArray();
        data.writeEntityHeader(key, buf.length);
        data.writeEntityData(buf, buf.length);
    }

    /**
     * On restore, we pull the various bits of data out of the restore stream,
     * then reconstruct the application's data file inside the shared lock.  A
     * restore data set will always be the full set of records supplied by the
     * application's backup operations.
     */
    @Override
    public void onRestore(BackupDataInput data, int appVersionCode,
            ParcelFileDescriptor newState) throws IOException {

        // Consume the restore data set, remembering each bit of application state
        // that we see along the way
        while (data.readNextHeader()) {
            String key = data.getKey();
            int dataSize = data.getDataSize();

            // In this implementation, we trust that we won't see any record keys
            // that we don't understand.  Since we expect to handle them all, we
            // go ahead and extract the data for each record before deciding how
            // it will be handled.
            byte[] dataBuf = new byte[dataSize];
            data.readEntityData(dataBuf, 0, dataSize);
            ByteArrayInputStream instream = new ByteArrayInputStream(dataBuf);
            DataInputStream in = new DataInputStream(instream);

            if (FILLING_KEY.equals(key)) {
                mFilling = in.readInt();
            } else if (MAYO_KEY.equals(key)) {
                mAddMayo = in.readBoolean();
            } else if (TOMATO_KEY.equals(key)) {
                mAddTomato = in.readBoolean();
            }
        }

        // Now we're ready to write out a full new dataset for the application.  Note that
        // the restore process is intended to *replace* any existing or default data, so
        // we can just go ahead and overwrite it all.
        synchronized (BackupRestoreActivity.sDataLock) {
            RandomAccessFile file = new RandomAccessFile(mDataFile, "rw");
            file.setLength(0L);
            file.writeInt(mFilling);
            file.writeBoolean(mAddMayo);
            file.writeBoolean(mAddTomato);
        }

        // Finally, write the state file that describes our data as of this restore pass.
        writeStateFile(newState);
    }
}



//res\layout\backup_restore.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
  
          *www.apache.org/licenses/LICENSE-2.0
  
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<!-- Layout description of the BackupRestore sample's main activity -->

<LinearLayout xmlns:android="*schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ScrollView
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_weight="1">

        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <TextView android:text="@string/filling_text"
                android:textSize="20dp"
                android:layout_marginTop="20dp"
                android:layout_marginBottom="10dp"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>

            <RadioGroup android:id="@+id/filling_group"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="20dp"
                android:orientation="vertical">

                <RadioButton android:id="@+id/bacon"
                    android:text="@string/bacon_label"/>
                <RadioButton android:id="@+id/pastrami"
                    android:text="@string/pastrami_label"/>
                <RadioButton android:id="@+id/hummus"
                    android:text="@string/hummus_label"/>

            </RadioGroup>

            <TextView android:text="@string/extras_text"
                android:textSize="20dp"
                android:layout_marginTop="20dp"
                android:layout_marginBottom="10dp"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>

            <CheckBox android:id="@+id/mayo"
                android:text="@string/mayo_text"
                android:layout_marginLeft="20dp"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>

            <CheckBox android:id="@+id/tomato"
                android:text="@string/tomato_text"
                android:layout_marginLeft="20dp"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>

        </LinearLayout>

    </ScrollView>

    <Button android:id="@+id/restore_button"
        android:text="@string/restore_text"
        android:onClick="onRestoreButtonClick"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:layout_weight="0" />

</LinearLayout>




//res\values\strings.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
  
          *www.apache.org/licenses/LICENSE-2.0
  
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<resources>
  <string name="filling_text">Choose a sandwich filling:</string>
  <string name="bacon_label">Bacon</string>
  <string name="pastrami_label">Pastrami</string>
  <string name="hummus_label">Hummus</string>

  <string name="extras_text">Extras:</string>
  <string name="mayo_text">Mayonnaise\?</string>
  <string name="tomato_text">Tomato\?</string>

  <string name="restore_text">Restore last data</string>
</resources>
```
Progress of AsyncTask

```
package app.test;

import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;

class CustomHttpClient {
  private static HttpClient customHttpClient;

  public static synchronized HttpClient getHttpClient() {
    if (customHttpClient != null) {
      return customHttpClient;
    }
    HttpParams params = new BasicHttpParams();
    HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
    HttpProtocolParams.setContentCharset(params,
        HTTP.DEFAULT_CONTENT_CHARSET);
    HttpProtocolParams.setUseExpectContinue(params, true);

    ConnManagerParams.setTimeout(params, 1000);

    HttpConnectionParams.setConnectionTimeout(params, 5000);
    HttpConnectionParams.setSoTimeout(params, 10000);

    SchemeRegistry schReg = new SchemeRegistry();
    schReg.register(new Scheme("http", PlainSocketFactory
        .getSocketFactory(), 80));
    schReg.register(new Scheme("https",
        SSLSocketFactory.getSocketFactory(), 443));
    ClientConnectionManager conMgr = new ThreadSafeClientConnManager(
        params, schReg);

    customHttpClient = new DefaultHttpClient(conMgr, params);

    return customHttpClient;
  }
}

class DownloadImageTask extends AsyncTask<String, Integer, Bitmap> {
  Context mContext;
  int progress = -1;
  Bitmap downloadedImage = null;

  DownloadImageTask(Context context) {
    mContext = context;
  }

  protected void setContext(Context context) {
    mContext = context;
    if (progress >= 0) {
      publishProgress(this.progress);
    }
  }

  protected void onPreExecute() {
    progress = 0;
  }

  protected Bitmap doInBackground(String... urls) {
    Log.v("doInBackground", "doing download of image...");
    return downloadImage(urls);
  }

  protected void onProgressUpdate(Integer... progress) {
    Log.v("onProgressUpdate", "Progress so far: " + progress[0]);
  }

  protected void onPostExecute(Bitmap result) {
    if (result != null) {
      downloadedImage = result;
      setImageInView();
    } else {
      Log.v("onPostExecute",
          "Problem downloading image. Please try later.");
    }
  }

  public Bitmap downloadImage(String... urls) {
    HttpClient httpClient = CustomHttpClient.getHttpClient();
    try {
      HttpGet request = new HttpGet(urls[0]);
      HttpParams params = new BasicHttpParams();
      HttpConnectionParams.setSoTimeout(params, 60000); // 1 minute
      request.setParams(params);
      HttpResponse response = httpClient.execute(request);
      setProgress(50);
      byte[] image = EntityUtils.toByteArray(response.getEntity());
      setProgress(75);
      Bitmap mBitmap = BitmapFactory.decodeByteArray(image, 0,
          image.length);
      setProgress(100);
      return mBitmap;
    } catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }

  private void setProgress(int progress) {
    this.progress = progress;
    publishProgress(this.progress);
  }

  protected void setImageInView() {
    if (downloadedImage != null) {
      ImageView mImage = (ImageView) ((Activity) mContext)
          .findViewById(R.id.image);
      mImage.setImageBitmap(downloadedImage);
    }
  }

  private void sleepFor(long msecs) {
    try {
      Thread.sleep(msecs);
    } catch (InterruptedException e) {
      Log.v("sleep", "interrupted");
    }
  }
}

public class Test extends Activity {
  private DownloadImageTask diTask;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    if ((diTask = (DownloadImageTask) getLastNonConfigurationInstance()) != null) {
      diTask.setContext(this);
      if (diTask.getStatus() == AsyncTask.Status.FINISHED)
        diTask.setImageInView();
    }
  }

  public void doClick(View view) {
    if (diTask != null) {
      AsyncTask.Status diStatus = diTask.getStatus();
      Log.v("doClick", "diTask status is " + diStatus);
      if (diStatus != AsyncTask.Status.FINISHED) {
        Log.v("doClick", "... no need to start a new task");
        return;
      }
    }
    diTask = new DownloadImageTask(this);
    diTask.execute("*aBigFile");
  }

  @Override
  public Object onRetainNonConfigurationInstance() {
    return diTask;
  }
}
```
Using Geocoder

```
package app.test;

import java.io.IOException;
import java.util.List;
import java.util.Locale;

import android.app.Activity;
import android.content.Context;
import android.location.Address;
import android.location.Criteria;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.widget.TextView;

public class Test extends Activity {

  @Override
  public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    setContentView(R.layout.main);

    LocationManager locationManager;
    locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

    Criteria criteria = new Criteria();
    criteria.setAccuracy(Criteria.ACCURACY_FINE);
    criteria.setAltitudeRequired(false);
    criteria.setBearingRequired(false);
    criteria.setCostAllowed(true);
    criteria.setPowerRequirement(Criteria.POWER_LOW);

    String provider = locationManager.getBestProvider(criteria, true);

    Location location = locationManager.getLastKnownLocation(provider);
    updateWithNewLocation(location);

    locationManager.requestLocationUpdates(provider, 2000, 10,
        locationListener);
  }

  private final LocationListener locationListener = new LocationListener() {
    public void onLocationChanged(Location location) {
      updateWithNewLocation(location);
    }

    public void onProviderDisabled(String provider) {
      updateWithNewLocation(null);
    }

    public void onProviderEnabled(String provider) {
    }

    public void onStatusChanged(String provider, int status, Bundle extras) {
    }
  };

  private void updateWithNewLocation(Location location) {
    TextView myLocationText = (TextView) findViewById(R.id.myLocationText);

    String latLongString;
    String addressString = "No address found";

    if (location != null) {
      double lat = location.getLatitude();
      double lng = location.getLongitude();
      latLongString = "Lat:" + lat + "\nLong:" + lng;

      Geocoder gc = new Geocoder(this, Locale.getDefault());
      try {
        List<Address> addresses = gc.getFromLocation(lat, lng, 1);
        StringBuilder sb = new StringBuilder();
        if (addresses.size() > 0) {
          Address address = addresses.get(0);

          for (int i = 0; i < address.getMaxAddressLineIndex(); i++)
            sb.append(address.getAddressLine(i)).append("\n");

          sb.append(address.getLocality()).append("\n");
          sb.append(address.getPostalCode()).append("\n");
          sb.append(address.getCountryName());
        }
        addressString = sb.toString();
      } catch (IOException e) {
      }
    } else {
      latLongString = "No location found";
    }
    myLocationText.setText("Your Current Position is:\n" + latLongString
        + "\n" + addressString);
  }

}


//main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
  xmlns:android="*schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
  <TextView  
    android:id="@+id/myLocationText"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/hello"
  />
</LinearLayout>
```
Handles all calling, receiving calls, and UI interaction in the WalkieTalkie app

```
package app.test;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.PendingIntent;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.*;
import android.net.sip.*;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.ToggleButton;

import java.text.ParseException;

import android.os.Bundle;
import android.preference.PreferenceActivity;


import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.sip.*;
import android.util.Log;

/**
 * Listens for incoming SIP calls, intercepts and hands them off to WalkieTalkieActivity.
 */
 class IncomingCallReceiver extends BroadcastReceiver {
    /**
     * Processes the incoming call, answers it, and hands it over to the
     * WalkieTalkieActivity.
     * [MENTION=9956]PARAM[/MENTION] context The context under which the receiver is running.
     * [MENTION=9956]PARAM[/MENTION] intent The intent being received.
     */
    @Override
    public void onReceive(Context context, Intent intent) {
        SipAudioCall incomingCall = null;
        try {

            SipAudioCall.Listener listener = new SipAudioCall.Listener() {
                @Override
                public void onRinging(SipAudioCall call, SipProfile caller) {
                    try {
                        call.answerCall(30);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            };

            WalkieTalkieActivity wtActivity = (WalkieTalkieActivity) context;

            incomingCall = wtActivity.manager.takeAudioCall(intent, listener);
            incomingCall.answerCall(30);
            incomingCall.startAudio();
            incomingCall.setSpeakerMode(true);
            if(incomingCall.isMuted()) {
                incomingCall.toggleMute();
            }

            wtActivity.call = incomingCall;

            wtActivity.updateStatus(incomingCall);

        } catch (Exception e) {
            if (incomingCall != null) {
                incomingCall.close();
            }
        }
    }

}

/**
 * Handles SIP authentication settings for the Walkie Talkie app.
 */
 class SipSettings extends PreferenceActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        // Note that none of the preferences are actually defined here.
        // They're all in the XML file res/xml/preferences.xml.
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);
    }
}

/**
 * Handles all calling, receiving calls, and UI interaction in the WalkieTalkie app.
 */
public class Test extends Activity implements View.OnTouchListener {

    public String sipAddress = null;

    public SipManager manager = null;
    public SipProfile me = null;
    public SipAudioCall call = null;
    public IncomingCallReceiver callReceiver;

    private static final int CALL_ADDRESS = 1;
    private static final int SET_AUTH_INFO = 2;
    private static final int UPDATE_SETTINGS_DIALOG = 3;
    private static final int HANG_UP = 4;


    @Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.walkietalkie);

        ToggleButton pushToTalkButton = (ToggleButton) findViewById(R.id.pushToTalk);
        pushToTalkButton.setOnTouchListener(this);

        // Set up the intent filter.  This will be used to fire an
        // IncomingCallReceiver when someone calls the SIP address used by this
        // application.
        IntentFilter filter = new IntentFilter();
        filter.addAction("android.SipDemo.INCOMING_CALL");
        callReceiver = new IncomingCallReceiver();
        this.registerReceiver(callReceiver, filter);

        // "Push to talk" can be a serious pain when the screen keeps turning off.
        // Let's prevent that.
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        initializeManager();
    }

    @Override
    public void onStart() {
        super.onStart();
        // When we get back from the preference setting Activity, assume
        // settings have changed, and re-login with new auth info.
        initializeManager();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (call != null) {
            call.close();
        }

        closeLocalProfile();

        if (callReceiver != null) {
            this.unregisterReceiver(callReceiver);
        }
    }

    public void initializeManager() {
        if(manager == null) {
          manager = SipManager.newInstance(this);
        }

        initializeLocalProfile();
    }

    /**
     * Logs you into your SIP provider, registering this device as the location to
     * send SIP calls to for your SIP address.
     */
    public void initializeLocalProfile() {
        if (manager == null) {
            return;
        }

        if (me != null) {
            closeLocalProfile();
        }

        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
        String username = prefs.getString("namePref", "");
        String domain = prefs.getString("domainPref", "");
        String password = prefs.getString("passPref", "");

        if (username.length() == 0 || domain.length() == 0 || password.length() == 0) {
            showDialog(UPDATE_SETTINGS_DIALOG);
            return;
        }

        try {
            SipProfile.Builder builder = new SipProfile.Builder(username, domain);
            builder.setPassword(password);
            me = builder.build();

            Intent i = new Intent();
            i.setAction("android.SipDemo.INCOMING_CALL");
            PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, Intent.FILL_IN_DATA);
            manager.open(me, pi, null);


            // This listener must be added AFTER manager.open is called,
            // Otherwise the methods aren't guaranteed to fire.

            manager.setRegistrationListener(me.getUriString(), new SipRegistrationListener() {
                    public void onRegistering(String localProfileUri) {
                        updateStatus("Registering with SIP Server...");
                    }

                    public void onRegistrationDone(String localProfileUri, long expiryTime) {
                        updateStatus("Ready");
                    }

                    public void onRegistrationFailed(String localProfileUri, int errorCode,
                            String errorMessage) {
                        updateStatus("Registration failed.  Please check settings.");
                    }
                });
        } catch (ParseException pe) {
            updateStatus("Connection Error.");
        } catch (SipException se) {
            updateStatus("Connection error.");
        }
    }

    /**
     * Closes out your local profile, freeing associated objects into memory
     * and unregistering your device from the server.
     */
    public void closeLocalProfile() {
        if (manager == null) {
            return;
        }
        try {
            if (me != null) {
                manager.close(me.getUriString());
            }
        } catch (Exception ee) {
            Log.d("WalkieTalkieActivity/onDestroy", "Failed to close local profile.", ee);
        }
    }

    /**
     * Make an outgoing call.
     */
    public void initiateCall() {

        updateStatus(sipAddress);

        try {
            SipAudioCall.Listener listener = new SipAudioCall.Listener() {
                // Much of the client's interaction with the SIP Stack will
                // happen via listeners.  Even making an outgoing call, don't
                // forget to set up a listener to set things up once the call is established.
                @Override
                public void onCallEstablished(SipAudioCall call) {
                    call.startAudio();
                    call.setSpeakerMode(true);
                    call.toggleMute();
                    updateStatus(call);
                }

                @Override
                public void onCallEnded(SipAudioCall call) {
                    updateStatus("Ready.");
                }
            };

            call = manager.makeAudioCall(me.getUriString(), sipAddress, listener, 30);

        }
        catch (Exception e) {
            Log.i("WalkieTalkieActivity/InitiateCall", "Error when trying to close manager.", e);
            if (me != null) {
                try {
                    manager.close(me.getUriString());
                } catch (Exception ee) {
                    Log.i("WalkieTalkieActivity/InitiateCall",
                            "Error when trying to close manager.", ee);
                    ee.printStackTrace();
                }
            }
            if (call != null) {
                call.close();
            }
        }
    }

    /**
     * Updates the status box at the top of the UI with a messege of your choice.
     * [MENTION=9956]PARAM[/MENTION] status The String to display in the status box.
     */
    public void updateStatus(final String status) {
        // Be a good citizen.  Make sure UI changes fire on the UI thread.
        this.runOnUiThread(new Runnable() {
            public void run() {
                TextView labelView = (TextView) findViewById(R.id.sipLabel);
                labelView.setText(status);
            }
        });
    }

    /**
     * Updates the status box with the SIP address of the current call.
     * [MENTION=9956]PARAM[/MENTION] call The current, active call.
     */
    public void updateStatus(SipAudioCall call) {
        String useName = call.getPeerProfile().getDisplayName();
        if(useName == null) {
          useName = call.getPeerProfile().getUserName();
        }
        updateStatus(useName + "@" + call.getPeerProfile().getSipDomain());
    }

    /**
     * Updates whether or not the user's voice is muted, depending on whether the button is pressed.
     * [MENTION=9956]PARAM[/MENTION] v The View where the touch event is being fired.
     * [MENTION=9956]PARAM[/MENTION] event The motion to act on.
     * @return boolean Returns false to indicate that the parent view should handle the touch event
     * as it normally would.
     */
    public boolean onTouch(View v, MotionEvent event) {
        if (call == null) {
            return false;
        } else if (event.getAction() == MotionEvent.ACTION_DOWN && call != null && call.isMuted()) {
            call.toggleMute();
        } else if (event.getAction() == MotionEvent.ACTION_UP && !call.isMuted()) {
            call.toggleMute();
        }
        return false;
    }

    public boolean onCreateOptionsMenu(Menu menu) {
        menu.add(0, CALL_ADDRESS, 0, "Call someone");
        menu.add(0, SET_AUTH_INFO, 0, "Edit your SIP Info.");
        menu.add(0, HANG_UP, 0, "End Current Call.");

        return true;
    }

    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case CALL_ADDRESS:
                showDialog(CALL_ADDRESS);
                break;
            case SET_AUTH_INFO:
                updatePreferences();
                break;
            case HANG_UP:
                if(call != null) {
                    try {
                      call.endCall();
                    } catch (SipException se) {
                        Log.d("WalkieTalkieActivity/onOptionsItemSelected",
                                "Error ending call.", se);
                    }
                    call.close();
                }
                break;
        }
        return true;
    }

    @Override
    protected Dialog onCreateDialog(int id) {
        switch (id) {
            case CALL_ADDRESS:

                LayoutInflater factory = LayoutInflater.from(this);
                final View textBoxView = factory.inflate(R.layout.call_address_dialog, null);
                return new AlertDialog.Builder(this)
                        .setTitle("Call Someone.")
                        .setView(textBoxView)
                        .setPositiveButton(
                                android.R.string.ok, new DialogInterface.OnClickListener() {
                                    public void onClick(DialogInterface dialog, int whichButton) {
                                        EditText textField = (EditText)
                                                (textBoxView.findViewById(R.id.calladdress_edit));
                                        sipAddress = textField.getText().toString();
                                        initiateCall();

                                    }
                        })
                        .setNegativeButton(
                                android.R.string.cancel, new DialogInterface.OnClickListener() {
                                    public void onClick(DialogInterface dialog, int whichButton) {
                                        // Noop.
                                    }
                        })
                        .create();

            case UPDATE_SETTINGS_DIALOG:
                return new AlertDialog.Builder(this)
                        .setMessage("Please update your SIP Account Settings.")
                        .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int whichButton) {
                                updatePreferences();
                            }
                        })
                        .setNegativeButton(
                                android.R.string.cancel, new DialogInterface.OnClickListener() {
                                    public void onClick(DialogInterface dialog, int whichButton) {
                                        // Noop.
                                    }
                        })
                        .create();
        }
        return null;
    }

    public void updatePreferences() {
        Intent settingsActivity = new Intent(getBaseContext(),
                SipSettings.class);
        startActivity(settingsActivity);
    }
}
//
//res\layout\call_address_dialog.xml
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2010 The Android Open Source Project

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

     [url]*www.apache.org/licenses/LICENSE-2.0[/url]

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

<LinearLayout xmlns:android="*schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:orientation="vertical">

  <TextView
      android:id="@+id/calladdress_view"
      android:layout_height="wrap_content"
      android:layout_width="wrap_content"
      android:layout_marginLeft="20dip"
      android:layout_marginRight="20dip"
      android:text="@+string/contactAddress"
      android:gravity="left"
      android:textAppearance="?android:attr/textAppearanceMedium" />

  <EditText
      android:id="@+id/calladdress_edit"
      android:layout_height="wrap_content"
      android:layout_width="fill_parent"
      android:layout_marginLeft="20dip"
      android:layout_marginRight="20dip"
      android:scrollHorizontally="true"
      android:autoText="false"
      android:capitalize="none"
      android:gravity="fill_horizontal"
      android:textAppearance="?android:attr/textAppearanceMedium" />

</LinearLayout>



//res\layout\walkietalkie.xml
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2010 The Android Open Source Project

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

     [url]*www.apache.org/licenses/LICENSE-2.0[/url]

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

<FrameLayout xmlns:android="*schemas.android.com/apk/res/android"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent">
  <RelativeLayout android:padding="12dp"
      android:id="@+id/mainlayout"
      android:orientation="vertical"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent">

      <TextView
          android:id="@+id/sipLabel"
          android:layout_width="fill_parent"
          android:layout_height="fill_parent"
          android:layout_centerHorizontal="true"
          android:textAppearance="?android:attr/textAppearanceLarge"
      />

      <ToggleButton
          android:layout_height="400dp"
          android:layout_width="400dp"
          android:text="@+string/talk"
          android:id="@+id/pushToTalk"

          android:layout_centerHorizontal="true"
          android:layout_centerVertical="true"
          android:background="@drawable/btn_record"
          android:textOff=""
          android:textOn=""
          android:layout_marginTop="-20dp" />

  </RelativeLayout>
</FrameLayout>



//
//res\values\strings.xml
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2010 The Android Open Source Project

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

     [url]*www.apache.org/licenses/LICENSE-2.0[/url]

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

<resources>
  <string name="app_name">SIP Demo</string>
  <string name="contactAddress">SIP Address to contact</string>
  <string name="talk">Talk</string>
</resources>



//
//res\xml\preferences.xml
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2010 The Android Open Source Project

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

     [url]*www.apache.org/licenses/LICENSE-2.0[/url]

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

<PreferenceScreen xmlns:android="*schemas.android.com/apk/res/android">
  <EditTextPreference
      android:name="SIP Username"
      android:summary="Username for your SIP Account"
      android:defaultValue=""
      android:title="Enter Username"
      android:key="namePref" />
  <EditTextPreference
      android:name="SIP Domain"
      android:summary="Domain for your SIP Account"
      android:defaultValue=""
      android:title="Enter Domain"
      android:key="domainPref" />
  <EditTextPreference
      android:name="SIP Password"
      android:summary="Password for your SIP Account"
      android:defaultValue=""
      android:title="Enter Password"
      android:key="passPref"
      android:password="true" />
</PreferenceScreen>
```
Launch browser

```
package app.test;

import java.io.File;
import java.util.ArrayList;

import android.app.Activity;
import android.app.SearchManager;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.Contacts;
import android.view.Menu;

public class Test extends Activity {

    private Intent browserIntent, phoneIntent, mapIntent, mailIntent, contactIntent, marketIntent, smsIntent;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        browserIntent = new Intent();
        browserIntent.setAction(Intent.ACTION_VIEW);
        browserIntent.setData(Uri.parse("*www.google.com"));
        browserIntent.setAction(Intent.ACTION_WEB_SEARCH);
        browserIntent.putExtra(SearchManager.QUERY, "puppies");

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        menu.add("Browser").setIntent(browserIntent);
        menu.add("Phone").setIntent(phoneIntent);
        menu.add("Map").setIntent(mapIntent);
        menu.add("Mail").setIntent(Intent.createChooser(mailIntent, "Mail Client"));
        menu.add("SMS").setIntent(smsIntent);
        menu.add("Contacts").setIntent(contactIntent);
        menu.add("Market").setIntent(marketIntent);
        return true;
    }
}
```
Voice recognition demo

```
package app.test;

import java.util.ArrayList;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.speech.RecognizerIntent;
import android.widget.TextView;
import android.widget.Toast;

public class Test extends Activity {
    private static final int REQUEST_RECOGNIZE = 100;
    TextView tv;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        tv = new TextView(this);
        setContentView(tv);
        
        Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
        intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
        intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "Tell Me Your Name");
        try {
            startActivityForResult(intent, REQUEST_RECOGNIZE);
        } catch (ActivityNotFoundException e) {
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle("Not Available");
            builder.setMessage("No recognition software installed.Download one?");
            builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    Intent marketIntent = new Intent(Intent.ACTION_VIEW);
                    marketIntent.setData(Uri.parse("market://details?id=com.google.android.voicesearch"));
                }
            });
            builder.setNegativeButton("No", null);
            builder.create().show();
        }
    }
   
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if(requestCode == REQUEST_RECOGNIZE && resultCode == Activity.RESULT_OK) {
            ArrayList<String> matches = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
            StringBuilder sb = new StringBuilder();
            for(String piece : matches) {
                sb.append(piece);
                sb.append('\n');
            }
            tv.setText(sb.toString());
        } else {
            Toast.makeText(this, "Operation Canceled", Toast.LENGTH_SHORT).show();
        }
    }
}
```
Lazy Loading Image

```
public class LazyLoadingImage {
   private String mImageUrl;
   private String mImageCacheName;
   private int mMaxWidth;
   private int mMaxHeight;
   private ImageType mImageType;
   public enum ImageType { Media, TvLogo };
   
   public LazyLoadingImage(String _url, String _cache, int _maxWidth, int _maxHeight) {
      mImageUrl = _url;
      mImageCacheName = _cache;
      mMaxWidth = _maxWidth;
      mMaxHeight = _maxHeight;
   }
   
   public void setImageType(ImageType _type){
      mImageType = _type;
   }
   
   public ImageType getImageType(){
      return mImageType;
   }
   
   /**
    * The url of the image that should be loaded on demand
    * @return Url to the image
    */
   public String getImageUrl() {
      return mImageUrl;
   }
   
   /**
    * The url of the image that should be loaded on demand
    * [MENTION=9956]PARAM[/MENTION] _imageUrl Url to the image
    */
   public void setImageUrl(String _imageUrl) {
      this.mImageUrl = _imageUrl;
   }
   
   /**
    * Name of image in cache
    * @return The path of the image (once cached) relative to the cache root
    */
   public String getImageCacheName() {
      return mImageCacheName;
   }
   
   /**
    * Name of image in cache
    * [MENTION=9956]PARAM[/MENTION] _cacheName The path of the image (once cached) relative to the cache root
    */
   public void setImageCacheName(String _cacheName) {
      this.mImageCacheName = _cacheName;
   }
   public int getMaxWidth() {
      return mMaxWidth;
   }
   public void setMaxWidth(int _maxWidth) {
      this.mMaxWidth = _maxWidth;
   }
   public int getMaxHeight() {
      return mMaxHeight;
   }
   public void setMaxHeight(int _maxHeight) {
      this.mMaxHeight = _maxHeight;
   }
   }
```
Drag and drop

```
package app.test;

import android.animation.ObjectAnimator;
import android.app.Activity;
import android.app.Fragment;
import android.content.ClipData;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log;
import android.view.DragEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.CycleInterpolator;
import android.widget.TextView;

class Dot extends View implements View.OnDragListener {
  private static final int DEFAULT_RADIUS = 50;
  private static final int DEFAULT_COLOR = Color.WHITE;
  private static final int SELECTED_COLOR = Color.MAGENTA;
  protected static final String DOTTAG = "DragDot";
  private Paint mNormalPaint;
  private Paint mDraggingPaint;
  private int mColor = DEFAULT_COLOR;
  private int mRadius = DEFAULT_RADIUS;
  private boolean inDrag;

  public Dot(Context context, AttributeSet attrs) {
    super(context, attrs);
    mNormalPaint = new Paint();
    mNormalPaint.setColor(mColor);
    mNormalPaint.setAntiAlias(true);

    mDraggingPaint = new Paint();
    mDraggingPaint.setColor(SELECTED_COLOR);
    mDraggingPaint.setAntiAlias(true);
    setOnLongClickListener(lcListener);
    setOnDragListener(this);
  }

  private static View.OnLongClickListener lcListener = new View.OnLongClickListener() {
    private boolean mDragInProgress;

    public boolean onLongClick(View v) {
      ClipData data = ClipData.newPlainText("DragData",
          (String) v.getTag());
      mDragInProgress = v.startDrag(data, new View.DragShadowBuilder(v),
          (Object) v, 0);
      Log.v((String) v.getTag(), "starting drag? " + mDragInProgress);
      return true;
    }
  };

  @Override
  protected void onMeasure(int widthSpec, int heightSpec) {
    int size = 2 * mRadius + getPaddingLeft() + getPaddingRight();
    setMeasuredDimension(size, size);
  }

  public boolean onDrag(View v, DragEvent event) {
    String dotTAG = (String) getTag();
    if (event.getLocalState() != this) {
      return false;
    }
    boolean result = true;
    int action = event.getAction();
    float x = event.getX();
    float y = event.getY();
    switch (action) {
    case DragEvent.ACTION_DRAG_STARTED:
      inDrag = true;
      break;
    case DragEvent.ACTION_DRAG_LOCATION:
      break;
    case DragEvent.ACTION_DRAG_ENTERED:
      break;
    case DragEvent.ACTION_DRAG_EXITED:
      break;
    case DragEvent.ACTION_DROP:
      result = false;
      break;
    case DragEvent.ACTION_DRAG_ENDED:
      inDrag = false; // change color of original dot back
      break;
    default:
      result = false;
      break;
    }
    return result;
  }

  public void draw(Canvas canvas) {
    float cx = this.getWidth() / 2 + getLeftPaddingOffset();
    float cy = this.getHeight() / 2 + getTopPaddingOffset();
    Paint paint = mNormalPaint;
    if (inDrag)
      paint = mDraggingPaint;
    canvas.drawCircle(cx, cy, mRadius, paint);
    invalidate();
  }
}

class DropZone extends Fragment {
  private View dropTarget;
  private TextView dropMessage;

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle icicle) {
    View v = inflater.inflate(R.layout.row, container, false);
    dropMessage = (TextView) v.findViewById(R.id.dropmessage);
    dropTarget = (View) v.findViewById(R.id.droptarget);
    dropTarget.setOnDragListener(new View.OnDragListener() {
      private static final String DROPTAG = "DropTarget";
      private int dropCount = 0;
      private ObjectAnimator anim;

      public boolean onDrag(View v, DragEvent event) {
        int action = event.getAction();
        boolean result = true;
        switch (action) {
        case DragEvent.ACTION_DRAG_STARTED:
          break;
        case DragEvent.ACTION_DRAG_ENTERED:
          anim = ObjectAnimator
              .ofFloat((Object) v, "alpha", 1f, 0.5f);
          anim.setInterpolator(new CycleInterpolator(40));
          anim.setDuration(30 * 1000);
          anim.start();
          break;
        case DragEvent.ACTION_DRAG_EXITED:
          if (anim != null) {
            anim.end();
            anim = null;
          }
          break;
        case DragEvent.ACTION_DRAG_LOCATION:
          Log.v(DROPTAG,
              "drag proceeding in dropTarget: " + event.getX()
                  + ", " + event.getY());
          break;
        case DragEvent.ACTION_DROP:
          Log.v(DROPTAG, "drag drop in dropTarget");
          if (anim != null) {
            anim.end();
            anim = null;
          }
          ClipData data = event.getClipData();
          Log.v(DROPTAG, "Item data is "
              + data.getItemAt(0).getText());
          dropCount++;
          String message = dropCount + " drop";
          if (dropCount > 1)
            message += "s";
          dropMessage.setText(message);
          break;
        case DragEvent.ACTION_DRAG_ENDED:
          Log.v(DROPTAG, "drag ended in dropTarget");
          if (anim != null) {
            anim.end();
            anim = null;
          }
          break;
        default:
          Log.v(DROPTAG, "other action in dropzone: " + action);
          result = false;
        }
        return result;
      }
    });
    return v;
  }
}

class Palette extends Fragment {
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle icicle) {
    View v = inflater.inflate(R.layout.add_edit, container, false);
    return v;
  }
}

public class Test extends Activity {
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
  }
}

//layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- This file is res/layout/main.xml -->
<LinearLayout xmlns:android="*schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    <fragment class="app.test.TitlesFragment"
            android:id="@+id/titles"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
            android:background="#00550033" />

    <FrameLayout
            android:id="@+id/details" android:layout_weight="2"
            android:layout_width="0px"
            android:layout_height="match_parent" />
</LinearLayout>

//row.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="*schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="horizontal" >
  
  <View android:id="@+id/droptarget"
    android:layout_width="75dp"
    android:layout_height="75dp"
    android:layout_gravity="center_vertical"
    android:background="#00ff00" />

  <TextView android:id="@+id/dropmessage"
    android:text="0 drops"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_vertical"
    android:paddingLeft="50dp"
    android:textSize="17sp" />

</LinearLayout>


//add_edit.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- This file is res/layout/palette.xml -->
<LinearLayout
  xmlns:android="*schemas.android.com/apk/res/android"
  xmlns:dot="*schemas.android.com/apk/res/app.test.demo"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical">

  <app.test.Dot android:id="@+id/dot1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="30dp"
    android:tag="Blue dot"
    dot:color="#ff1111ff"
    dot:radius="20dp"
  />

  <app.test.Dot android:id="@+id/dot2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="10dp"
    android:tag="White dot"
    dot:color="#ffffffff"
    dot:radius="40dp"
  />

</LinearLayout>
```
Using Thread and Progress bar

```
package app.test;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.widget.ProgressBar;

public class Test extends Activity {

  private static int progress;
  private ProgressBar progressBar;
  private int progressStatus = 0;
  private Handler handler = new Handler();

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    progress = 0;
    progressBar = (ProgressBar) findViewById(R.id.progressbar);
    progressBar.setMax(200);

    new Thread(new Runnable() {
      public void run() {
        while (progressStatus < 200) {
          progressStatus = doSomeWork();
          handler.post(new Runnable() {
            public void run() {
              progressBar.setProgress(progressStatus);
            }
          });
        }
        handler.post(new Runnable() {
          public void run() {
            // ---0 - VISIBLE; 4 - INVISIBLE; 8 - GONE---
            progressBar.setVisibility(8);
          }
        });
      }

      private int doSomeWork() {
        try {
          // ---simulate doing some work---
          Thread.sleep(50);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        return ++progress;
      }
    }).start();
  }
}

//main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="*schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >
    
 <ProgressBar android:id="@+id/progressbar"
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content"
        style="?android:attr/progressBarStyleHorizontal" />
        
</LinearLayout>
```
Using TimePickerDialog

```
package app.test;

import android.app.Activity;
import android.os.Bundle;
import android.app.DatePickerDialog;
import android.app.TimePickerDialog;
import android.view.View;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.TimePicker;
import android.widget.TextView;
import java.text.DateFormat;
import java.util.Calendar;

public class Test extends Activity {
  DateFormat fmtDateAndTime=DateFormat.getDateTimeInstance();
  TextView dateAndTimeLabel;
  Calendar dateAndTime=Calendar.getInstance();
  DatePickerDialog.OnDateSetListener d=new DatePickerDialog.OnDateSetListener() {
    public void onDateSet(DatePicker view, int year, int monthOfYear,
                int dayOfMonth) {
      dateAndTime.set(Calendar.YEAR, year);
      dateAndTime.set(Calendar.MONTH, monthOfYear);
      dateAndTime.set(Calendar.DAY_OF_MONTH, dayOfMonth);
      updateLabel();
    }
  };  
  TimePickerDialog.OnTimeSetListener t=new TimePickerDialog.OnTimeSetListener() {
    public void onTimeSet(TimePicker view, int hourOfDay,
                          int minute) {
      dateAndTime.set(Calendar.HOUR_OF_DAY, hourOfDay);
      dateAndTime.set(Calendar.MINUTE, minute);
      updateLabel();
    }
  };  
      
  @Override
  public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    setContentView(R.layout.main);
    
    Button btn=(Button)findViewById(R.id.dateBtn);
    
    btn.setOnClickListener(new View.OnClickListener() {
      public void onClick(View v) {
        new DatePickerDialog(Test.this,
            d,
            dateAndTime.get(Calendar.YEAR),
            dateAndTime.get(Calendar.MONTH),
            dateAndTime.get(Calendar.DAY_OF_MONTH)).show();
      }
    });
    
    btn=(Button)findViewById(R.id.timeBtn);
    
    btn.setOnClickListener(new View.OnClickListener() {
      public void onClick(View v) {
        new TimePickerDialog(Test.this,
                    t,
                    dateAndTime.get(Calendar.HOUR_OF_DAY),
                    dateAndTime.get(Calendar.MINUTE),
                    true).show();
      }
    });
    
    dateAndTimeLabel=(TextView)findViewById(R.id.dateAndTime);
    
    updateLabel();
  }
  
  private void updateLabel() {
    dateAndTimeLabel.setText(fmtDateAndTime.format(dateAndTime.getTime()));
  }
}

//main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="*schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  >
  <TextView android:id="@+id/dateAndTime"  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content"
    />
  <Button android:id="@+id/dateBtn"  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="Set the Date"
    />
  <Button android:id="@+id/timeBtn"  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="Set the Time"
    />
</LinearLayout>
```
Load Url to WebView

```
package app.test;

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

public class Test extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);        
        
        WebView wv = (WebView) findViewById(R.id.webview1);          
        wv.loadUrl("*www.google.com"); 
        
       
    }
    
    private class Callback extends WebViewClient {
      @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
      return(false);
    }
  }  
}

//main.xml

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

<WebView android:id="@+id/webview1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
    
</LinearLayout>
```
Create Option menu

```
package app.Test;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.ImageView;
import android.widget.LinearLayout;

public class appTest extends Activity {
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
  }

  public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.mainmenu, menu);
    return true;
  }

  public boolean onOptionsItemSelected(MenuItem item) {
    LinearLayout bkgr = (LinearLayout) findViewById(R.id.uilayout);
    final ImageView image = (ImageView) findViewById(R.id.ImageView01);

    AlertDialog.Builder builder = new AlertDialog.Builder(this);

    builder.setTitle("Pick an Image!")
        .setMessage("Please Select Image One or Image Two:")
        .setCancelable(false)
        .setPositiveButton("IMAGE 1",
            new DialogInterface.OnClickListener() {
              public void onClick(DialogInterface dialog, int id) {
                image.setImageResource(R.drawable.image1);
              }
            })

        .setNegativeButton("IMAGE 2",
            new DialogInterface.OnClickListener() {
              public void onClick(DialogInterface dialog, int id) {
                image.setImageResource(R.drawable.image2);
              }
            });

    switch (item.getItemId()) {
    case R.id.buttonone:
      image.setImageResource(R.drawable.image1);
      return true;
    case R.id.buttontwo:
      image.setImageResource(R.drawable.image2);
      return true;
    case R.id.buttonthree:
      bkgr.setBackgroundResource(R.color.background2);
      return true;
    case R.id.buttonfour:
      bkgr.setBackgroundResource(R.color.background);
      return true;
    case R.id.buttonfive:
      builder.show();
      return true;
    default:
      return super.onOptionsItemSelected(item);
    }
  }
}

//main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="*schemas.android.com/apk/res/android"
  android:id="@+id/uilayout"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@color/background">
    
  <ImageButton android:id="@+id/button_one"
          android:layout_width="wrap_content"
         android:layout_height="wrap_content"
          android:src="@drawable/button1"
          android:paddingTop="5px"
          android:background="#00000000">
  </ImageButton>
  
  <TextView  android:id="@+id/TextView01" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:text="Sample Text" 
        android:textColor="#CCCC77" 
        android:padding="12dip">
  </TextView>
  
  <ImageView  android:id="@+id/ImageView01" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:src="@drawable/image1">
  </ImageView>
  
</LinearLayout>


//mainmenu.xml
<?xml version="1.0" encoding="utf-8"?>

<menu xmlns:android="*schemas.android.com/apk/res/android">

    <item android:id="@+id/buttonone"
          android:icon="@drawable/image1icon"
          android:title="@string/showimage1" />
          
    <item android:id="@+id/buttontwo"
          android:icon="@drawable/image2icon"
          android:title="@string/showimage2" />
          
    <item android:id="@+id/buttonthree"
          android:icon="@drawable/menu3icon"
          android:title="@string/showwhite" />
          
    <item android:id="@+id/buttonfour"
          android:icon="@drawable/menu4icon"
          android:title="@string/showblack" />
          
    <item android:id="@+id/buttonfive"
          android:icon="@drawable/menu5icon"
          android:title="@string/showalert" />
          
</menu>
```
Google map view

```
import android.os.Bundle;
import android.view.View;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;

public class MapViewDemoActivity extends MapActivity
{
    private MapView mapView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.mapview);

        mapView = (MapView)findViewById(R.id.mapview);
    }

    public void myClickHandler(View target) {
        switch(target.getId()) {
        case R.id.zoomin:
            mapView.getController().zoomIn();
            break;
        case R.id.zoomout:
            mapView.getController().zoomOut();
            break;
        case R.id.sat:
            mapView.setSatellite(true);
            break;
        case R.id.street:
            mapView.setStreetView(true);
            break;
        case R.id.traffic:
            mapView.setTraffic(true);
            break;
        case R.id.normal:
            mapView.setSatellite(false);
            mapView.setStreetView(false);
            mapView.setTraffic(false);
            break;
        default:
          break;
        }

        mapView.postInvalidateDelayed(2000);
    }

    @Override
    protected boolean isLocationDisplayed() {
        return false;
    }

    @Override
    protected boolean isRouteDisplayed() {
        return false;
    }
}
<?xml version="1.0" encoding="utf-8"?>
<!-- This file is /res/layout/mapview.xml -->
<LinearLayout xmlns:android="*schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <LinearLayout xmlns:android="*schemas.android.com/apk/res/android"
        android:orientation="horizontal" android:layout_width="fill_parent"
        android:layout_height="wrap_content">

        <Button android:id="@+id/zoomin" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:text="+"
            android:onClick="myClickHandler" android:padding="12px" />

        <Button android:id="@+id/zoomout" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:text="-"
            android:onClick="myClickHandler" android:padding="12px" />

        <Button android:id="@+id/sat" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:text="Satellite"
            android:onClick="myClickHandler" android:padding="8px" />

        <Button android:id="@+id/street" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:text="Street"
            android:onClick="myClickHandler" android:padding="8px" />

        <Button android:id="@+id/traffic" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:text="Traffic"
            android:onClick="myClickHandler" android:padding="8px" />

        <Button android:id="@+id/normal" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:text="Normal"
            android:onClick="myClickHandler" android:padding="8px" />

    </LinearLayout>
     <com.google.android.maps.MapView android:id="@+id/mapview"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:clickable="true"
             android:apiKey="yourKey"
             />
</LinearLayout>
```
Using Spinner

```
package com.commonsware.android.selection;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;

public class SpinnerDemo extends Activity
  implements AdapterView.OnItemSelectedListener {
  TextView selection;
  String[] items={"lorem", "ipsum", "dolor", "sit", "amet",
          "consectetuer", "adipiscing", "elit", "morbi", "vel",
          "ligula", "vitae", "arcu", "aliquet", "mollis",
          "etiam", "vel", "erat", "placerat", "ante",
          "porttitor", "sodales", "pellentesque", "augue", "purus"};
  
  @Override
  public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    setContentView(R.layout.main);
    selection=(TextView)findViewById(R.id.selection);
    
    Spinner spin=(Spinner)findViewById(R.id.spinner);
    spin.setOnItemSelectedListener(this);
    
    ArrayAdapter<String> aa=new ArrayAdapter<String>(this,
                              android.R.layout.simple_spinner_item,
                              items);
    
    aa.setDropDownViewResource(
      android.R.layout.simple_spinner_dropdown_item);
    spin.setAdapter(aa);
  }
  
  public void onItemSelected(AdapterView<?> parent,
                                View v, int position, long id) {
    selection.setText(items[position]);
  }
  
  public void onNothingSelected(AdapterView<?> parent) {
    selection.setText("");
  }
}



//res\layout\main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="*schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  >
  <TextView
    android:id="@+id/selection"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    />
  <Spinner android:id="@+id/spinner"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:drawSelectorOnTop="true"
  />
</LinearLayout>
```
Using Gallery widget

```
package app.test;

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

import android.content.Context;
import android.content.res.TypedArray;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.Gallery;
import android.widget.ImageView;
import android.widget.Toast;

public class Test extends Activity {  
  //---the images to display---
    Integer[] imageIDs = {
            R.drawable.icon,
            R.drawable.icon,
            R.drawable.icon,
            R.drawable.icon,
            R.drawable.icon,
            R.drawable.icon,
            R.drawable.icon
    };
    
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        Gallery gallery = (Gallery) findViewById(R.id.gallery1);
        
        gallery.setAdapter(new ImageAdapter(this));        
        gallery.setOnItemClickListener(new OnItemClickListener() 
        {
            public void onItemClick(AdapterView<?> parent, View v, int position, long id) 
            {                
                Toast.makeText(getBaseContext(), 
                        "pic" + (position + 1) + " selected", 
                        Toast.LENGTH_SHORT).show();
                ImageView imageView = (ImageView) findViewById(R.id.image1);                
                imageView.setImageResource(imageIDs[position]);
            }
        });
    }
    
    public class ImageAdapter extends BaseAdapter 
    {
        private Context context;
        private int itemBackground;
 
        public ImageAdapter(Context c) 
        {
            context = c;
            //---setting the style---
            TypedArray a = obtainStyledAttributes(R.styleable.Gallery1);
            itemBackground = a.getResourceId(
                R.styleable.Gallery1_android_galleryItemBackground, 0);
            a.recycle();                    
        }
 
        //---returns the number of images---
        public int getCount() {
            return imageIDs.length;
        } 
        
        //---returns the ID of an item--- 
        public Object getItem(int position) {
            return position;
        }            
        
        //---returns the ID of an item---         
        public long getItemId(int position) {
            return position;
        }
  
        //---returns an ImageView view---
        public View getView(int position, View convertView, ViewGroup parent) {
            ImageView imageView = new ImageView(context);
            imageView.setImageResource(imageIDs[position]);
            imageView.setScaleType(ImageView.ScaleType.FIT_XY);
            imageView.setLayoutParams(new Gallery.LayoutParams(150, 120));
            imageView.setBackgroundResource(itemBackground);
            return imageView;
        }
    }    
}

//main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="*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="Images of San Francisco" /> 
 
<Gallery
    android:id="@+id/gallery1"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" />          

<ImageView
    android:id="@+id/image1"
    android:layout_width="320px" 
    android:layout_height="250px"
    android:scaleType="fitXY" />
    
</LinearLayout>
```

*Android Books*
1) Android Application Development (with Kitkat Support), Black Book by Pradeep Kothari
2) Android Programming: Pushing the Limits by Erik Hellman
3) Professional Android 4 Application Development (Wrox) by Reto Meier
4) Android Programming: The Big Nerd Ranch Guide by Bill Phillips and Chris Stewart
5) Beginning Android 4 Application Development by Wei-Meng Lee
6) Android Application Development Cookbook: 93 Recipes for Building Winning Apps by Wei-Meng Lee
7) Android Programming Unleashed by B.M. Harwani
8) Programming Android by G. Blake Meike
9) Embedded Android: Porting, Extending, and Customizing by Karim Yaghmour
10) Android How to Program by Paul Deitel and Harvey M Deitel
11) Android Developer Tools Essentials by Mike Wolfson and Donn Felker
12) Android Studio Development Essentials by Neil Smyth


----------



## D@rekills4 (May 25, 2016)

This is Android app development, not development of Android itself, you might wanna change the title.

Apart from that good post, the demos would be really helpful.


----------



## sujansimkhada (May 26, 2016)

can you please provide me face detection code in java


----------



## JGuru (Jun 3, 2016)

You can write a Face detection system in Java using OpenCV Real Time Face Detection using OpenCV with Java - All

Read the book  OpenCV 3.0 Computer Vision with Java by Daniel Lélis Baggio OpenCV 3.0 Computer Vision with Java | PACKT Book

 This book comes with complete code for writing a Face detection system in Java using OpenCV


----------



## shanmorkel1685 (Jun 6, 2016)

Is Java is necessary to learn android app development. I am interest to learn Android but i didn't know how to start?


----------



## JGuru (Jun 8, 2016)

You can read *Head First Java, Second Edition* Head First Labs from O'Reilly Media, Inc. :: Head First Java, Second Edition  It's a very good introductory book on 
Java . If you already know C/C++ it will be a cake walk!!


----------



## williamsbarbara (Jul 1, 2016)

Really great........I have been looking for it. I m going to develop Android app. Thanks
Best Android Development Company in Bareilly


----------



## JGuru (Jul 13, 2016)

You don't need to know Java programming to learn Android. But knowledge of Java programming will make it easier to learn Android programming.


----------



## Shawndev (Jun 9, 2017)

JGuru said:


> *Introduction to Android programming*
> Lets get started programming in Android!!. I give some android useful examples  with complete source code.  I'm not a android programmer. But learning android is easy for a Java programmer!!
> Let's start !!
> Threads Handler Demo
> ...



It is very useful information to me as i am at learning phase of android programming. I quoted the best part of the article


----------

