Android Tutorial - Core Class : Application

 Application Widget

//src\apt\tutorial\AlarmActivity.java
package apt.tutorial;

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

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



//src\apt\tutorial\AppWidget.java
package apt.tutorial;

import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;

public class AppWidget extends AppWidgetProvider {
  @Override
  public void onUpdate(Context ctxt,
                        AppWidgetManager mgr,
                        int[] appWidgetIds) {
    ctxt.startService(new Intent(ctxt, WidgetService.class));
  }
}



//src\apt\tutorial\DetailForm.java
package apt.tutorial;

import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;

public class DetailForm extends Activity {
  EditText name=null;
  EditText address=null;
  EditText notes=null;
  EditText feed=null;
  RadioGroup types=null;
  RestaurantHelper helper=null;
  String restaurantId=null;
  TextView location=null;
  LocationManager locMgr=null;
  double latitude=0.0d;
  double longitude=0.0d;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.detail_form);
    
    locMgr=(LocationManager)getSystemService(LOCATION_SERVICE);
    helper=new RestaurantHelper(this);
    
    name=(EditText)findViewById(R.id.name);
    address=(EditText)findViewById(R.id.addr);
    notes=(EditText)findViewById(R.id.notes);
    types=(RadioGroup)findViewById(R.id.types);
    feed=(EditText)findViewById(R.id.feed);
    location=(TextView)findViewById(R.id.location);
    
    restaurantId=getIntent().getStringExtra(LunchList.ID_EXTRA);
    
    if (restaurantId!=null) {
      load();
    }
  }
  
  @Override
  public void onPause() {
    save();
    
    super.onPause();
  }
  
  @Override
  public void onDestroy() {
    helper.close();
    locMgr.removeUpdates(onLocationChange);
    
    super.onDestroy();
  }
  
  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    new MenuInflater(this).inflate(R.menu.details_option, menu);

    return(super.onCreateOptionsMenu(menu));
  }

  @Override
  public boolean onPrepareOptionsMenu(Menu menu) {
    if (restaurantId==null) {
      menu.findItem(R.id.location).setEnabled(false);
      menu.findItem(R.id.map).setEnabled(false);
    }

    return(super.onPrepareOptionsMenu(menu));
  }
  
  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId()==R.id.feed) {
      if (isNetworkAvailable()) {
        Intent i=new Intent(this, FeedActivity.class);
        
        i.putExtra(FeedActivity.FEED_URL, feed.getText().toString());
        startActivity(i);
      }
      else {
        Toast
          .makeText(this, "Sorry, the Internet is not available",
                    Toast.LENGTH_LONG)
          .show();
      }
    
      return(true);
    }
    else if (item.getItemId()==R.id.location) {
      locMgr.requestLocationUpdates(LocationManager.GPS_PROVIDER,
                                    0, 0, onLocationChange);
      
      return(true);
    }
    else if (item.getItemId()==R.id.map) {
      Intent i=new Intent(this, RestaurantMap.class);
      
      i.putExtra(RestaurantMap.EXTRA_LATITUDE, latitude);
      i.putExtra(RestaurantMap.EXTRA_LONGITUDE, longitude);
      i.putExtra(RestaurantMap.EXTRA_NAME, name.getText().toString());
      
      startActivity(i);
      
      return(true);
    }

    return(super.onOptionsItemSelected(item));
  }
  
  private boolean isNetworkAvailable() {
    ConnectivityManager cm=(ConnectivityManager)getSystemService(CONNECTIVITY_SERVICE);
    NetworkInfo info=cm.getActiveNetworkInfo();
    
    return(info!=null);
  }
  
  private void load() {
    Cursor c=helper.getById(restaurantId);

    c.moveToFirst();    
    name.setText(helper.getName(c));
    address.setText(helper.getAddress(c));
    notes.setText(helper.getNotes(c));
    feed.setText(helper.getFeed(c));
    
    if (helper.getType(c).equals("sit_down")) {
      types.check(R.id.sit_down);
    }
    else if (helper.getType(c).equals("take_out")) {
      types.check(R.id.take_out);
    }
    else {
      types.check(R.id.delivery);
    }
    
    latitude=helper.getLatitude(c);
    longitude=helper.getLongitude(c);
    
    location.setText(String.valueOf(latitude)
                      +", "
                      +String.valueOf(longitude));
    
    c.close();
  }
  
  private void save() {
    if (name.getText().toString().length()>0) {
      String type=null;
      
      switch (types.getCheckedRadioButtonId()) {
        case R.id.sit_down:
          type="sit_down";
          break;
        case R.id.take_out:
          type="take_out";
          break;
        default:
          type="delivery";
          break;
      }
  
      if (restaurantId==null) {
        helper.insert(name.getText().toString(),
                      address.getText().toString(), type,
                      notes.getText().toString(),
                      feed.getText().toString());
      }
      else {
        helper.update(restaurantId, name.getText().toString(),
                      address.getText().toString(), type,
                      notes.getText().toString(),
                      feed.getText().toString());
      }
    }
  }
  
  LocationListener onLocationChange=new LocationListener() {
    public void onLocationChanged(Location fix) {
      helper.updateLocation(restaurantId, fix.getLatitude(),
                            fix.getLongitude());
      location.setText(String.valueOf(fix.getLatitude())
                      +", "
                      +String.valueOf(fix.getLongitude()));
      locMgr.removeUpdates(onLocationChange);
      
      Toast
        .makeText(DetailForm.this, "Location saved",
                  Toast.LENGTH_LONG)
        .show();
    }
    
    public void onProviderDisabled(String provider) {
      // required for interface, not used
    }
    
    public void onProviderEnabled(String provider) {
      // required for interface, not used
    }
    
    public void onStatusChanged(String provider, int status,
                                  Bundle extras) {
      // required for interface, not used
    }
  };
}



//src\apt\tutorial\EditPreferences.java
package apt.tutorial;

import android.app.Activity;
import android.content.ComponentName;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceManager;

public class EditPreferences extends PreferenceActivity {
  SharedPreferences prefs=null;
  
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    
    addPreferencesFromResource(R.xml.preferences);
  }
  
  @Override
  public void onResume() {
    super.onResume();
    
    prefs=PreferenceManager.getDefaultSharedPreferences(this);
    prefs.registerOnSharedPreferenceChangeListener(onChange);
  }
  
  @Override
  public void onPause() {
    prefs.unregisterOnSharedPreferenceChangeListener(onChange);
    
    super.onPause();
  }
  
  SharedPreferences.OnSharedPreferenceChangeListener onChange=
    new SharedPreferences.OnSharedPreferenceChangeListener() {
    public void onSharedPreferenceChanged(SharedPreferences prefs,
                                          String key) {
      if ("alarm".equals(key)) {
        boolean enabled=prefs.getBoolean(key, false);
        int flag=(enabled ?
                    PackageManager.COMPONENT_ENABLED_STATE_ENABLED :
                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
        ComponentName component=new ComponentName(EditPreferences.this,
                                                  OnBootReceiver.class);
        
        getPackageManager()
          .setComponentEnabledSetting(component,
                                      flag,
                                      PackageManager.DONT_KILL_APP);
          
        if (enabled) {
          OnBootReceiver.setAlarm(EditPreferences.this);
        }
        else {
          OnBootReceiver.cancelAlarm(EditPreferences.this);
        }
      }
      else if ("alarm_time".equals(key)) {
        OnBootReceiver.cancelAlarm(EditPreferences.this);
        OnBootReceiver.setAlarm(EditPreferences.this);
      }
    }
  };
}



//src\apt\tutorial\FeedActivity.java
package apt.tutorial;

import android.app.AlertDialog;
import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import org.mcsoxford.rss.RSSItem;
import org.mcsoxford.rss.RSSFeed;

public class FeedActivity extends ListActivity {
  public static final String FEED_URL="apt.tutorial.FEED_URL";
  private InstanceState state=null;
  
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    
    state=(InstanceState)getLastNonConfigurationInstance();
    
    if (state==null) {
      state=new InstanceState();
      state.handler=new FeedHandler(this);
      
      Intent i=new Intent(this, FeedService.class);
      
      i.putExtra(FeedService.EXTRA_URL,
                 getIntent().getStringExtra(FEED_URL));
      i.putExtra(FeedService.EXTRA_MESSENGER,
                 new Messenger(state.handler));
      
      startService(i);
    }
    else {
      if (state.handler!=null) {
        state.handler.attach(this);
      }
      
      if (state.feed!=null) {
        setFeed(state.feed);
      }
    }
  }
  
  @Override
  public Object onRetainNonConfigurationInstance() {
    if (state.handler!=null) {
      state.handler.detach();
    }
    
    return(state);
  }
  
  private void setFeed(RSSFeed feed) {
    state.feed=feed;
    setListAdapter(new FeedAdapter(feed));
  }
  
  private void goBlooey(Throwable t) {
    AlertDialog.Builder builder=new AlertDialog.Builder(this);
    
    builder
      .setTitle("Exception!")
      .setMessage(t.toString())
      .setPositiveButton("OK", null)
      .show();
  }
  
  private static class InstanceState {
    RSSFeed feed=null;
    FeedHandler handler=null;
  }
  
  private class FeedAdapter extends BaseAdapter {
    RSSFeed feed=null;
    
    FeedAdapter(RSSFeed feed) {
      super();
      
      this.feed=feed;
    }
    
    @Override
    public int getCount() {
      return(feed.getItems().size());
    }
    
    @Override
    public Object getItem(int position) {
      return(feed.getItems().get(position));
    }
    
    @Override
    public long getItemId(int position) {
      return(position);
    }
    
    @Override
    public View getView(int position, View convertView,
                        ViewGroup parent) {
      View row=convertView;
      
      if (row==null) {                          
        LayoutInflater inflater=getLayoutInflater();
        
        row=inflater.inflate(android.R.layout.simple_list_item_1,
                             parent, false);
      }
      
      RSSItem item=(RSSItem)getItem(position);
      
      ((TextView)row).setText(item.getTitle());
      
      return(row);
    }
  }
  
  private static class FeedHandler extends Handler {
    FeedActivity activity=null;
    
    FeedHandler(FeedActivity activity) {
      attach(activity);
    }
    
    void attach(FeedActivity activity) {
      this.activity=activity;
    }
    
    void detach() {
      this.activity=null;
    }
    
    @Override
    public void handleMessage(Message msg) {
      if (msg.arg1==RESULT_OK) {
        activity.setFeed((RSSFeed)msg.obj);
      }
      else {
        activity.goBlooey((Exception)msg.obj);
      }
    }
  };
}



//src\apt\tutorial\FeedService.java
package apt.tutorial;

import android.app.Activity;
import android.app.IntentService;
import android.content.Intent;
import android.os.Message;
import android.os.Messenger;
import android.util.Log;
import org.mcsoxford.rss.RSSItem;
import org.mcsoxford.rss.RSSFeed;
import org.mcsoxford.rss.RSSReader;

public class FeedService extends IntentService {
  public static final String EXTRA_URL="apt.tutorial.EXTRA_URL";
  public static final String EXTRA_MESSENGER="apt.tutorial.EXTRA_MESSENGER";

  public FeedService() {
    super("FeedService");
  }
  
  @Override
  public void onHandleIntent(Intent i) {
    RSSReader reader=new RSSReader();
    Messenger messenger=(Messenger)i.getExtras().get(EXTRA_MESSENGER);
    Message msg=Message.obtain();
    
    try {
      RSSFeed result=reader.load(i.getStringExtra(EXTRA_URL));
      
      msg.arg1=Activity.RESULT_OK;
      msg.obj=result;
    }
    catch (Exception e) {
      Log.e("LunchList", "Exception parsing feed", e);
      msg.arg1=Activity.RESULT_CANCELED;
      msg.obj=e;
    }
    
    try {
      messenger.send(msg);
    }
    catch (Exception e) {
      Log.w("LunchList", "Exception sending results to activity", e);
    }
  }
}




//src\apt\tutorial\LunchList.java
package apt.tutorial;

import android.app.ListActivity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.LayoutInflater;
import android.widget.AdapterView;
import android.widget.CursorAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

public class LunchList extends ListActivity {
  public final static String ID_EXTRA="apt.tutorial._ID";
  Cursor model=null;
  RestaurantAdapter adapter=null;
  RestaurantHelper helper=null;
  SharedPreferences prefs=null;
  
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    
    helper=new RestaurantHelper(this);
    prefs=PreferenceManager.getDefaultSharedPreferences(this);
    initList();
    prefs.registerOnSharedPreferenceChangeListener(prefListener);
  }
  
  @Override
  public void onDestroy() {
    super.onDestroy();
    
    helper.close();
  }
  
  @Override
  public void onListItemClick(ListView list, View view,
                              int position, long id) {
    Intent i=new Intent(LunchList.this, DetailForm.class);

    i.putExtra(ID_EXTRA, String.valueOf(id));
    startActivity(i);
  }
  
  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    new MenuInflater(this).inflate(R.menu.option, menu);

    return(super.onCreateOptionsMenu(menu));
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId()==R.id.add) {
      startActivity(new Intent(LunchList.this, DetailForm.class));
      
      return(true);
    }
    else if (item.getItemId()==R.id.prefs) {
      startActivity(new Intent(this, EditPreferences.class));
    
      return(true);
    }

    return(super.onOptionsItemSelected(item));
  }
  
  private void initList() {
    if (model!=null) {
      stopManagingCursor(model);
      model.close();
    }
    
    model=helper.getAll(prefs.getString("sort_order", "name"));
    startManagingCursor(model);
    adapter=new RestaurantAdapter(model);
    setListAdapter(adapter);
  }
  
  private SharedPreferences.OnSharedPreferenceChangeListener prefListener=
   new SharedPreferences.OnSharedPreferenceChangeListener() {
    public void onSharedPreferenceChanged(SharedPreferences sharedPrefs,
                                          String key) {
      if (key.equals("sort_order")) {
        initList();
      }
    }
  };
  
  class RestaurantAdapter extends CursorAdapter {
    RestaurantAdapter(Cursor c) {
      super(LunchList.this, c);
    }
    
    @Override
    public void bindView(View row, Context ctxt,
                         Cursor c) {
      RestaurantHolder holder=(RestaurantHolder)row.getTag();
      
      holder.populateFrom(c, helper);
    }
    
    @Override
    public View newView(Context ctxt, Cursor c,
                         ViewGroup parent) {
      LayoutInflater inflater=getLayoutInflater();
      View row=inflater.inflate(R.layout.row, parent, false);
      RestaurantHolder holder=new RestaurantHolder(row);
      
      row.setTag(holder);
      
      return(row);
    }
  }
  
  static class RestaurantHolder {
    private TextView name=null;
    private TextView address=null;
    private ImageView icon=null;
    
    RestaurantHolder(View row) {
      name=(TextView)row.findViewById(R.id.title);
      address=(TextView)row.findViewById(R.id.address);
      icon=(ImageView)row.findViewById(R.id.icon);
    }
    
    void populateFrom(Cursor c, RestaurantHelper helper) {
      name.setText(helper.getName(c));
      address.setText(helper.getAddress(c));
  
      if (helper.getType(c).equals("sit_down")) {
        icon.setImageResource(R.drawable.ball_red);
      }
      else if (helper.getType(c).equals("take_out")) {
        icon.setImageResource(R.drawable.ball_yellow);
      }
      else {
        icon.setImageResource(R.drawable.ball_green);
      }
    }
  }
}



//src\apt\tutorial\OnAlarmReceiver.java
package apt.tutorial;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;

public class OnAlarmReceiver extends BroadcastReceiver {
  private static final int NOTIFY_ME_ID=1337;

  @Override
  public void onReceive(Context ctxt, Intent intent) {
    SharedPreferences prefs=PreferenceManager.getDefaultSharedPreferences(ctxt);
    boolean useNotification=prefs.getBoolean("use_notification",
                                             true);

    if (useNotification) {
      NotificationManager mgr=
        (NotificationManager)ctxt.getSystemService(Context.NOTIFICATION_SERVICE);
      Notification note=new Notification(R.drawable.stat_notify_chat,
                                          "It's time for lunch!",
                                          System.currentTimeMillis());
      PendingIntent i=PendingIntent.getActivity(ctxt, 0,
                              new Intent(ctxt, AlarmActivity.class),
                                                0);
      
      note.setLatestEventInfo(ctxt, "LunchList",
                              "It's time for lunch! Aren't you hungry?",
                              i);
      note.flags|=Notification.FLAG_AUTO_CANCEL;
      
      mgr.notify(NOTIFY_ME_ID, note);
    }
    else {
      Intent i=new Intent(ctxt, AlarmActivity.class);
      
      i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
      
      ctxt.startActivity(i);
    }
  }
}



//src\apt\tutorial\OnBootReceiver.java
package apt.tutorial;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import java.util.Calendar;

public class OnBootReceiver extends BroadcastReceiver {
  public static void setAlarm(Context ctxt) {
    AlarmManager mgr=(AlarmManager)ctxt.getSystemService(Context.ALARM_SERVICE);
    Calendar cal=Calendar.getInstance();
    SharedPreferences prefs=PreferenceManager.getDefaultSharedPreferences(ctxt);
    String time=prefs.getString("alarm_time", "12:00");
    
    cal.set(Calendar.HOUR_OF_DAY, TimePreference.getHour(time));
    cal.set(Calendar.MINUTE, TimePreference.getMinute(time));
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);
    
    if (cal.getTimeInMillis()<System.currentTimeMillis()) {
      cal.add(Calendar.DAY_OF_YEAR, 1);
    }
    
android.util.Log.e("***OnBootReceiver", android.text.format.DateFormat.format("MM/dd/yy h:mmaa", cal).toString());
    
    mgr.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),
                      AlarmManager.INTERVAL_DAY,
                      getPendingIntent(ctxt));
  }
  
  public static void cancelAlarm(Context ctxt) {
    AlarmManager mgr=(AlarmManager)ctxt.getSystemService(Context.ALARM_SERVICE);

    mgr.cancel(getPendingIntent(ctxt));
  }
  
  private static PendingIntent getPendingIntent(Context ctxt) {
    Intent i=new Intent(ctxt, OnAlarmReceiver.class);
    
    return(PendingIntent.getBroadcast(ctxt, 0, i, 0));
  }
  
  @Override
  public void onReceive(Context ctxt, Intent intent) {
android.util.Log.e("****OnBootReceiver", "got here");    
    setAlarm(ctxt);
  }
}



//src\apt\tutorial\RestaurantHelper.java
package apt.tutorial;

import android.content.Context;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;

class RestaurantHelper extends SQLiteOpenHelper {
  private static final String DATABASE_NAME="lunchlist.db";
  private static final int SCHEMA_VERSION=3;
  
  public RestaurantHelper(Context context) {
    super(context, DATABASE_NAME, null, SCHEMA_VERSION);
  }
  
  @Override
  public void onCreate(SQLiteDatabase db) {
    db.execSQL("CREATE TABLE restaurants (_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, address TEXT, type TEXT, notes TEXT, feed TEXT, lat REAL, lon REAL);");
  }

  @Override
  public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    if (oldVersion<2) {
      db.execSQL("ALTER TABLE restaurants ADD COLUMN feed TEXT");
    }
    
    if (oldVersion<3) {
      db.execSQL("ALTER TABLE restaurants ADD COLUMN lat REAL");
      db.execSQL("ALTER TABLE restaurants ADD COLUMN lon REAL");
    }
  }

  public Cursor getAll(String orderBy) {
    return(getReadableDatabase()
            .rawQuery("SELECT _id, name, address, type, notes, lat, lon FROM restaurants ORDER BY "+orderBy,
                      null));
  }
  
  public Cursor getById(String id) {
    String[] args={id};

    return(getReadableDatabase()
            .rawQuery("SELECT _id, name, address, type, notes, feed, lat, lon FROM restaurants WHERE _ID=?",
                      args));
  }
  
  public void insert(String name, String address,
                     String type, String notes,
                     String feed) {
    ContentValues cv=new ContentValues();
          
    cv.put("name", name);
    cv.put("address", address);
    cv.put("type", type);
    cv.put("notes", notes);
    cv.put("feed", feed);
    
    getWritableDatabase().insert("restaurants", "name", cv);
  }
  
  public void update(String id, String name, String address,
                     String type, String notes, String feed) {
    ContentValues cv=new ContentValues();
    String[] args={id};
    
    cv.put("name", name);
    cv.put("address", address);
    cv.put("type", type);
    cv.put("notes", notes);
    cv.put("feed", feed);
    
    getWritableDatabase().update("restaurants", cv, "_ID=?",
                                 args);
  }
  
  public void updateLocation(String id, double lat, double lon) {
    ContentValues cv=new ContentValues();
    String[] args={id};
    
    cv.put("lat", lat);
    cv.put("lon", lon);
    
    getWritableDatabase().update("restaurants", cv, "_ID=?",
                                 args);
  }
  
  public String getName(Cursor c) {
    return(c.getString(1));
  }
  
  public String getAddress(Cursor c) {
    return(c.getString(2));
  }
  
  public String getType(Cursor c) {
    return(c.getString(3));
  }
  
  public String getNotes(Cursor c) {
    return(c.getString(4));
  }
  
  public String getFeed(Cursor c) {
    return(c.getString(5));
  }
  
  public double getLatitude(Cursor c) {
    return(c.getDouble(6));
  }
  
  public double getLongitude(Cursor c) {
    return(c.getDouble(7));
  }
}



//src\apt\tutorial\RestaurantMap.java
package apt.tutorial;

import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.widget.Toast;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.OverlayItem;

public class RestaurantMap extends MapActivity {
  public static final String EXTRA_LATITUDE="apt.tutorial.EXTRA_LATITUDE";
  public static final String EXTRA_LONGITUDE="apt.tutorial.EXTRA_LONGITUDE";
  public static final String EXTRA_NAME="apt.tutorial.EXTRA_NAME";
  private MapView map=null;
  
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.map);
    
    double lat=getIntent().getDoubleExtra(EXTRA_LATITUDE, 0);
    double lon=getIntent().getDoubleExtra(EXTRA_LONGITUDE, 0);
    
    map=(MapView)findViewById(R.id.map);
    
    map.getController().setZoom(17);
    
    GeoPoint status=new GeoPoint((int)(lat*1000000.0),
                                  (int)(lon*1000000.0));
    
    map.getController().setCenter(status);
    map.setBuiltInZoomControls(true);
    
    Drawable marker=getResources().getDrawable(R.drawable.marker);
    
    marker.setBounds(0, 0, marker.getIntrinsicWidth(),
                      marker.getIntrinsicHeight());
    
    map
      .getOverlays()
      .add(new RestaurantOverlay(marker, status,
                                  getIntent().getStringExtra(EXTRA_NAME)));
  }
  
   @Override
  protected boolean isRouteDisplayed() {
    return(false);
  }
    
  private class RestaurantOverlay extends ItemizedOverlay<OverlayItem> {
    private OverlayItem item=null;
    
    public RestaurantOverlay(Drawable marker, GeoPoint point,
                              String name) {
      super(marker);
      
      boundCenterBottom(marker);
      
      item=new OverlayItem(point, name, name);

      populate();
    }
    
    @Override
    protected OverlayItem createItem(int i) {
      return(item);
    }
     
    @Override
    protected boolean onTap(int i) {
      Toast.makeText(RestaurantMap.this,
                      item.getSnippet(),
                      Toast.LENGTH_SHORT).show();
      
      return(true);
    }
    
    @Override
    public int size() {
      return(1);
    }
  }
}



//src\apt\tutorial\TimePreference.java
package apt.tutorial;

import android.content.Context;
import android.content.res.TypedArray;
import android.preference.DialogPreference;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TimePicker;

public class TimePreference extends DialogPreference {
  private int lastHour=0;
  private int lastMinute=0;
  private TimePicker picker=null;
  
  public static int getHour(String time) {
    String[] pieces=time.split(":");
    
    return(Integer.parseInt(pieces[0]));
  }

  public static int getMinute(String time) {
    String[] pieces=time.split(":");
    
    return(Integer.parseInt(pieces[1]));
  }

  public TimePreference(Context ctxt, AttributeSet attrs) {
    super(ctxt, attrs);
    
    setPositiveButtonText("Set");
    setNegativeButtonText("Cancel");
  }

  @Override
  protected View onCreateDialogView() {
    picker=new TimePicker(getContext());
    
    return(picker);
  }
  
  @Override
  protected void onBindDialogView(View v) {
    super.onBindDialogView(v);
    
    picker.setCurrentHour(lastHour);
    picker.setCurrentMinute(lastMinute);
  }
  
  @Override
  protected void onDialogClosed(boolean positiveResult) {
    super.onDialogClosed(positiveResult);

    if (positiveResult) {
      lastHour=picker.getCurrentHour();
      lastMinute=picker.getCurrentMinute();
      
      String time=String.valueOf(lastHour)+":"+String.valueOf(lastMinute);
      
      if (callChangeListener(time)) {
        persistString(time);
      }
    }
  }

  @Override
  protected Object onGetDefaultValue(TypedArray a, int index) {
    return(a.getString(index));
  }

  @Override
  protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
    String time=null;
    
    if (restoreValue) {
      if (defaultValue==null) {
        time=getPersistedString("00:00");
      }
      else {
        time=getPersistedString(defaultValue.toString());
      }
    }
    else {
      time=defaultValue.toString();
    }
    
    lastHour=getHour(time);
    lastMinute=getMinute(time);
  }
}



//src\apt\tutorial\WidgetService.java
package apt.tutorial;

import android.app.IntentService;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.widget.RemoteViews;

public class WidgetService extends IntentService {
  public WidgetService() {
    super("WidgetService");
  }
    
  @Override
  public void onHandleIntent(Intent intent) {
    ComponentName me=new ComponentName(this, AppWidget.class);
    RemoteViews updateViews=new RemoteViews("apt.tutorial",
                                            R.layout.widget);
    RestaurantHelper helper=new RestaurantHelper(this);
    AppWidgetManager mgr=AppWidgetManager.getInstance(this);
    
    try {
      Cursor c=helper
                .getReadableDatabase()
                .rawQuery("SELECT COUNT(*) FROM restaurants", null);
      
      c.moveToFirst();
      
      int count=c.getInt(0);
      
      c.close();
      
      if (count>0) {
        int offset=(int)(count*Math.random());
        String args[]={String.valueOf(offset)};
        
        c=helper
            .getReadableDatabase()
            .rawQuery("SELECT _ID, name FROM restaurants LIMIT 1 OFFSET ?", args);
        c.moveToFirst();
        updateViews.setTextViewText(R.id.name, c.getString(1));
        
        Intent i=new Intent(this, DetailForm.class);
        
        i.putExtra(LunchList.ID_EXTRA, c.getString(0));
        
        PendingIntent pi=PendingIntent.getActivity(this, 0, i,
                                                    PendingIntent.FLAG_UPDATE_CURRENT);
        
        updateViews.setOnClickPendingIntent(R.id.name, pi);
        
        c.close();
      }
      else {
        updateViews.setTextViewText(R.id.title,
                                    this.getString(R.string.empty));
      }
    }
    finally {
      helper.close();
    }
    
    Intent i=new Intent(this, WidgetService.class);
    PendingIntent pi=PendingIntent.getService(this, 0, i, 0);
      
    updateViews.setOnClickPendingIntent(R.id.next, pi);
    mgr.updateAppWidget(me, updateViews);
  }
}



//
//res\xml\preferences.xml
<PreferenceScreen
  xmlns:android="http://schemas.android.com/apk/res/android">
  <ListPreference
    android:key="sort_order"
    android:title="Sort Order"
    android:summary="Choose the order the list uses"
    android:entries="@array/sort_names"
    android:entryValues="@array/sort_clauses"
    android:dialogTitle="Choose a sort order" />
  <CheckBoxPreference
    android:key="alarm"
    android:title="Sound a Lunch Alarm"
    android:summary="Check if you want to know when it is time for lunch" />
  <apt.tutorial.TimePreference
    android:key="alarm_time"
    android:title="Lunch Alarm Time"
    android:defaultValue="12:00"
    android:summary="Set your desired time for the lunch alarm"
    android:dependency="alarm" />
  <CheckBoxPreference
    android:key="use_notification"
    android:title="Use a Notification"
    android:defaultValue="true"
    android:summary="Check if you want a status bar icon at lunchtime, or uncheck for a full-screen notice"
    android:dependency="alarm" />
</PreferenceScreen>



//res\xml\widget_provider.xml
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
   android:minWidth="300dip"
   android:minHeight="79dip"
   android:updatePeriodMillis="1800000"
   android:initialLayout="@layout/widget"
/>



//
//res\values\arrays.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
  <string-array name="sort_names">
    <item>By Name, Ascending</item>
    <item>By Name, Descending</item>
    <item>By Type</item>
    <item>By Address, Ascending</item>
    <item>By Address, Descending</item>
  </string-array>
  <string-array name="sort_clauses">
    <item>name ASC</item>
    <item>name DESC</item>
    <item>type, name ASC</item>
    <item>address ASC</item>
    <item>address DESC</item>
  </string-array>
</resources>



//res\values\strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">LunchList</string>
    <string name="empty">No restaurants!</string>
</resources>



//
//res\menu\details_option.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:id="@+id/feed"
    android:title="RSS Feed"
    android:icon="@drawable/ic_menu_friendslist"
  />
  <item android:id="@+id/location"
    android:title="Save Location"
    android:icon="@drawable/ic_menu_compass"
  />
  <item android:id="@+id/map"
    android:title="Show on Map"
    android:icon="@drawable/ic_menu_mapmode"
  />
</menu>



//res\menu\option.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:id="@+id/add"
    android:title="Add"
    android:icon="@drawable/ic_menu_add"
  />
  <item android:id="@+id/prefs"
    android:title="Settings"
    android:icon="@drawable/ic_menu_preferences"
  />
</menu>



//
//res\layout-land\detail_form.xml
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:stretchColumns="2"
  >
  <TableRow>
    <TextView android:text="Name:" />
    <EditText android:id="@+id/name"
      android:layout_span="2"
    />
  </TableRow>
  <TableRow>
    <TextView android:text="Address:" />
    <EditText android:id="@+id/addr"
      android:layout_span="2"
    />
  </TableRow>
  <TableRow>
    <TextView android:text="Type:" />
    <RadioGroup android:id="@+id/types">
      <RadioButton android:id="@+id/take_out"
        android:text="Take-Out"
      />
      <RadioButton android:id="@+id/sit_down"
        android:text="Sit-Down"
      />
      <RadioButton android:id="@+id/delivery"
        android:text="Delivery"
      />
    </RadioGroup>
    <LinearLayout android:orientation="vertical">
      <EditText android:id="@+id/notes"
        android:singleLine="false"
        android:gravity="top"
        android:lines="2"
        android:scrollHorizontally="false"
        android:maxLines="2"
        android:maxWidth="140sp"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:hint="Notes"
      />
      <EditText android:id="@+id/feed"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:hint="Feed URL"
      />
      <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        >
        <TextView android:text="Location:"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
        />
        <TextView android:id="@+id/location"
          android:text="(not set)"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
        />
      </LinearLayout>
    </LinearLayout>
  </TableRow>
</TableLayout>



//
//res\layout\alarm.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="It's time for lunch!"
  android:textSize="30sp"
  android:textStyle="bold"
/>



//res\layout\detail_form.xml
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:stretchColumns="1"
  >
  <TableRow>
    <TextView android:text="Name:" />
    <EditText android:id="@+id/name" />
  </TableRow>
  <TableRow>
    <TextView android:text="Address:" />
    <EditText android:id="@+id/addr" />
  </TableRow>
  <TableRow>
    <TextView android:text="Type:" />
    <RadioGroup android:id="@+id/types">
      <RadioButton android:id="@+id/take_out"
        android:text="Take-Out"
      />
      <RadioButton android:id="@+id/sit_down"
        android:text="Sit-Down"
      />
      <RadioButton android:id="@+id/delivery"
        android:text="Delivery"
      />
    </RadioGroup>
  </TableRow>
  <TableRow>
    <TextView android:text="Location:" />
    <TextView android:id="@+id/location" android:text="(not set)" />
  </TableRow>
  <EditText android:id="@+id/notes"
    android:singleLine="false"
    android:gravity="top"
    android:lines="2"
    android:scrollHorizontally="false"
    android:maxLines="2"
    android:maxWidth="200sp"
    android:layout_span="2"
    android:hint="Notes"
    android:layout_marginTop="4dip"
  />
  <EditText android:id="@+id/feed"
    android:layout_span="2"
    android:hint="Feed URL"
  />
</TableLayout>



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



//res\layout\map.xml
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.maps.MapView
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/map"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:apiKey="00yHj0k7_7vxbuQ9zwyXI4bNMJrAjYrJ9KKHgbQ"
  android:clickable="true" />



//res\layout\row.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:orientation="horizontal"
  android:padding="4dip"
  >
  <ImageView android:id="@+id/icon"
    android:layout_width="wrap_content"
    android:layout_height="fill_parent"
    android:layout_alignParentTop="true"
    android:layout_alignParentBottom="true"
    android:layout_marginRight="4dip"
  />
  <LinearLayout
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    >  
    <TextView android:id="@+id/title"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:layout_weight="1"
      android:gravity="center_vertical"
      android:textStyle="bold"
      android:singleLine="true"
      android:ellipsize="end"
    />
    <TextView android:id="@+id/address"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:layout_weight="1"
      android:gravity="center_vertical"
      android:singleLine="true"
      android:ellipsize="end"
    />
  </LinearLayout>
</LinearLayout>



//res\layout\widget.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:background="@drawable/widget_frame"
>
  <TextView android:id="@+id/name"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerVertical="true"
    android:layout_alignParentLeft="true"
    android:layout_toLeftOf="@+id/next"
    android:textSize="10pt"
    android:textColor="#FFFFFFFF"
  />
  <ImageButton android:id="@id/next"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerVertical="true"
    android:layout_alignParentRight="true"
    android:src="@drawable/ff"
  />
</RelativeLayout>

extends Application

  


package app.test;

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.BasicResponseHandler;
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 android.app.Activity;
import android.app.Application;
import android.os.Bundle;
class MyHttpClient extends Application {
  private HttpClient httpClient;
  @Override
  public void onCreate() {
    super.onCreate();
    httpClient = createHttpClient();
  }
  private HttpClient createHttpClient() {
    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);

    return new DefaultHttpClient(conMgr, params);
  }

  public HttpClient getHttpClient() {
    if (httpClient == null)
      httpClient = createHttpClient();
    return httpClient;
  }

  @Override
  public void onLowMemory() {
    super.onLowMemory();
    shutdownHttpClient();
  }

  @Override
  public void onTerminate() {
    super.onTerminate();
    shutdownHttpClient();
  }

  private void shutdownHttpClient() {
    if (httpClient != null && httpClient.getConnectionManager() != null) {
      httpClient.getConnectionManager().shutdown();
      httpClient = null;
    }
  }
}

public class Test extends Activity {
  private MyHttpClient app;
  private HttpClient httpClient;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    app = (MyHttpClient) this.getApplication();
    httpClient = app.getHttpClient();
    getHttpContent();
  }

  public void getHttpContent() {
    try {
      HttpGet request = new HttpGet("http://www.google.com/");
      HttpParams params = request.getParams();
      HttpConnectionParams.setSoTimeout(params, 60000); // 1 minute
      request.setParams(params);
      String page = httpClient.execute(request,
          new BasicResponseHandler());
      System.out.println(page);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

Loads the list of installed applications in mApplications.

package com.example.android.home;

import android.content.ComponentName;
import android.content.Intent;
import android.graphics.drawable.Drawable;

/**
 * Represents a launchable application. An application is made of a name (or title), an intent
 * and an icon.
 */
class ApplicationInfo {
    /**
     * The application name.
     */
    CharSequence title;

    /**
     * The intent used to start the application.
     */
    Intent intent;

    /**
     * The application icon.
     */
    Drawable icon;

    /**
     * When set to true, indicates that the icon has been resized.
     */
    boolean filtered;

    /**
     * Creates the application intent based on a component name and various launch flags.
     *
     * @param className the class name of the component representing the intent
     * @param launchFlags the launch flags
     */
    final void setActivity(ComponentName className, int launchFlags) {
        intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        intent.setComponent(className);
        intent.setFlags(launchFlags);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof ApplicationInfo)) {
            return false;
        }

        ApplicationInfo that = (ApplicationInfo) o;
        return title.equals(that.title) &&
                intent.getComponent().getClassName().equals(
                        that.intent.getComponent().getClassName());
    }

    @Override
    public int hashCode() {
        int result;
        result = (title != null ? title.hashCode() : 0);
        final String name = intent.getComponent().getClassName();
        result = 31 * result + (name != null ? name.hashCode() : 0);
        return result;
    }
}



//src\com\example\android\home\ApplicationsStackLayout.java


package com.example.android.home;

import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.LayoutInflater;
import android.widget.TextView;

import java.util.List;


public class ApplicationsStackLayout extends ViewGroup implements View.OnClickListener {
    public static final int HORIZONTAL = 0;
    public static final int VERTICAL = 1;

    private View mButton;
    private LayoutInflater mInflater;

    private int mFavoritesEnd;
    private int mFavoritesStart;

    private List<ApplicationInfo> mFavorites;
    private List<ApplicationInfo> mRecents;

    private int mOrientation = VERTICAL;

    private int mMarginLeft;
    private int mMarginTop;
    private int mMarginRight;
    private int mMarginBottom;

    private Rect mDrawRect = new Rect();

    private Drawable mBackground;
    private int mIconSize;

    public ApplicationsStackLayout(Context context) {
        super(context);
        initLayout();
    }

    public ApplicationsStackLayout(Context context, AttributeSet attrs) {
        super(context, attrs);

        TypedArray a =
                context.obtainStyledAttributes(attrs, R.styleable.ApplicationsStackLayout);

        mOrientation = a.getInt(R.styleable.ApplicationsStackLayout_stackOrientation, VERTICAL);

        mMarginLeft = a.getDimensionPixelSize(R.styleable.ApplicationsStackLayout_marginLeft, 0);
        mMarginTop = a.getDimensionPixelSize(R.styleable.ApplicationsStackLayout_marginTop, 0);
        mMarginRight = a.getDimensionPixelSize(R.styleable.ApplicationsStackLayout_marginRight, 0);
        mMarginBottom = a.getDimensionPixelSize(R.styleable.ApplicationsStackLayout_marginBottom, 0);

        a.recycle();

        mIconSize = 42; //(int) getResources().getDimension(android.R.dimen.app_icon_size);

        initLayout();
    }

    private void initLayout() {
        mInflater = LayoutInflater.from(getContext());
        mButton = mInflater.inflate(R.layout.all_applications_button, this, false);
        addView(mButton);

        mBackground = getBackground();
        setBackgroundDrawable(null);
        setWillNotDraw(false);
    }

    /**
     * Return the current orientation, either VERTICAL (default) or HORIZONTAL.
     * 
     * @return the stack orientation
     */
    public int getOrientation() {
        return mOrientation;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        final Drawable background = mBackground;

        final int right = getWidth();
        final int bottom = getHeight();

        // Draw behind recents
        if (mOrientation == VERTICAL) {
            mDrawRect.set(0, 0, right, mFavoritesStart);
        } else {
            mDrawRect.set(0, 0, mFavoritesStart, bottom);
        }
        background.setBounds(mDrawRect);
        background.draw(canvas);

        // Draw behind favorites
        if (mFavoritesStart > -1) {
            if (mOrientation == VERTICAL) {
                mDrawRect.set(0, mFavoritesStart, right, mFavoritesEnd);
            } else {
                mDrawRect.set(mFavoritesStart, 0, mFavoritesEnd, bottom);
            }
            background.setBounds(mDrawRect);
            background.draw(canvas);
        }

        super.onDraw(canvas);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);

        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        if (widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY) {
            throw new IllegalStateException("ApplicationsStackLayout can only be used with "
                    + "measure spec mode=EXACTLY");
        }

        setMeasuredDimension(widthSize, heightSize);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        removeAllApplications();

        LayoutParams layoutParams = mButton.getLayoutParams();
        final int widthSpec = MeasureSpec.makeMeasureSpec(layoutParams.width, MeasureSpec.EXACTLY);
        final int heightSpec = MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY);
        mButton.measure(widthSpec, heightSpec);

        if (mOrientation == VERTICAL) {
            layoutVertical();
        } else {
            layoutHorizontal();
        }
    }

    private void layoutVertical() {
        int childLeft = 0;
        int childTop = getHeight();

        int childWidth = mButton.getMeasuredWidth();
        int childHeight = mButton.getMeasuredHeight();

        childTop -= childHeight + mMarginBottom;
        mButton.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
        childTop -= mMarginTop;
        mFavoritesEnd = childTop - mMarginBottom;

        int oldChildTop = childTop;
        childTop = stackApplications(mFavorites, childLeft, childTop);
        if (childTop != oldChildTop) {
            mFavoritesStart = childTop + mMarginTop;
        } else {
            mFavoritesStart = -1;
        }

        stackApplications(mRecents, childLeft, childTop);
    }

    private void layoutHorizontal() {
        int childLeft = getWidth();
        int childTop = 0;

        int childWidth = mButton.getMeasuredWidth();
        int childHeight = mButton.getMeasuredHeight();

        childLeft -= childWidth;
        mButton.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
        childLeft -= mMarginLeft;
        mFavoritesEnd = childLeft - mMarginRight;

        int oldChildLeft = childLeft;
        childLeft = stackApplications(mFavorites, childLeft, childTop);
        if (childLeft != oldChildLeft) {
            mFavoritesStart = childLeft + mMarginLeft;
        } else {
            mFavoritesStart = -1;
        }

        stackApplications(mRecents, childLeft, childTop);
    }

    private int stackApplications(List<ApplicationInfo> applications, int childLeft, int childTop) {
        LayoutParams layoutParams;
        int widthSpec;
        int heightSpec;
        int childWidth;
        int childHeight;

        final boolean isVertical = mOrientation == VERTICAL;

        final int count = applications.size();
        for (int i = count - 1; i >= 0; i--) {
            final ApplicationInfo info = applications.get(i);
            final View view = createApplicationIcon(mInflater, this, info);

            layoutParams = view.getLayoutParams();
            widthSpec = MeasureSpec.makeMeasureSpec(layoutParams.width, MeasureSpec.EXACTLY);
            heightSpec = MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY);
            view.measure(widthSpec, heightSpec);

            childWidth = view.getMeasuredWidth();
            childHeight = view.getMeasuredHeight();

            if (isVertical) {
                childTop -= childHeight + mMarginBottom;

                if (childTop < 0) {
                    childTop += childHeight + mMarginBottom;
                    break;
                }
            } else {
                childLeft -= childWidth + mMarginRight;

                if (childLeft < 0) {
                    childLeft += childWidth + mMarginRight;
                    break;
                }
            }

            addViewInLayout(view, -1, layoutParams);

            view.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);

            if (isVertical) {
                childTop -= mMarginTop;
            } else {
                childLeft -= mMarginLeft;
            }
        }

        return isVertical ? childTop : childLeft;
    }

    private void removeAllApplications() {
        final int count = getChildCount();
        for (int i = count - 1; i >= 0; i--) {
            final View view = getChildAt(i);
            if (view != mButton) {
                removeViewAt(i);
            }
        }
    }

    private View createApplicationIcon(LayoutInflater inflater,
            ViewGroup group, ApplicationInfo info) {

        TextView textView = (TextView) inflater.inflate(R.layout.favorite, group, false);

        info.icon.setBounds(0, 0, mIconSize, mIconSize);
        textView.setCompoundDrawables(null, info.icon, null, null);
        textView.setText(info.title);

        textView.setTag(info.intent);
        textView.setOnClickListener(this);

        return textView;
    }

    /**
     * Sets the list of favorites.
     *
     * @param applications the applications to put in the favorites area
     */
    public void setFavorites(List<ApplicationInfo> applications) {
        mFavorites = applications;
        requestLayout();
    }

    /**
     * Sets the list of recents.
     *
     * @param applications the applications to put in the recents area
     */
    public void setRecents(List<ApplicationInfo> applications) {
        mRecents = applications;
        requestLayout();
    }

    public void onClick(View v) {
        getContext().startActivity((Intent) v.getTag());
    }
}



//src\com\example\android\home\Home.java


package com.example.android.home;

import android.app.Activity;
import android.app.ActivityManager;
import android.app.SearchManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.ColorFilter;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.PaintDrawable;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.util.Xml;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.LayoutAnimationController;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.GridView;
import android.widget.TextView;

import java.io.IOException;
import java.io.FileReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

public class Home extends Activity {
    /**
     * Tag used for logging errors.
     */
    private static final String LOG_TAG = "Home";

    /**
     * Keys during freeze/thaw.
     */
    private static final String KEY_SAVE_GRID_OPENED = "grid.opened";

    private static final String DEFAULT_FAVORITES_PATH = "etc/favorites.xml";

    private static final String TAG_FAVORITES = "favorites";
    private static final String TAG_FAVORITE = "favorite";
    private static final String TAG_PACKAGE = "package";
    private static final String TAG_CLASS = "class";    

    // Identifiers for option menu items
    private static final int MENU_WALLPAPER_SETTINGS = Menu.FIRST + 1;
    private static final int MENU_SEARCH = MENU_WALLPAPER_SETTINGS + 1;
    private static final int MENU_SETTINGS = MENU_SEARCH + 1;

    /**
     * Maximum number of recent tasks to query.
     */
    private static final int MAX_RECENT_TASKS = 20;

    private static boolean mWallpaperChecked;
    private static ArrayList<ApplicationInfo> mApplications;
    private static LinkedList<ApplicationInfo> mFavorites;

    private final BroadcastReceiver mWallpaperReceiver = new WallpaperIntentReceiver();
    private final BroadcastReceiver mApplicationsReceiver = new ApplicationsIntentReceiver();

    private GridView mGrid;

    private LayoutAnimationController mShowLayoutAnimation;
    private LayoutAnimationController mHideLayoutAnimation;

    private boolean mBlockAnimation;

    private boolean mHomeDown;
    private boolean mBackDown;
    
    private View mShowApplications;
    private CheckBox mShowApplicationsCheck;

    private ApplicationsStackLayout mApplicationsStack;

    private Animation mGridEntry;
    private Animation mGridExit;
    
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);

        setContentView(R.layout.home);

        registerIntentReceivers();

        setDefaultWallpaper();

        loadApplications(true);

        bindApplications();
        bindFavorites(true);
        bindRecents();
        bindButtons();

        mGridEntry = AnimationUtils.loadAnimation(this, R.anim.grid_entry);
        mGridExit = AnimationUtils.loadAnimation(this, R.anim.grid_exit);
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);

        // Close the menu
        if (Intent.ACTION_MAIN.equals(intent.getAction())) {
            getWindow().closeAllPanels();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

        // Remove the callback for the cached drawables or we leak
        // the previous Home screen on orientation change
        final int count = mApplications.size();
        for (int i = 0; i < count; i++) {
            mApplications.get(i).icon.setCallback(null);
        }

        unregisterReceiver(mWallpaperReceiver);
        unregisterReceiver(mApplicationsReceiver);
    }

    @Override
    protected void onResume() {
        super.onResume();
        bindRecents();
    }
    
    @Override
    protected void onRestoreInstanceState(Bundle state) {
        super.onRestoreInstanceState(state);
        final boolean opened = state.getBoolean(KEY_SAVE_GRID_OPENED, false);
        if (opened) {
            showApplications(false);
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putBoolean(KEY_SAVE_GRID_OPENED, mGrid.getVisibility() == View.VISIBLE);
    }

    /**
     * Registers various intent receivers. The current implementation registers
     * only a wallpaper intent receiver to let other applications change the
     * wallpaper.
     */
    private void registerIntentReceivers() {
        IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
        registerReceiver(mWallpaperReceiver, filter);

        filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
        filter.addDataScheme("package");
        registerReceiver(mApplicationsReceiver, filter);
    }

    /**
     * Creates a new appplications adapter for the grid view and registers it.
     */
    private void bindApplications() {
        if (mGrid == null) {
            mGrid = (GridView) findViewById(R.id.all_apps);
        }
        mGrid.setAdapter(new ApplicationsAdapter(this, mApplications));
        mGrid.setSelection(0);

        if (mApplicationsStack == null) {
            mApplicationsStack = (ApplicationsStackLayout) findViewById(R.id.faves_and_recents);
        }
    }

    /**
     * Binds actions to the various buttons.
     */
    private void bindButtons() {
        mShowApplications = findViewById(R.id.show_all_apps);
        mShowApplications.setOnClickListener(new ShowApplications());
        mShowApplicationsCheck = (CheckBox) findViewById(R.id.show_all_apps_check);

        mGrid.setOnItemClickListener(new ApplicationLauncher());
    }

    /**
     * When no wallpaper was manually set, a default wallpaper is used instead.
     */
    private void setDefaultWallpaper() {
        if (!mWallpaperChecked) {
            Drawable wallpaper = peekWallpaper();
            if (wallpaper == null) {
                try {
                    clearWallpaper();
                } catch (IOException e) {
                    Log.e(LOG_TAG, "Failed to clear wallpaper " + e);
                }
            } else {
                getWindow().setBackgroundDrawable(new ClippedDrawable(wallpaper));
            }
            mWallpaperChecked = true;
        }
    }

    /**
     * Refreshes the favorite applications stacked over the all apps button.
     * The number of favorites depends on the user.
     */
    private void bindFavorites(boolean isLaunching) {
        if (!isLaunching || mFavorites == null) {

            if (mFavorites == null) {
                mFavorites = new LinkedList<ApplicationInfo>();
            } else {
                mFavorites.clear();
            }
            mApplicationsStack.setFavorites(mFavorites);            
            
            FileReader favReader;

            // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
            final File favFile = new File(Environment.getRootDirectory(), DEFAULT_FAVORITES_PATH);
            try {
                favReader = new FileReader(favFile);
            } catch (FileNotFoundException e) {
                Log.e(LOG_TAG, "Couldn't find or open favorites file " + favFile);
                return;
            }

            final Intent intent = new Intent(Intent.ACTION_MAIN, null);
            intent.addCategory(Intent.CATEGORY_LAUNCHER);

            final PackageManager packageManager = getPackageManager();

            try {
                final XmlPullParser parser = Xml.newPullParser();
                parser.setInput(favReader);

                beginDocument(parser, TAG_FAVORITES);

                ApplicationInfo info;

                while (true) {
                    nextElement(parser);

                    String name = parser.getName();
                    if (!TAG_FAVORITE.equals(name)) {
                        break;
                    }

                    final String favoritePackage = parser.getAttributeValue(null, TAG_PACKAGE);
                    final String favoriteClass = parser.getAttributeValue(null, TAG_CLASS);

                    final ComponentName cn = new ComponentName(favoritePackage, favoriteClass);
                    intent.setComponent(cn);
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

                    info = getApplicationInfo(packageManager, intent);
                    if (info != null) {
                        info.intent = intent;
                        mFavorites.addFirst(info);
                    }
                }
            } catch (XmlPullParserException e) {
                Log.w(LOG_TAG, "Got exception parsing favorites.", e);
            } catch (IOException e) {
                Log.w(LOG_TAG, "Got exception parsing favorites.", e);
            }
        }

        mApplicationsStack.setFavorites(mFavorites);
    }

    private static void beginDocument(XmlPullParser parser, String firstElementName)
            throws XmlPullParserException, IOException {

        int type;
        while ((type = parser.next()) != XmlPullParser.START_TAG &&
                type != XmlPullParser.END_DOCUMENT) {
            // Empty
        }

        if (type != XmlPullParser.START_TAG) {
            throw new XmlPullParserException("No start tag found");
        }

        if (!parser.getName().equals(firstElementName)) {
            throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() +
                    ", expected " + firstElementName);
        }
    }

    private static void nextElement(XmlPullParser parser) throws XmlPullParserException, IOException {
        int type;
        while ((type = parser.next()) != XmlPullParser.START_TAG &&
                type != XmlPullParser.END_DOCUMENT) {
            // Empty
        }
    }

    /**
     * Refreshes the recently launched applications stacked over the favorites. The number
     * of recents depends on how many favorites are present.
     */
    private void bindRecents() {
        final PackageManager manager = getPackageManager();
        final ActivityManager tasksManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
        final List<ActivityManager.RecentTaskInfo> recentTasks = tasksManager.getRecentTasks(
                MAX_RECENT_TASKS, 0);

        final int count = recentTasks.size();
        final ArrayList<ApplicationInfo> recents = new ArrayList<ApplicationInfo>();

        for (int i = count - 1; i >= 0; i--) {
            final Intent intent = recentTasks.get(i).baseIntent;

            if (Intent.ACTION_MAIN.equals(intent.getAction()) &&
                    !intent.hasCategory(Intent.CATEGORY_HOME)) {

                ApplicationInfo info = getApplicationInfo(manager, intent);
                if (info != null) {
                    info.intent = intent;
                    if (!mFavorites.contains(info)) {
                        recents.add(info);
                    }
                }
            }
        }

        mApplicationsStack.setRecents(recents);
    }

    private static ApplicationInfo getApplicationInfo(PackageManager manager, Intent intent) {
        final ResolveInfo resolveInfo = manager.resolveActivity(intent, 0);

        if (resolveInfo == null) {
            return null;
        }

        final ApplicationInfo info = new ApplicationInfo();
        final ActivityInfo activityInfo = resolveInfo.activityInfo;
        info.icon = activityInfo.loadIcon(manager);
        if (info.title == null || info.title.length() == 0) {
            info.title = activityInfo.loadLabel(manager);
        }
        if (info.title == null) {
            info.title = "";
        }
        return info;
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if (!hasFocus) {
            mBackDown = mHomeDown = false;
        }
    }

    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (event.getAction() == KeyEvent.ACTION_DOWN) {
            switch (event.getKeyCode()) {
                case KeyEvent.KEYCODE_BACK:
                    mBackDown = true;
                    return true;
                case KeyEvent.KEYCODE_HOME:
                    mHomeDown = true;
                    return true;
            }
        } else if (event.getAction() == KeyEvent.ACTION_UP) {
            switch (event.getKeyCode()) {
                case KeyEvent.KEYCODE_BACK:
                    if (!event.isCanceled()) {
                        // Do BACK behavior.
                    }
                    mBackDown = true;
                    return true;
                case KeyEvent.KEYCODE_HOME:
                    if (!event.isCanceled()) {
                        // Do HOME behavior.
                    }
                    mHomeDown = true;
                    return true;
            }
        }

        return super.dispatchKeyEvent(event);
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);

        menu.add(0, MENU_WALLPAPER_SETTINGS, 0, R.string.menu_wallpaper)
                 .setIcon(android.R.drawable.ic_menu_gallery)
                 .setAlphabeticShortcut('W');
        menu.add(0, MENU_SEARCH, 0, R.string.menu_search)
                .setIcon(android.R.drawable.ic_search_category_default)
                .setAlphabeticShortcut(SearchManager.MENU_KEY);
        menu.add(0, MENU_SETTINGS, 0, R.string.menu_settings)
                .setIcon(android.R.drawable.ic_menu_preferences)
                .setIntent(new Intent(android.provider.Settings.ACTION_SETTINGS));

        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case MENU_WALLPAPER_SETTINGS:
                startWallpaper();
                return true;
            case MENU_SEARCH:
                onSearchRequested();
                return true;
        }

        return super.onOptionsItemSelected(item);
    }

    private void startWallpaper() {
        final Intent pickWallpaper = new Intent(Intent.ACTION_SET_WALLPAPER);
        startActivity(Intent.createChooser(pickWallpaper, getString(R.string.menu_wallpaper)));
    }

    /**
     * Loads the list of installed applications in mApplications.
     */
    private void loadApplications(boolean isLaunching) {
        if (isLaunching && mApplications != null) {
            return;
        }

        PackageManager manager = getPackageManager();

        Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
        mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);

        final List<ResolveInfo> apps = manager.queryIntentActivities(mainIntent, 0);
        Collections.sort(apps, new ResolveInfo.DisplayNameComparator(manager));

        if (apps != null) {
            final int count = apps.size();

            if (mApplications == null) {
                mApplications = new ArrayList<ApplicationInfo>(count);
            }
            mApplications.clear();

            for (int i = 0; i < count; i++) {
                ApplicationInfo application = new ApplicationInfo();
                ResolveInfo info = apps.get(i);

                application.title = info.loadLabel(manager);
                application.setActivity(new ComponentName(
                        info.activityInfo.applicationInfo.packageName,
                        info.activityInfo.name),
                        Intent.FLAG_ACTIVITY_NEW_TASK
                        | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
                application.icon = info.activityInfo.loadIcon(manager);

                mApplications.add(application);
            }
        }
    }

    /**
     * Shows all of the applications by playing an animation on the grid.
     */
    private void showApplications(boolean animate) {
        if (mBlockAnimation) {
            return;
        }
        mBlockAnimation = true;

        mShowApplicationsCheck.toggle();

        if (mShowLayoutAnimation == null) {
            mShowLayoutAnimation = AnimationUtils.loadLayoutAnimation(
                    this, R.anim.show_applications);
        }

        // This enables a layout animation; if you uncomment this code, you need to
        // comment the line mGrid.startAnimation() below
//        mGrid.setLayoutAnimationListener(new ShowGrid());
//        mGrid.setLayoutAnimation(mShowLayoutAnimation);
//        mGrid.startLayoutAnimation();

        if (animate) {
            mGridEntry.setAnimationListener(new ShowGrid());
            mGrid.startAnimation(mGridEntry);
        }

        mGrid.setVisibility(View.VISIBLE);

        if (!animate) {
            mBlockAnimation = false;
        }

        // ViewDebug.startHierarchyTracing("Home", mGrid);
    }

    /**
     * Hides all of the applications by playing an animation on the grid.
     */
    private void hideApplications() {
        if (mBlockAnimation) {
            return;
        }
        mBlockAnimation = true;

        mShowApplicationsCheck.toggle();

        if (mHideLayoutAnimation == null) {
            mHideLayoutAnimation = AnimationUtils.loadLayoutAnimation(
                    this, R.anim.hide_applications);
        }

        mGridExit.setAnimationListener(new HideGrid());
        mGrid.startAnimation(mGridExit);
        mGrid.setVisibility(View.INVISIBLE);
        mShowApplications.requestFocus();

        // This enables a layout animation; if you uncomment this code, you need to
        // comment the line mGrid.startAnimation() above
//        mGrid.setLayoutAnimationListener(new HideGrid());
//        mGrid.setLayoutAnimation(mHideLayoutAnimation);
//        mGrid.startLayoutAnimation();
    }

    /**
     * Receives intents from other applications to change the wallpaper.
     */
    private class WallpaperIntentReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            getWindow().setBackgroundDrawable(new ClippedDrawable(getWallpaper()));
        }
    }

    /**
     * Receives notifications when applications are added/removed.
     */
    private class ApplicationsIntentReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            loadApplications(false);
            bindApplications();
            bindRecents();
            bindFavorites(false);
        }
    }

    /**
     * GridView adapter to show the list of all installed applications.
     */
    private class ApplicationsAdapter extends ArrayAdapter<ApplicationInfo> {
        private Rect mOldBounds = new Rect();

        public ApplicationsAdapter(Context context, ArrayList<ApplicationInfo> apps) {
            super(context, 0, apps);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            final ApplicationInfo info = mApplications.get(position);

            if (convertView == null) {
                final LayoutInflater inflater = getLayoutInflater();
                convertView = inflater.inflate(R.layout.application, parent, false);
            }

            Drawable icon = info.icon;

            if (!info.filtered) {
                //final Resources resources = getContext().getResources();
                int width = 42;//(int) resources.getDimension(android.R.dimen.app_icon_size);
                int height = 42;//(int) resources.getDimension(android.R.dimen.app_icon_size);

                final int iconWidth = icon.getIntrinsicWidth();
                final int iconHeight = icon.getIntrinsicHeight();

                if (icon instanceof PaintDrawable) {
                    PaintDrawable painter = (PaintDrawable) icon;
                    painter.setIntrinsicWidth(width);
                    painter.setIntrinsicHeight(height);
                }

                if (width > 0 && height > 0 && (width < iconWidth || height < iconHeight)) {
                    final float ratio = (float) iconWidth / iconHeight;

                    if (iconWidth > iconHeight) {
                        height = (int) (width / ratio);
                    } else if (iconHeight > iconWidth) {
                        width = (int) (height * ratio);
                    }

                    final Bitmap.Config c =
                            icon.getOpacity() != PixelFormat.OPAQUE ?
                                Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
                    final Bitmap thumb = Bitmap.createBitmap(width, height, c);
                    final Canvas canvas = new Canvas(thumb);
                    canvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG, 0));
                    // Copy the old bounds to restore them later
                    // If we were to do oldBounds = icon.getBounds(),
                    // the call to setBounds() that follows would
                    // change the same instance and we would lose the
                    // old bounds
                    mOldBounds.set(icon.getBounds());
                    icon.setBounds(0, 0, width, height);
                    icon.draw(canvas);
                    icon.setBounds(mOldBounds);
                    icon = info.icon = new BitmapDrawable(thumb);
                    info.filtered = true;
                }
            }

            final TextView textView = (TextView) convertView.findViewById(R.id.label);
            textView.setCompoundDrawablesWithIntrinsicBounds(null, icon, null, null);
            textView.setText(info.title);

            return convertView;
        }
    }

    /**
     * Shows and hides the applications grid view.
     */
    private class ShowApplications implements View.OnClickListener {
        public void onClick(View v) {
            if (mGrid.getVisibility() != View.VISIBLE) {
                showApplications(true);
            } else {
                hideApplications();
            }
        }
    }

    /**
     * Hides the applications grid when the layout animation is over.
     */
    private class HideGrid implements Animation.AnimationListener {
        public void onAnimationStart(Animation animation) {
        }

        public void onAnimationEnd(Animation animation) {
            mBlockAnimation = false;
        }

        public void onAnimationRepeat(Animation animation) {
        }
    }

    /**
     * Shows the applications grid when the layout animation is over.
     */
    private class ShowGrid implements Animation.AnimationListener {
        public void onAnimationStart(Animation animation) {
        }

        public void onAnimationEnd(Animation animation) {
            mBlockAnimation = false;
            // ViewDebug.stopHierarchyTracing();
        }

        public void onAnimationRepeat(Animation animation) {
        }
    }


    private class ApplicationLauncher implements AdapterView.OnItemClickListener {
        public void onItemClick(AdapterView parent, View v, int position, long id) {
            ApplicationInfo app = (ApplicationInfo) parent.getItemAtPosition(position);
            startActivity(app.intent);
        }
    }


    private class ClippedDrawable extends Drawable {
        private final Drawable mWallpaper;

        public ClippedDrawable(Drawable wallpaper) {
            mWallpaper = wallpaper;
        }

        @Override
        public void setBounds(int left, int top, int right, int bottom) {
            super.setBounds(left, top, right, bottom);
  
            mWallpaper.setBounds(left, top, left + mWallpaper.getIntrinsicWidth(),
                    top + mWallpaper.getIntrinsicHeight());
        }

        public void draw(Canvas canvas) {
            mWallpaper.draw(canvas);
        }

        public void setAlpha(int alpha) {
            mWallpaper.setAlpha(alpha);
        }

        public void setColorFilter(ColorFilter cf) {
            mWallpaper.setColorFilter(cf);
        }

        public int getOpacity() {
            return mWallpaper.getOpacity();
        }
    }
}



//src\com\example\android\home\Wallpaper.java


package com.example.android.home;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Gallery;
import android.widget.ImageView;
import android.widget.Gallery.LayoutParams;

import java.io.IOException;
import java.io.InputStream;


public class Wallpaper extends Activity implements
        AdapterView.OnItemSelectedListener, AdapterView.OnItemClickListener {
    
    private static final String LOG_TAG = "Home";

    private static final Integer[] THUMB_IDS = {
            R.drawable.bg_android_icon,
            R.drawable.bg_sunrise_icon,
            R.drawable.bg_sunset_icon,
    };

    private static final Integer[] IMAGE_IDS = {
            R.drawable.bg_android,
            R.drawable.bg_sunrise,
            R.drawable.bg_sunset,
    };

    private Gallery mGallery;
    private boolean mIsWallpaperSet;
        
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        requestWindowFeature(Window.FEATURE_NO_TITLE);

        setContentView(R.layout.wallpaper);

        mGallery = (Gallery) findViewById(R.id.gallery);
        mGallery.setAdapter(new ImageAdapter(this));
        mGallery.setOnItemSelectedListener(this);
        mGallery.setOnItemClickListener(this);
    }
    
    @Override
    protected void onResume() {
        super.onResume();
        mIsWallpaperSet = false;
    }

    public void onItemSelected(AdapterView parent, View v, int position, long id) {
        getWindow().setBackgroundDrawableResource(IMAGE_IDS[position]);
    }
    
    public void onItemClick(AdapterView parent, View v, int position, long id) {
        selectWallpaper(position);
    }


    private synchronized void selectWallpaper(int position) {
        if (mIsWallpaperSet) {
            return;
        }
        mIsWallpaperSet = true;
        try {
            InputStream stream = getResources().openRawResource(IMAGE_IDS[position]);
            setWallpaper(stream);
            setResult(RESULT_OK);
            finish();
        } catch (IOException e) {
            Log.e(LOG_TAG, "Failed to set wallpaper " + e);
        }
    }

    public void onNothingSelected(AdapterView parent) {
    }
    
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        selectWallpaper(mGallery.getSelectedItemPosition());
        return true;
    }

    public class ImageAdapter extends BaseAdapter {

        private Context mContext;
        
        public ImageAdapter(Context c) {
            mContext = c;
        }

        public int getCount() {
            return THUMB_IDS.length;
        }

        public Object getItem(int position) {
            return position;
        }

        public long getItemId(int position) {
            return position;
        }

        public View getView(final int position, View convertView, ViewGroup parent) {
            ImageView i = new ImageView(mContext);

            i.setImageResource(THUMB_IDS[position]);
            i.setAdjustViewBounds(true);
            i.setLayoutParams(new Gallery.LayoutParams(
                    LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
            i.setBackgroundResource(android.R.drawable.picture_frame);
            return i;
        }

    }

}

    



//
//res\anim\fade_in.xml
<?xml version="1.0" encoding="utf-8"?>


<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_interpolator"
    android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="50" />



//res\anim\fade_out.xml
<?xml version="1.0" encoding="utf-8"?>


<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_interpolator"
    android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="50" />



//res\anim\grid_entry.xml
<?xml version="1.0" encoding="utf-8"?>


<set xmlns:android="http://schemas.android.com/apk/res/android" 
    android:interpolator="@android:anim/decelerate_interpolator">
    <scale android:fromXScale="0.8" android:toXScale="1.0"
           android:fromYScale="0.9" android:toYScale="1.0"
           android:pivotX="100%" android:pivotY="100%" android:duration="200" />
    <alpha android:fromAlpha="0.5" android:toAlpha="1.0" android:duration="200" />
</set>



//res\anim\grid_exit.xml
<?xml version="1.0" encoding="utf-8"?>


<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_interpolator"
    android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="200" />



//res\anim\hide_applications.xml
<?xml version="1.0" encoding="utf-8"?>


<gridLayoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
        android:rowDelay="25%"
        android:directionPriority="column"
        android:animation="@anim/fade_out" />



//res\anim\show_applications.xml
<?xml version="1.0" encoding="utf-8"?>

<gridLayoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
        android:rowDelay="25%"
        android:directionPriority="column"
        android:direction="right_to_left|bottom_to_top"
        android:animation="@anim/fade_in" />



//
//res\color\bright_text_dark_focused.xml
<?xml version="1.0" encoding="utf-8"?>


<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_selected="true" android:color="#000" />
    <item android:state_focused="true" android:color="#000" />
    <item android:state_pressed="true" android:color="#000" />
    <item android:color="#FFF" />
</selector>




//
//res\layout\all_applications_button.xml
<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/show_all_apps"
    android:layout_width="78dip"
    android:layout_height="65dip"
    android:orientation="vertical"
    android:gravity="center_vertical"
    android:clickable="true"
    android:focusable="true"    
    android:background="@drawable/all_applications_button_background">

    <CheckBox
        android:id="@+id/show_all_apps_check"
        android:focusable="false"
        android:clickable="false"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/all_applications_background"
        android:button="@drawable/all_applications"
        android:text="@string/show_all_apps"
        android:textSize="12dip"
        android:maxLines="1"
        android:duplicateParentState="true"            
        android:textColor="@color/bright_text_dark_focused"
        android:gravity="center_horizontal" />

</LinearLayout>



//res\layout\application.xml
<?xml version="1.0" encoding="utf-8"?>


<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/label"
    android:layout_width="78dip"
    android:layout_height="65dip"
    android:paddingTop="4dip"
    android:textSize="12dip"
    android:singleLine="true"
    android:ellipsize="end"
    android:textColor="@color/bright_text_dark_focused"
    android:gravity="center_horizontal|center_vertical" />



//res\layout\favorite.xml
<?xml version="1.0" encoding="utf-8"?>


<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="78dip"
    android:layout_height="65dip"
    android:paddingTop="3dip"
    android:paddingBottom="3dip"
    android:clickable="true"
    android:focusable="true"
    android:background="@drawable/favorite_background"
    android:textSize="12dip"
    android:maxLines="1"
    android:ellipsize="end"
    android:textColor="@color/bright_text_dark_focused"
    android:gravity="center_horizontal|bottom" />



//res\layout\wallpaper.xml
<?xml version="1.0" encoding="utf-8"?>


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 
    
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="5dip"
        android:background="#70000000"
        android:text="@string/wallpaper_instructions"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
    />
    
    <Gallery android:id="@+id/gallery"
        android:background="#70000000"
        android:layout_width="match_parent"
        android:layout_height="60dip"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:gravity="center_vertical"
        android:spacing="16dp"
    />

</RelativeLayout>
   



//
//res\layout-land\home.xml
<?xml version="1.0" encoding="utf-8"?>


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

    <!-- All applications on the top side of the screen -->
    <GridView android:id="@+id/all_apps"
        android:background="@drawable/application_background"
        android:persistentDrawingCache="animation|scrolling"
        android:alwaysDrawnWithCache="true"
        android:scrollbars="none"
        android:drawSelectorOnTop="false"
        android:listSelector="@drawable/grid_selector"
        android:numColumns="auto_fit"
        android:columnWidth="78dp"
        android:stretchMode="spacingWidth"
        android:layout_weight="1.0"
        android:layout_height="0dip"
        android:layout_width="match_parent"
        android:stackFromBottom="true"
        android:visibility="invisible" />

    <!-- Favorites and Recents -->
    <com.example.android.home.ApplicationsStackLayout android:id="@+id/faves_and_recents"
        home:stackOrientation="horizontal"
        home:marginLeft="1dip"
        home:marginRight="1dip"
        android:layout_marginTop="0dip"
        android:layout_width="match_parent"
        android:layout_height="65dip"
        android:background="@drawable/application_background" />

</LinearLayout>



//
//res\layout-port\home.xml
<?xml version="1.0" encoding="utf-8"?>


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

    <!-- All applications on the top side of the screen -->
    <GridView android:id="@+id/all_apps"
        android:background="@drawable/application_background"
        android:persistentDrawingCache="animation|scrolling"
        android:alwaysDrawnWithCache="true"
        android:scrollbars="none"
        android:drawSelectorOnTop="false"
        android:listSelector="@drawable/grid_selector"
        android:numColumns="auto_fit"
        android:columnWidth="78dp"
        android:stretchMode="spacingWidth"
        android:layout_weight="1.0"
        android:layout_height="0dip"
        android:layout_width="match_parent"
        android:stackFromBottom="true"
        android:visibility="invisible" />

    <!-- Favorites and Recents -->
    <com.example.android.home.ApplicationsStackLayout android:id="@+id/faves_and_recents"
        home:stackOrientation="horizontal"
        home:marginLeft="1dip"
        home:marginRight="1dip"
        android:layout_marginTop="0dip"
        android:layout_width="match_parent"
        android:layout_height="65dip"
        android:background="@drawable/application_background" />

</LinearLayout>



//
//res\values\attrs.xml
<?xml version="1.0" encoding="utf-8"?>


<resources>
    <declare-styleable name="ApplicationsStackLayout">
        <attr name="stackOrientation">
            <enum name="horizontal" value="0" />
            <enum name="vertical" value="1" />
        </attr>
        <attr name="marginLeft" format="dimension"  />
        <attr name="marginTop" format="dimension"  />
        <attr name="marginRight" format="dimension"  />
        <attr name="marginBottom" format="dimension"  />
    </declare-styleable>
</resources>



//res\values\strings.xml
<?xml version="1.0" encoding="utf-8"?>


<resources>
    <!-- Home -->
    <string name="home_title">Home Sample</string>
    <string name="show_all_apps">All</string>

    <!-- Home Menus -->
    <string name="menu_wallpaper">Wallpaper</string>
    <string name="menu_search">Search</string>
    <string name="menu_settings">Settings</string>

    <!-- Wallpaper -->
    <string name="wallpaper_instructions">Tap picture to set portrait wallpaper</string>
</resources>




//res\values\styles.xml
<?xml version="1.0" encoding="utf-8"?>

<resources>
    <style name="Theme" parent="android:Theme">
        <item name="android:windowNoTitle">true</item>    
    </style>
</resources>



//
//res\values-cs\strings.xml
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <string name="home_title">"Dom"</string>
    <string name="show_all_apps">"Ve"</string>
    <string name="menu_wallpaper">"Tapeta"</string>
    <string name="menu_search">"Hledat"</string>
    <!-- no translation found for menu_settings (1769059051084007158) -->
    <skip />
    <string name="wallpaper_instructions">"Klepnutm na obrzek nastavte tapetu portrtu"</string>
</resources>



//
//res\values-land\strings.xml
<?xml version="1.0" encoding="utf-8"?>


<resources>
    <!-- Wallpaper -->
    <string name="wallpaper_instructions">Tap image to set landscape wallpaper</string>
</resources>

Implementation of the android.app.Instrumentation class, allowing you to run tests against application code.

package app.test;

import android.app.Activity;
import android.app.Instrumentation;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

/**
 * Front-end for launching {@link ContactsFilterInstrumentation} example
 * instrumentation class.
 */
public class Test extends Activity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.main);

    // Watch for button clicks.
    Button button = (Button) findViewById(R.id.go);
    button.setOnClickListener(mGoListener);
  }

  private OnClickListener mGoListener = new OnClickListener() {
    public void onClick(View v) {
      startInstrumentation(new ComponentName(Test.this,
          ContactsFilterInstrumentation.class), null, null);
    }
  };
}

/**
 * This is an example implementation of the {@link android.app.Instrumentation}
 * class, allowing you to run tests against application code. The
 * instrumentation implementation here is loaded into the application's process,
 * for controlling and monitoring what it does.
 */
class ContactsFilterInstrumentation extends Instrumentation {
  @Override
  public void onCreate(Bundle arguments) {
    super.onCreate(arguments);

    // When this instrumentation is created, we simply want to start
    // its test code off in a separate thread, which will call back
    // to us in onStart().
    start();
  }

  @Override
  public void onStart() {
    super.onStart();
    // First start the activity we are instrumenting -- the contacts
    // list.
    Intent intent = new Intent(Intent.ACTION_MAIN);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    intent.setClassName(getTargetContext(), "com.android.phone.Dialer");
    Activity activity = startActivitySync(intent);

    // This is the Activity object that was started, to do with as we want.
    Log.i("ContactsFilterInstrumentation", "Started: " + activity);

    // We are going to enqueue a couple key events to simulate the user
    // filtering the list. This is the low-level API so we must send both
    // down and up events.
    sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_M));
    sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_M));
    sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A));
    sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_A));

    // Wait for the activity to finish all of its processing.
    waitForIdleSync();

    // And we are done!
    Log.i("ContactsFilterInstrumentation", "Done!");
    finish(Activity.RESULT_OK, null);
  }
}
//main.xml

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


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:padding="4dip"
    android:gravity="center_horizontal"
    android:layout_width="match_parent" android:layout_height="match_parent">

    <TextView
        android:layout_width="match_parent" android:layout_height="wrap_content"
        android:layout_weight="0"
        android:paddingBottom="4dip"
        android:text="contacts_filter"/>

    <Button android:id="@+id/go"
        android:layout_width="wrap_content" android:layout_height="wrap_content" 
        android:text="go">
        <requestFocus />
    </Button>

</LinearLayout>

   

This application demonstrates the seeking capability of ValueAnimator.

  
package com.example.android.apis.animation;

import java.util.ArrayList;

import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RadialGradient;
import android.graphics.Shader;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.graphics.drawable.shapes.Shape;
import android.os.Bundle;
import android.view.View;
import android.view.animation.BounceInterpolator;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.SeekBar;

/**
 * This application demonstrates the seeking capability of ValueAnimator. The
 * SeekBar in the UI allows you to set the position of the animation. Pressing
 * the Run button will play from the current position of the animation.
 */
public class AnimationSeeking extends Activity {

  private static final int DURATION = 1500;
  private SeekBar mSeekBar;

  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.animation_seeking);
    LinearLayout container = (LinearLayout) findViewById(R.id.container);
    final MyAnimationView animView = new MyAnimationView(this);
    container.addView(animView);

    Button starter = (Button) findViewById(R.id.startButton);
    starter.setOnClickListener(new View.OnClickListener() {
      public void onClick(View v) {
        animView.startAnimation();
      }
    });

    mSeekBar = (SeekBar) findViewById(R.id.seekBar);
    mSeekBar.setMax(DURATION);
    mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
      public void onStopTrackingTouch(SeekBar seekBar) {
      }

      public void onStartTrackingTouch(SeekBar seekBar) {
      }

      public void onProgressChanged(SeekBar seekBar, int progress,
          boolean fromUser) {
        // prevent seeking on app creation
        if (animView.getHeight() != 0) {
          animView.seek(progress);
        }
      }
    });
  }

  public class MyAnimationView extends View implements
      ValueAnimator.AnimatorUpdateListener, Animator.AnimatorListener {

    private static final int RED = 0xffFF8080;
    private static final int BLUE = 0xff8080FF;
    private static final int CYAN = 0xff80ffff;
    private static final int GREEN = 0xff80ff80;
    private static final float BALL_SIZE = 100f;

    public final ArrayList<ShapeHolder> balls = new ArrayList<ShapeHolder>();
    AnimatorSet animation = null;
    ValueAnimator bounceAnim = null;
    ShapeHolder ball = null;

    public MyAnimationView(Context context) {
      super(context);
      ball = addBall(200, 0);
    }

    private void createAnimation() {
      if (bounceAnim == null) {
        bounceAnim = ObjectAnimator.ofFloat(ball, "y", ball.getY(),
            getHeight() - BALL_SIZE).setDuration(1500);
        bounceAnim.setInterpolator(new BounceInterpolator());
        bounceAnim.addUpdateListener(this);
      }
    }

    public void startAnimation() {
      createAnimation();
      bounceAnim.start();
    }

    public void seek(long seekTime) {
      createAnimation();
      bounceAnim.setCurrentPlayTime(seekTime);
    }

    private ShapeHolder addBall(float x, float y) {
      OvalShape circle = new OvalShape();
      circle.resize(BALL_SIZE, BALL_SIZE);
      ShapeDrawable drawable = new ShapeDrawable(circle);
      ShapeHolder shapeHolder = new ShapeHolder(drawable);
      shapeHolder.setX(x);
      shapeHolder.setY(y);
      int red = (int) (100 + Math.random() * 155);
      int green = (int) (100 + Math.random() * 155);
      int blue = (int) (100 + Math.random() * 155);
      int color = 0xff000000 | red << 16 | green << 8 | blue;
      Paint paint = drawable.getPaint();
      int darkColor = 0xff000000 | red / 4 << 16 | green / 4 << 8 | blue
          / 4;
      RadialGradient gradient = new RadialGradient(37.5f, 12.5f, 50f,
          color, darkColor, Shader.TileMode.CLAMP);
      paint.setShader(gradient);
      shapeHolder.setPaint(paint);
      balls.add(shapeHolder);
      return shapeHolder;
    }

    @Override
    protected void onDraw(Canvas canvas) {
      canvas.translate(ball.getX(), ball.getY());
      ball.getShape().draw(canvas);
    }

    public void onAnimationUpdate(ValueAnimator animation) {
      invalidate();
      long playtime = bounceAnim.getCurrentPlayTime();
      // mSeekBar.setProgress((int)playtime);
    }

    public void onAnimationCancel(Animator animation) {
    }

    public void onAnimationEnd(Animator animation) {
      balls.remove(((ObjectAnimator) animation).getTarget());

    }

    public void onAnimationRepeat(Animator animation) {
    }

    public void onAnimationStart(Animator animation) {
    }
  }
}

/**
 * A data structure that holds a Shape and various properties that can be used
 * to define how the shape is drawn.
 */
class ShapeHolder {
  private float x = 0, y = 0;
  private ShapeDrawable shape;
  private int color;
  private RadialGradient gradient;
  private float alpha = 1f;
  private Paint paint;

  public void setPaint(Paint value) {
    paint = value;
  }

  public Paint getPaint() {
    return paint;
  }

  public void setX(float value) {
    x = value;
  }

  public float getX() {
    return x;
  }

  public void setY(float value) {
    y = value;
  }

  public float getY() {
    return y;
  }

  public void setShape(ShapeDrawable value) {
    shape = value;
  }

  public ShapeDrawable getShape() {
    return shape;
  }

  public int getColor() {
    return color;
  }

  public void setColor(int value) {
    shape.getPaint().setColor(value);
    color = value;
  }

  public void setGradient(RadialGradient value) {
    gradient = value;
  }

  public RadialGradient getGradient() {
    return gradient;
  }

  public void setAlpha(float alpha) {
    this.alpha = alpha;
    shape.setAlpha((int) ((alpha * 255f) + .5f));
  }

  public float getWidth() {
    return shape.getShape().getWidth();
  }

  public void setWidth(float width) {
    Shape s = shape.getShape();
    s.resize(width, s.getHeight());
  }

  public float getHeight() {
    return shape.getShape().getHeight();
  }

  public void setHeight(float height) {
    Shape s = shape.getShape();
    s.resize(s.getWidth(), height);
  }

  public ShapeHolder(ShapeDrawable s) {
    shape = s;
  }
}

//layout/animation_seeking.xml

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

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/container"
    >
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Run"
            android:id="@+id/startButton"
            />
        <SeekBar
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/seekBar"
        />
    </LinearLayout>
</LinearLayout>

Get Application File Path

  
//package org.acra.util;

import java.io.File;


import android.content.Context;
import android.content.res.Configuration;
import android.os.Environment;
import android.os.StatFs;
import android.telephony.TelephonyManager;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;


public final class ReportUtils {

    public static String getApplicationFilePath(Context context) {
        final File filesDir = context.getFilesDir();
        if (filesDir != null) {
            return filesDir.getAbsolutePath();
        }

      //  Log.w(ACRA.LOG_TAG, "Couldn't retrieve ApplicationFilePath for : " + context.getPackageName());
        return "Couldn't retrieve ApplicationFilePath";
    }

}

Creates a file storing a UUID on the first application start. This UUID can then be used as a identifier of this specific application installation.

//package org.acra.util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.UUID;


import android.content.Context;
import android.util.Log;

public class Installation {

    private static String sID;
    private static final String INSTALLATION = "ACRA-INSTALLATION";

    public synchronized static String id(Context context) {
        if (sID == null) {
            final File installation = new File(context.getFilesDir(), INSTALLATION);
            try {
                if (!installation.exists()) {
                    writeInstallationFile(installation);
                }
                sID = readInstallationFile(installation);
            } catch (IOException e) {
           //    Log.w(ACRA.LOG_TAG, "Couldn't retrieve InstallationId for " + context.getPackageName(), e);
                return "Couldn't retrieve InstallationId";
            } catch (RuntimeException e) {
          //      Log.w(ACRA.LOG_TAG, "Couldn't retrieve InstallationId for " + context.getPackageName(), e);
                return "Couldn't retrieve InstallationId";
            }
        }
        return sID;
    }

    private static String readInstallationFile(File installation) throws IOException {
        final RandomAccessFile f = new RandomAccessFile(installation, "r");
        final byte[] bytes = new byte[(int) f.length()];
        try {
            f.readFully(bytes);
        } finally {
            f.close();
        }
        return new String(bytes);
    }

    private static void writeInstallationFile(File installation) throws IOException {
        final FileOutputStream out = new FileOutputStream(installation);
        try {
            final String id = UUID.randomUUID().toString();
            out.write(id.getBytes());
        } finally {
            out.close();
        }
    }
}