SlideShare a Scribd company logo
INTERMEDIATE
ANDROID
Michael Galpin
                 Bump Technologies
ABOUT: ME
 ‣       Android engineer, Bump Technologies

 ‣       ex-eBay: eBay Mobile for Android

 ‣       Android in Practice

 ‣       Social info

     ‣    @michaelg
     ‣    +Michael Galpin
Bump
Technologies
     • Creators of Bump app
       • Android + iOS
       • 65M+ Downloads
     • Creators of BumpCube
     • Hiring!
You down with AIP?
• Chapter 11: “Appeal to
  the senses using
  multimedia.”

• Slideshow app
  MediaMogul.apk

• http://
  code.google.com/p/
  android-in-practice/
Android workshop
MULTIMEDIA
“Of all of our inventions for mass
communication, pictures still speak the
most universally understood language.”

                          -- Walt Disney
Android workshop
Android workshop
Android workshop
Android workshop
DETECTING
CAPABILITIES
Android workshop
AndroidManifest.xml
<uses-feature android:name="android.hardware.camera"
    android:required="true" />
<uses-feature android:name="android.hardware.camera.autofocus"
    android:required="true"/>
<uses-feature android:name="android.hardware.camera.flash"
    android:required="false" />
<uses-feature android:name="android.hardware.camera.front"
    android:required="false" />
<uses-feature android:name="android.hardware.microphone"
    android:required="true"/>
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
Check the front
private boolean hasFrontFacingCamera(){
    PackageManager mgr = this.getPackageManager();
    for (FeatureInfo fi : mgr.getSystemAvailableFeatures()){
        if (fi.name.equals(PackageManager.FEATURE_CAMERA_FRONT)){
            return true;
        }
    }
    return false;
}

private Camera getFrontFacingCamera(){
    for (int i=0;i<Camera.getNumberOfCameras();i++){
        Camera.CameraInfo info = new Camera.CameraInfo();
        Camera.getCameraInfo(i, info);
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT){
            return Camera.open(i);
        }
    }
    return null;
}
Check the front
private boolean hasFrontFacingCamera(){
    PackageManager mgr = this.getPackageManager();
    for (FeatureInfo fi : mgr.getSystemAvailableFeatures()){
        if (fi.name.equals(PackageManager.FEATURE_CAMERA_FRONT)){
            return true;
        }
    }
    return false;
}

private Camera getFrontFacingCamera(){
    for (int i=0;i<Camera.getNumberOfCameras();i++){
        Camera.CameraInfo info = new Camera.CameraInfo();
        Camera.getCameraInfo(i, info);
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT){
            return Camera.open(i);
        }
    }
    return null;
}
But I have to
  support
Android 2.1
Android workshop
Android workshop
Reflection?
LOLZ

// Can't use Build.VERSION_CODES.GINGERBREAD
if (Build.VERSION.SDK_INT >= 9){
    PostFroyoClass wontThisBlowUp = new PostFroyoClass();
}
These are my customers!
These are my customers!
Proprietary APIs FTW!

import com.sprint.hardware.twinCamDevice.FrontFacingCamera;

Camera evoCam = FrontFacingCamera.getFrontFacingCamera();
RESOURCES
Android workshop
MediaPlayer.framework?
MediaPlayer.framework?

[MPMusicPlayerController iPodMusicPlayer] ??
MediaPlayer.framework?

[MPMusicPlayerController iPodMusicPlayer] ??

   [MusicLibrary sharedMusicLibrary] ???
MediaPlayer.framework?

[MPMusicPlayerController iPodMusicPlayer] ??

   [MusicLibrary sharedMusicLibrary] ???
        UIImagePickerController ?
MediaPlayer.framework?

[MPMusicPlayerController iPodMusicPlayer] ??

   [MusicLibrary sharedMusicLibrary] ???
        UIImagePickerController ?
MediaPlayer.framework?

[MPMusicPlayerController iPodMusicPlayer] ??

   [MusicLibrary sharedMusicLibrary] ???
        UIImagePickerController ?




            Files !!!!
Inside your APK




                  External
Just give it to me /res/raw

Resources res = this.getResources();


InputStream stream = res.openRawResource(R.raw.sunflower);


MediaPlayer.create(this, R.raw.constancy).start();
I like big /
     assets
and I cannot lie
MediaPlayer player = new MediaPlayer();
AssetManager mgr = getResources().getAssets();
String audioDir = "audio";
final LinkedList<FileDescriptor> queue =
    new LinkedList<FileDescriptor>();
for (String song : mgr.list("audio")){
    queue.add(
            mgr.openFd(audioDir + "/" + song).getFileDescriptor());
}
if (!queue.isEmpty()){
    FileDescriptor song = queue.poll();
    player.setDataSource(song);
    player.prepare();
    player.start();
}
player.setOnCompletionListener(new OnCompletionListener(){
    @Override
    public void onCompletion(MediaPlayer mp) {
        if (!queue.isEmpty()){
            FileDescriptor song = queue.poll();
            player.setDataSource(song);
            player.prepare();
            player.start();
        }
    }
});
Android workshop
File picturesDir =
    Environment.getExternalStoragePublicDirectory(
        Environment.DIRECTORY_PICTURES);
File picturesDir =
    Environment.getExternalStoragePublicDirectory(
        Environment.DIRECTORY_PICTURES);
IMAGES
Android workshop
Loading local images
InputStream stream = new FileInputStream(imgFile);
Bitmap bm = BitmapFactory.decodeStream(stream);
Loading local images
InputStream stream = new FileInputStream(imgFile);
Bitmap bm = BitmapFactory.decodeStream(stream);



// calculate desired width and height



Bitmap thumb = ThumbnailUtils.extractThumbnail(bm, width, height);

Bitmap thumb = Bitmap.createScaledBitmap(bm, width, height, false);
Android workshop
Loading without
                         exploding
public static Bitmap decodeDownsizedBitmapStream(File file, int target, Context context) throws
IOException {
    FileInputStream stream = new FileInputStream(file);
    Pair<Integer, Integer> source = getDimensionsForStream(stream);
    stream.close();
    FileInputStream in = new FileInputStream(file);
    Options options = new Options();
    options.inSampleSize = 1 + getDownSampleSize(max(source.first, source.second), target);
    return BitmapFactory.decodeStream(in, null, options);
}
public static Pair<Integer, Integer> getDimensionsForStream(InputStream in){
    Options options = new Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeStream(in, null, options);
    return new Pair<Integer, Integer>(options.outWidth, options.outHeight);
}
public static int getDownSampleSize(int source, int target){
    int size = 1;
    if (source <= 2*target){
        int power = (int) ((log (source / target)) / log(2));
        size = (int) pow(2, power);
    }
    return size;
}
Loading web images
URL url = new URL(urlString);



//   NOTE, be careful about just doing "url.openStream()"
//   it's a shortcut for openConnection().getInputStream() and doesn't set timeouts
//   the defaults are "infinite" so it will wait forever if endpoint server is down
//   do it properly with a few more lines of code . . .



URLConnection conn = url.openConnection();
conn.setConnectTimeout(3000);
conn.setReadTimeout(5000);

Bitmap bitmap = BitmapFactory.decodeStream(conn.getInputStream());
Android workshop
AsyncTask FTW!
private class RetrieveImageTask extends AsyncTask<String, Void, Bitmap> {
   private ImageView imageView;

    public RetrieveImageTask(ImageView imageView) {
       this.imageView = imageView;
    }

    @Override
    protected Bitmap doInBackground(String... args) {
       try {
          URL url = new URL(args[0]);
          URLConnection conn = url.openConnection();
          conn.setConnectTimeout(3000);
          conn.setReadTimeout(5000);
          return BitmapFactory.decodeStream(conn.getInputStream());
       } catch (Exception e) {
       }
       return null;
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
       if (bitmap != null) {
          imageView.setImageBitmap(bitmap);
       }
    }
}
Loading a dozen images
       isn’t cool.
 Y’know what’s cool?
Loading a billion images.
Hot or Not?
private class DealsAdapter extends ArrayAdapter<Item> {

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
       if (convertView == null) {
          LayoutInflater inflater = (LayoutInflater)
              getSystemService(Context.LAYOUT_INFLATER_SERVICE);
          convertView = inflater.inflate(R.layout.list_item, parent, false);
       }
       TextView text = (TextView) convertView.findViewById(R.id.deal_title);
       ImageView image = (ImageView) convertView.findViewById(R.id.deal_img);
       Item item = getItem(position);
       if (item != null) {
          text.setText(item.getTitle());
          new RetrieveImageTask(image).execute(item.getSmallPicUrl());
       }
       return convertView;
    }
}
Watch out for leaks
public class LeakProofActivity extends Activity {
   LeakProofAsyncTask task;
   private class LeakProofAsyncTask extends AsyncTask<String, Void, Bitmap>{
      Context potentialLeak = LeakProofActivity.this;

      @Override
      protected Bitmap doInBackground(String... arg0) {
         // Do something that takes a long time
         // Note if you need a Context here, use Application
         return null;
      }

      @Override
      protected void onPostExecute(Bitmap result){
         // update UI, etc.
      }
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);

      task = (LeakProofAsyncTask) getLastNonConfigurationInstance();
      if (task != null){
         task.potentialLeak = this;
      }
    }
    @Override
    protected void onDestroy() {
       super.onDestroy();
       if (task != null){
          task.potentialLeak = null;
       }
    }
    @Override
    public Object onRetainNonConfigurationInstance() {
       return task;
    }
}
Android workshop
How to build a cache?

• WeakReferences?
• SoftReferences?
• WeakHashMap?
• MapMaker?
LinkedHashMap!?
private static class ImageCache extends LinkedHashMap<String, Bitmap>{

    private final int capacity;

    public ImageCache(int capacity){
        super(capacity/2, 0.75f, true);
        this.capacity = capacity;
    }

    @Override
    protected boolean removeEldestEntry(Entry<String, Bitmap> eldest) {
        return this.size() > capacity;
    }
}
Disk Cache

• Context.getCacheDir()
• SQLite
• Environment.getExternalStorage()
Sidebar: Bitmaps & Heap
Reported by andreas....@googlemail.com, May 22, 2010
Note: This is NOT a requst for assistance!

In my applications, I keep getting the following exception:

E/AndroidRuntime( 1420): java.lang.OutOfMemoryError: bitmap size exceeds
VM budget
E/AndroidRuntime( 1420): 
 at
android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
E/AndroidRuntime( 1420): 
 at
android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:459)
E/AndroidRuntime( 1420): 
 at
android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:515)
E/AndroidRuntime( 1420): 
 at
de.schildbach.bitmapbug.MyActivity.bitmap(MyActivity.java:38)

Comment 1 by romaingu...@gtempaccount.com, May 23, 2010
Your app needs to use less memory.

                       http://code.google.com/p/android/issues/detail?id=8488
Android workshop
Use Placeholders

      ImageView image =
          (ImageView) convertView.findViewById(R.id.deal_img);

      image.setImageBitmap(
          BitmapFactory.decodeResource(
              getResources(), R.drawable.temp));

      Item item = getItem(position);

      new RetrieveImageTask(image).
          execute(item.getSmallPicUrl());
@Override
                       View Holders
public View getView(final int position, View cell, ViewGroup parent) {
	 ViewHolder holder = (ViewHolder) cell.getTag();
	 if (holder == null){
	 	 holder = new ViewHolder(cell);
	 	 cell.setTag(holder);
	 }
	 Bitmap thumb = (Bitmap) getItem(position);
   holder.img.setImageBitmap(thumb);
	 File file = getImageFile(position);
	 if (selectedFiles.contains(file)){
	 	 holder.cbox.setChecked(true);
	 } else {
	 	 holder.cbox.setChecked(false);
	 }
	 return cell;
}

static class ViewHolder {
    final ImageView img;
    final CheckBox cbox;
    ViewHolder(View cell){
        img = (ImageView) cell.findViewById(R.id.thumb);
    	 cbox = (CheckBox) cell.findViewById(R.id.cbox);
    }
}
Sidebar: Strict Mode
CONTENT
PROVIDERS
SQL?


       NoSQL?


           SortOfSQL!
Queries
Cursor cursor = getContentResolver().query(table,
                                           columns,
                                           whereClause,
                                           paramValues,
                                           sortOrder);
while (cursor.moveToNext()){
    // process results
}
cursor.close();
Music
import   static   android.provider.BaseColumns._ID;
import   static   android.provider.MediaStore.Audio.AudioColumns.ARTIST;
import   static   android.provider.MediaStore.Audio.AudioColumns.IS_MUSIC;
import   static   android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
import   static   android.provider.MediaStore.MediaColumns.DATA;
import   static   android.provider.MediaStore.MediaColumns.TITLE;

String[] columns = {TITLE,ARTIST,_ID, DATA};
// where clause so we don't get ringtones, podcasts, etc.
String whereClause = IS_MUSIC + " = ?";
String[] whereValues = {"1"};
cursor = managedQuery(EXTERNAL_CONTENT_URI,
	 columns,
	 whereClause,
	 whereValues,
	 null
);
Contacts
String[] projection = {Phone.CONTACT_ID, Phone.NUMBER};
String selection = Data.IN_VISIBLE_GROUP + "=1 AND " +
    Phone.NUMBER + " LIKE ?";
String[] selectionArgs = {"%" + phoneSubStr + "%"};
Cursor phoneCursor = resolver.query(Phone.CONTENT_URI,
                                 projection,
                                 selection,
                                 selectionArgs,
                                 null);


String[] projection = new String[] {StructuredName.GIVEN_NAME,
                                    StructuredName.FAMILY_NAME,
                                    StructuredName.RAW_CONTACT_ID,
                                    StructuredName.CONTACT_ID};
String selection = StructuredName.CONTACT_ID+ " = ? AND " +
    Data.MIMETYPE + " = '" + StructuredName.CONTENT_ITEM_TYPE +"'";
String[] selectionArgs = new String[] {contact.id};
Cursor nameCursor = resolver.query(Data.CONTENT_URI,
                                projection,
                                selection,
                                selectionArgs,
                                null);
Android workshop
Scanning media
Scanning 101
MediaScannerConnection conn = new MediaScannerConnection(this,
  new MediaScannerConnectionClient(){
    public void onMediaScannerConnected(){
        scanFile("/some/path/SomeSong.mp3", "audio/mpeg3");
        scanFile("/some/other/path/IMG1999.jpg", "image/jpeg");
    }

      public void onScanCompleted(String path, Uri uri){
          Log.d("LogTag", "Media scanned uir=" + uri.toString());
      }
});

conn.connect();
Cursor   Adapter
CursorAdapter
Avoid
Use Other Apps
private static final int SELECT_VIDEO = 1;
private Uri videoUri;
@Override
protected void onCreate(Bundle savedInstanceState) {
    Button vidBtn = (Button) findViewById(R.id.vidBtn);
    vidBtn.setOnClickListener(new OnClickListener(){
        @Override
        public void onClick(View button) {
            Intent videoChooser = new Intent(Intent.ACTION_GET_CONTENT);
            videoChooser.setType("video/*");
            startActivityForResult(videoChooser, SELECT_VIDEO);
        }
    });
}
@Override
protected void onActivityResult(int requestCode, int resultCode,
        Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == SELECT_VIDEO && resultCode == RESULT_OK){
        videoUri = data.getData();
    }
}
Android workshop
ANIMATION
Dissolve Animation
private void nextSlide() {
    AlphaAnimation animation = new AlphaAnimation(0.0f, 1.0f);
    if ((count % 2) == 0) {
        animation = new AlphaAnimation(1.0f, 0.0f);
    }
    animation.setStartOffset(TIME_PER_SLIDE);
    animation.setDuration(TIME_PER_SLIDE);
    animation.setFillAfter(true);
    animation.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {}
        @Override
        public void onAnimationRepeat(Animation animation) {}
        @Override
        public void onAnimationEnd(Animation animation) {
            if (playingSlides){
                nextImage = getNextImage();
                ImageView backgroundImage =
                    (count % 2 == 0) ? rightSlide : leftSlide;
                backgroundImage.setImageBitmap(nextImage);
                count++;
                nextSlide();
            }
        }
    });
    rightSlide.startAnimation(animation);
    currentImage = nextImage;
}
Honeycomb+
Animators
ImageView backgroundImage = (count % 2 == 0) ? rightSlide : leftSlide;
ObjectAnimator anim =
    ObjectAnimator.ofFloat(backgroundImage, "alpha", 0.0f, 1.0f);
anim.addListener(new AnimatorListenerAdapter(){
    public void onAnimationEnd(Animator animator){
        nextSlide();
    }
});
Android workshop
Android workshop
A/V
PLAYBACK
playBtn.setOnClickListener(new OnClickListener(){
    private Handler handler = new Handler();
    MediaPlayer player = null;
    long maxTime = 15L*1000; // 15 seconds
    long timeLeft = maxTime;
                                                      Audio Preview
    Runnable autoStop;
    @Override
    public void onClick(View view) {
        if (player == null){
            player = MediaPlayer.create(activity, song.uri);
        }
        if (!playingSongs.contains(song.id)){           Start/Resume
            player.start();
            playingSongs.add(song.id);
            autoStop = new Runnable(){
                                                     Timer
                 @Override
                 public void run() {
                     player.pause();
                     player.seekTo(0);
                     playingSongs.remove(song.id);
                     playBtn.setText(R.string.play);
                     timeLeft = maxTime;
                }
            };
            handler.postDelayed(autoStop, timeLeft);
            playBtn.setText(R.string.pause);
        } else {
            player.pause();
                                                                   Pause
            playingSongs.remove(song.id);
            timeLeft = maxTime - player.getCurrentPosition();
            playBtn.setText(R.string.play);
                                                                Calc time left
            handler.removeCallbacks(autoStop);
        }
    }
});
Handler?
Handler?
Pipeline Thread
Looper.prepare();
handler = new Handler();

// handle tasks in queue



Looper.loop();
Handler?
      Thread                 Pipeline Thread
                             Looper.prepare();
                             handler = new Handler();

                             // handle tasks in queue



                             Looper.loop();

// long running task
Message msg =
  handler.obtainMessage();
handler.sendMessage(msg);
Handler?
      Thread                 Pipeline Thread                 Thread
                             Looper.prepare();
                             handler = new Handler();

                             // handle tasks in queue
                                                        // long running task
                                                        handler.post(
                             Looper.loop();                 new Runnable() {...
                                                        });
// long running task
Message msg =
  handler.obtainMessage();
handler.sendMessage(msg);
Theme Muzak
private MediaPlayer player;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setupThemeMusic();
}

@Override
public void onResume() {
    super.onResume();
    if (player != null){
        player.start();
    }
                                               @Override
}
                                               public void onPause(){
                                                   super.onPause();
                                                   if (player != null && player.isPlaying()){
                                                       player.pause();
                                                   }
                                               }

                                               @Override
                                               protected void onDestroy() {
                                                   super.onDestroy();
                                                   if (player != null && player.isPlaying()){
                                                       player.stop();
                                                   }
                                                   player.release();
                                               }
Activity Lifecycle
Android workshop
Video Playback
Uri videoUri = ...;

VideoView video = (VideoView) findViewById(R.id.video);
video.setVideoURI(videoUri);

MediaController controller = new MediaController(this);
controller.setMediaPlayer(video);
video.setMediaController(controller);
video.requestFocus();
video.start();
Android workshop
TAKE A
PICTURE
Use the Camera (app)
import static android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI;

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
photoUri = getContentResolver().insert(
        EXTERNAL_CONTENT_URI, new ContentValues());
intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
startActivityForResult(intent,TAKE_PHOTO);




@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == Activity.RESULT_OK && requestCode == TAKE_PHOTO){
        ImageView img = (ImageView) findViewById(R.id.photoThumb);
        InputStream stream =
            getContentResolver().openInputStream(photoUri);
        Bitmap bmp = BitmapFactory.decodeStream(stream);
        img.setImageBitmap(bmp);
    }
}
Android workshop
EXIF!
Popular on Facebook
Correctly Oriented
Options photoImageOptions = new BitmapFactory.Options();
Matrix matrix = new Matrix();
ExifInterface ei = new ExifInterface(somePath);
int orientation = ei.getAttributeInt(TAG_ORIENTATION, ORIENTATION_UNDEFINED);
int angle = 0;
switch (orientation) {
    case ORIENTATION_ROTATE_90 : angle=90; break;
    case ORIENTATION_ROTATE_180 : angle=180; break;
    case ORIENTATION_ROTATE_270 : angle=270; break;
    default: break;
}
Bitmap bm = BitmapFactory.decodeFile(path, photoImageOptions);
if (angle > 0){
    matrix.setRotate(angle);
    Bitmap bm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(),
                                    matrix, true);
}
Geo Tagging


ExifInterface exif = new ExifInterface(filename);
exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, latitude);
exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, longitude);
exif.saveAttributes();




                                                    “dd/1,mm/1,ss/1”
Where?
Getting a (geo) fix

LocationManager mgr = getSystemService(LOCATION_SERVICE);

for (String provider : mgr.getAllProviders()){
    Location last = mgr.getLastKnownLocation(last);

    mgr.requestLocationUpdates(provider, 60000, 500, new LocationListener(){
        public void onLocationChanged(Location loc){
            // do stuff
        }
        // other methods
    });
}
To the cloud!
Uploading a photo

String url = "http://my/server";
HttpClient client = new DefaultHttpClient();
HttpContext context = new BasicHttpContext();
HttpPost post = new HttpPost(url);

File imgFile = new File("/path/to/my/image");
MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
entity.addPart("image", new FileBody(imgFile));
post.setEntity(entity);

HttpResponse response = client.execute(httpPost, localContext);
Android workshop
Upload Service
UploadService extends IntentService {

    protected void onHandleIntent(Intent i){
        String imgPath = i.getStringExtra("file");
        // upload code goes here
    }
}




Intent i = new Intent(this, UploadService.class);
i.putExtra("file", "/path/to/my/image");
startService(i);
Android workshop
Process Priority
       Foreground

         Visible


         Service

       Background
         Empty
A/V
RECORDING
Android workshop
Video Preview
private   SurfaceHolder holder;
private   Camera camera;
private   MediaRecorder mediaRecorder;
private   File tempFile;
private   SurfaceView preview;
private   boolean isRecording = false;
private   final int maxDurationInMs = 20000;
private   final long maxFileSizeInBytes = 500000;
private   final int videoFramesPerSecond = 20;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    preview = new SurfaceView(this);
    holder = preview.getHolder();
    holder.addCallback(cameraman);
    holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    setContentView(preview);
    tempFile = new File(getCacheDir(), "temp.mov");
    if (tempFile.length() > 0){
        tempFile.delete();
    }
}
Video Preview
private Callback cameraman = new Callback(){
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        camera = Camera.open();
        camera.setPreviewDisplay(holder);
    }
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format,
            int width,int height) {
        Parameters params = camera.getParameters();
        List<Size> sizes = params.getSupportedPreviewSizes();
        Size optimalSize = getOptimalPreviewSize(sizes, width, height);
        params.setPreviewSize(optimalSize.width, optimalSize.height);
        camera.setParameters(params);
        camera.startPreview();
    }
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        camera.stopPreview();
        camera.release();
    }
};
Video Preview
private void startRecording(){
    if (isRecording){
        return;
    }
    isRecording = true;
    camera.unlock();
    mediaRecorder = new MediaRecorder();
    mediaRecorder.setCamera(camera);
    mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
    mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
    mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
    mediaRecorder.setMaxDuration(maxDurationInMs);

    mediaRecorder.setOutputFile(tempFile.getPath());
    mediaRecorder.setVideoFrameRate(videoFramesPerSecond);
    mediaRecorder.setVideoSize(preview.getWidth(), preview.getHeight());
    mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
    mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
    mediaRecorder.setPreviewDisplay(holder.getSurface());
    mediaRecorder.setMaxFileSize(maxFileSizeInBytes);

    mediaRecorder.prepare();
    mediaRecorder.start();
}

More Related Content

What's hot

CompletableFuture
CompletableFutureCompletableFuture
CompletableFuture
koji lin
 
Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)
Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)
Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)
Ontico
 
Rxjs marble-testing
Rxjs marble-testingRxjs marble-testing
Rxjs marble-testing
Christoffer Noring
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best Practices
Yekmer Simsek
 
Physical web
Physical webPhysical web
Physical web
Jeff Prestes
 
Integrating React.js with PHP projects
Integrating React.js with PHP projectsIntegrating React.js with PHP projects
Integrating React.js with PHP projects
Ignacio Martín
 
Angular mix chrisnoring
Angular mix chrisnoringAngular mix chrisnoring
Angular mix chrisnoring
Christoffer Noring
 
Google Fit, Android Wear & Xamarin
Google Fit, Android Wear & XamarinGoogle Fit, Android Wear & Xamarin
Google Fit, Android Wear & Xamarin
Peter Friese
 
The redux saga begins
The redux saga beginsThe redux saga begins
The redux saga begins
Daniel Franz
 
Under the Hood: Using Spring in Grails
Under the Hood: Using Spring in GrailsUnder the Hood: Using Spring in Grails
Under the Hood: Using Spring in Grails
GR8Conf
 
Under the Hood: Using Spring in Grails
Under the Hood: Using Spring in GrailsUnder the Hood: Using Spring in Grails
Under the Hood: Using Spring in Grails
Burt Beckwith
 
망고100 보드로 놀아보자 19
망고100 보드로 놀아보자 19망고100 보드로 놀아보자 19
망고100 보드로 놀아보자 19
종인 전
 
【Unite 2017 Tokyo】もっと気軽に、動的なコンテンツ配信を ~アセットバンドルの未来と開発ロードマップ
【Unite 2017 Tokyo】もっと気軽に、動的なコンテンツ配信を ~アセットバンドルの未来と開発ロードマップ【Unite 2017 Tokyo】もっと気軽に、動的なコンテンツ配信を ~アセットバンドルの未来と開発ロードマップ
【Unite 2017 Tokyo】もっと気軽に、動的なコンテンツ配信を ~アセットバンドルの未来と開発ロードマップ
Unite2017Tokyo
 
Asynchronous programming done right - Node.js
Asynchronous programming done right - Node.jsAsynchronous programming done right - Node.js
Asynchronous programming done right - Node.js
Piotr Pelczar
 
Programming with ZooKeeper - A basic tutorial
Programming with ZooKeeper - A basic tutorialProgramming with ZooKeeper - A basic tutorial
Programming with ZooKeeper - A basic tutorial
Jeff Smith
 
Event driven javascript
Event driven javascriptEvent driven javascript
Event driven javascript
Francesca1980
 
Firebase ng2 zurich
Firebase ng2 zurichFirebase ng2 zurich
Firebase ng2 zurich
Christoffer Noring
 
G*なクラウド 雲のかなたに ショートバージョン
G*なクラウド 雲のかなたに ショートバージョンG*なクラウド 雲のかなたに ショートバージョン
G*なクラウド 雲のかなたに ショートバージョン
Tsuyoshi Yamamoto
 
My way to clean android - Android day salamanca edition
My way to clean android - Android day salamanca editionMy way to clean android - Android day salamanca edition
My way to clean android - Android day salamanca edition
Christian Panadero
 

What's hot (19)

CompletableFuture
CompletableFutureCompletableFuture
CompletableFuture
 
Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)
Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)
Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)
 
Rxjs marble-testing
Rxjs marble-testingRxjs marble-testing
Rxjs marble-testing
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best Practices
 
Physical web
Physical webPhysical web
Physical web
 
Integrating React.js with PHP projects
Integrating React.js with PHP projectsIntegrating React.js with PHP projects
Integrating React.js with PHP projects
 
Angular mix chrisnoring
Angular mix chrisnoringAngular mix chrisnoring
Angular mix chrisnoring
 
Google Fit, Android Wear & Xamarin
Google Fit, Android Wear & XamarinGoogle Fit, Android Wear & Xamarin
Google Fit, Android Wear & Xamarin
 
The redux saga begins
The redux saga beginsThe redux saga begins
The redux saga begins
 
Under the Hood: Using Spring in Grails
Under the Hood: Using Spring in GrailsUnder the Hood: Using Spring in Grails
Under the Hood: Using Spring in Grails
 
Under the Hood: Using Spring in Grails
Under the Hood: Using Spring in GrailsUnder the Hood: Using Spring in Grails
Under the Hood: Using Spring in Grails
 
망고100 보드로 놀아보자 19
망고100 보드로 놀아보자 19망고100 보드로 놀아보자 19
망고100 보드로 놀아보자 19
 
【Unite 2017 Tokyo】もっと気軽に、動的なコンテンツ配信を ~アセットバンドルの未来と開発ロードマップ
【Unite 2017 Tokyo】もっと気軽に、動的なコンテンツ配信を ~アセットバンドルの未来と開発ロードマップ【Unite 2017 Tokyo】もっと気軽に、動的なコンテンツ配信を ~アセットバンドルの未来と開発ロードマップ
【Unite 2017 Tokyo】もっと気軽に、動的なコンテンツ配信を ~アセットバンドルの未来と開発ロードマップ
 
Asynchronous programming done right - Node.js
Asynchronous programming done right - Node.jsAsynchronous programming done right - Node.js
Asynchronous programming done right - Node.js
 
Programming with ZooKeeper - A basic tutorial
Programming with ZooKeeper - A basic tutorialProgramming with ZooKeeper - A basic tutorial
Programming with ZooKeeper - A basic tutorial
 
Event driven javascript
Event driven javascriptEvent driven javascript
Event driven javascript
 
Firebase ng2 zurich
Firebase ng2 zurichFirebase ng2 zurich
Firebase ng2 zurich
 
G*なクラウド 雲のかなたに ショートバージョン
G*なクラウド 雲のかなたに ショートバージョンG*なクラウド 雲のかなたに ショートバージョン
G*なクラウド 雲のかなたに ショートバージョン
 
My way to clean android - Android day salamanca edition
My way to clean android - Android day salamanca editionMy way to clean android - Android day salamanca edition
My way to clean android - Android day salamanca edition
 

Viewers also liked

Unmanned Eyes In The Commercial Skies Presentation
Unmanned Eyes In The Commercial Skies PresentationUnmanned Eyes In The Commercial Skies Presentation
Unmanned Eyes In The Commercial Skies Presentation
mseraj
 
Jisc RSC Wales ISS 260213
Jisc RSC Wales ISS 260213Jisc RSC Wales ISS 260213
Jisc RSC Wales ISS 260213
Lis Parcell
 
Chemistryfm
ChemistryfmChemistryfm
Chemistryfm
Joss Winn
 
The socio political culture and economy of the thirteen american colonies
The socio political culture and economy of the thirteen american coloniesThe socio political culture and economy of the thirteen american colonies
The socio political culture and economy of the thirteen american colonies
Paulo Arieu
 
Mis 2 Princesas Chico 2
Mis 2 Princesas Chico 2Mis 2 Princesas Chico 2
Mis 2 Princesas Chico 2
Carlos Arrieta
 
Overview for Technical Nearshore Investment in Costa Rica
Overview for Technical Nearshore Investment in Costa RicaOverview for Technical Nearshore Investment in Costa Rica
Overview for Technical Nearshore Investment in Costa Rica
Andrea Tanzi
 
Presentation of the SIG TEL 4 Health
Presentation of the SIG TEL 4 HealthPresentation of the SIG TEL 4 Health
Presentation of the SIG TEL 4 Health
Hendrik Drachsler
 
Digital literacy and competences as essential life skills
Digital literacy and competences as essential life skillsDigital literacy and competences as essential life skills
Digital literacy and competences as essential life skills
DeborahJane
 
Virtuous Spiral or Vicious Circle?
Virtuous Spiral or Vicious Circle?Virtuous Spiral or Vicious Circle?
Virtuous Spiral or Vicious Circle?
Martin Rehm
 
Open Access Week | Dag van het onderzoek
Open Access Week | Dag van het onderzoekOpen Access Week | Dag van het onderzoek
Open Access Week | Dag van het onderzoek
Hendrik Drachsler
 
An API-first approach. Integrating ckan with RDM services
An API-first approach. Integrating ckan with RDM servicesAn API-first approach. Integrating ckan with RDM services
An API-first approach. Integrating ckan with RDM services
Joss Winn
 
Pero florecera
Pero floreceraPero florecera
Pero florecera
Paulo Arieu
 
Rik Panganiban's Keynote at SLCC 2011
Rik Panganiban's Keynote at SLCC 2011Rik Panganiban's Keynote at SLCC 2011
Rik Panganiban's Keynote at SLCC 2011
rik panganiban
 
Szablon strony www
Szablon strony wwwSzablon strony www
Szablon strony www
Maria Ptak
 
Lift'11 Venture Night Presentation
Lift'11 Venture Night PresentationLift'11 Venture Night Presentation
Lift'11 Venture Night Presentation
Sebastien Dubuis
 
Mobile Web 5.0
Mobile Web 5.0Mobile Web 5.0
Mobile Web 5.0
Michael Galpin
 
Riks tips on giving great presentations
Riks tips on giving great presentationsRiks tips on giving great presentations
Riks tips on giving great presentations
rik panganiban
 
30 wcwb
30 wcwb30 wcwb
Digital literacies supporting learning
Digital literacies supporting learningDigital literacies supporting learning
Digital literacies supporting learning
Lis Parcell
 

Viewers also liked (20)

Unmanned Eyes In The Commercial Skies Presentation
Unmanned Eyes In The Commercial Skies PresentationUnmanned Eyes In The Commercial Skies Presentation
Unmanned Eyes In The Commercial Skies Presentation
 
Jisc RSC Wales ISS 260213
Jisc RSC Wales ISS 260213Jisc RSC Wales ISS 260213
Jisc RSC Wales ISS 260213
 
Chemistryfm
ChemistryfmChemistryfm
Chemistryfm
 
The socio political culture and economy of the thirteen american colonies
The socio political culture and economy of the thirteen american coloniesThe socio political culture and economy of the thirteen american colonies
The socio political culture and economy of the thirteen american colonies
 
Mis 2 Princesas Chico 2
Mis 2 Princesas Chico 2Mis 2 Princesas Chico 2
Mis 2 Princesas Chico 2
 
Overview for Technical Nearshore Investment in Costa Rica
Overview for Technical Nearshore Investment in Costa RicaOverview for Technical Nearshore Investment in Costa Rica
Overview for Technical Nearshore Investment in Costa Rica
 
Presentation of the SIG TEL 4 Health
Presentation of the SIG TEL 4 HealthPresentation of the SIG TEL 4 Health
Presentation of the SIG TEL 4 Health
 
Digital literacy and competences as essential life skills
Digital literacy and competences as essential life skillsDigital literacy and competences as essential life skills
Digital literacy and competences as essential life skills
 
Virtuous Spiral or Vicious Circle?
Virtuous Spiral or Vicious Circle?Virtuous Spiral or Vicious Circle?
Virtuous Spiral or Vicious Circle?
 
Open Access Week | Dag van het onderzoek
Open Access Week | Dag van het onderzoekOpen Access Week | Dag van het onderzoek
Open Access Week | Dag van het onderzoek
 
An API-first approach. Integrating ckan with RDM services
An API-first approach. Integrating ckan with RDM servicesAn API-first approach. Integrating ckan with RDM services
An API-first approach. Integrating ckan with RDM services
 
Pero florecera
Pero floreceraPero florecera
Pero florecera
 
Rik Panganiban's Keynote at SLCC 2011
Rik Panganiban's Keynote at SLCC 2011Rik Panganiban's Keynote at SLCC 2011
Rik Panganiban's Keynote at SLCC 2011
 
Miejsca opuszczone
Miejsca opuszczoneMiejsca opuszczone
Miejsca opuszczone
 
Szablon strony www
Szablon strony wwwSzablon strony www
Szablon strony www
 
Lift'11 Venture Night Presentation
Lift'11 Venture Night PresentationLift'11 Venture Night Presentation
Lift'11 Venture Night Presentation
 
Mobile Web 5.0
Mobile Web 5.0Mobile Web 5.0
Mobile Web 5.0
 
Riks tips on giving great presentations
Riks tips on giving great presentationsRiks tips on giving great presentations
Riks tips on giving great presentations
 
30 wcwb
30 wcwb30 wcwb
30 wcwb
 
Digital literacies supporting learning
Digital literacies supporting learningDigital literacies supporting learning
Digital literacies supporting learning
 

Similar to Android workshop

Slightly Advanced Android Wear ;)
Slightly Advanced Android Wear ;)Slightly Advanced Android Wear ;)
Slightly Advanced Android Wear ;)
Alfredo Morresi
 
From newbie to ...
From newbie to ...From newbie to ...
From newbie to ...
Vitali Pekelis
 
Capture image on eye blink
Capture image on eye blinkCapture image on eye blink
Capture image on eye blink
InnovationM
 
Android programming -_pushing_the_limits
Android programming -_pushing_the_limitsAndroid programming -_pushing_the_limits
Android programming -_pushing_the_limits
Droidcon Berlin
 
Oleksandr Tolstykh
Oleksandr TolstykhOleksandr Tolstykh
Oleksandr Tolstykh
CodeFest
 
Improving android experience for both users and developers
Improving android experience for both users and developersImproving android experience for both users and developers
Improving android experience for both users and developers
Pavel Lahoda
 
Droidcon2013 android experience lahoda
Droidcon2013 android experience lahodaDroidcon2013 android experience lahoda
Droidcon2013 android experience lahoda
Droidcon Berlin
 
Android - Api & Debugging in Android
Android - Api & Debugging in AndroidAndroid - Api & Debugging in Android
Android - Api & Debugging in Android
Vibrant Technologies & Computers
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android Infrastructure
C.T.Co
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android Infrastructure
Alexey Buzdin
 
XebiCon'17 : Faites chauffer les neurones de votre Smartphone avec du Deep Le...
XebiCon'17 : Faites chauffer les neurones de votre Smartphone avec du Deep Le...XebiCon'17 : Faites chauffer les neurones de votre Smartphone avec du Deep Le...
XebiCon'17 : Faites chauffer les neurones de votre Smartphone avec du Deep Le...
Publicis Sapient Engineering
 
Androidaop 170105090257
Androidaop 170105090257Androidaop 170105090257
Androidaop 170105090257
newegg
 
Modern Android app library stack
Modern Android app library stackModern Android app library stack
Modern Android app library stack
Tomáš Kypta
 
MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012
MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012
MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012
Amazon Web Services
 
Android For All The Things
Android For All The ThingsAndroid For All The Things
Android For All The Things
Paul Trebilcox-Ruiz
 
Construire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradleConstruire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradle
Thierry Wasylczenko
 
Build Lightweight Web Module
Build Lightweight Web ModuleBuild Lightweight Web Module
Build Lightweight Web Module
Morgan Cheng
 
Non Conventional Android Programming En
Non Conventional Android Programming EnNon Conventional Android Programming En
Non Conventional Android Programming En
guest9bcef2f
 
Non Conventional Android Programming (English)
Non Conventional Android Programming (English)Non Conventional Android Programming (English)
Non Conventional Android Programming (English)
Davide Cerbo
 
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Tsuyoshi Yamamoto
 

Similar to Android workshop (20)

Slightly Advanced Android Wear ;)
Slightly Advanced Android Wear ;)Slightly Advanced Android Wear ;)
Slightly Advanced Android Wear ;)
 
From newbie to ...
From newbie to ...From newbie to ...
From newbie to ...
 
Capture image on eye blink
Capture image on eye blinkCapture image on eye blink
Capture image on eye blink
 
Android programming -_pushing_the_limits
Android programming -_pushing_the_limitsAndroid programming -_pushing_the_limits
Android programming -_pushing_the_limits
 
Oleksandr Tolstykh
Oleksandr TolstykhOleksandr Tolstykh
Oleksandr Tolstykh
 
Improving android experience for both users and developers
Improving android experience for both users and developersImproving android experience for both users and developers
Improving android experience for both users and developers
 
Droidcon2013 android experience lahoda
Droidcon2013 android experience lahodaDroidcon2013 android experience lahoda
Droidcon2013 android experience lahoda
 
Android - Api & Debugging in Android
Android - Api & Debugging in AndroidAndroid - Api & Debugging in Android
Android - Api & Debugging in Android
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android Infrastructure
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android Infrastructure
 
XebiCon'17 : Faites chauffer les neurones de votre Smartphone avec du Deep Le...
XebiCon'17 : Faites chauffer les neurones de votre Smartphone avec du Deep Le...XebiCon'17 : Faites chauffer les neurones de votre Smartphone avec du Deep Le...
XebiCon'17 : Faites chauffer les neurones de votre Smartphone avec du Deep Le...
 
Androidaop 170105090257
Androidaop 170105090257Androidaop 170105090257
Androidaop 170105090257
 
Modern Android app library stack
Modern Android app library stackModern Android app library stack
Modern Android app library stack
 
MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012
MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012
MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012
 
Android For All The Things
Android For All The ThingsAndroid For All The Things
Android For All The Things
 
Construire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradleConstruire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradle
 
Build Lightweight Web Module
Build Lightweight Web ModuleBuild Lightweight Web Module
Build Lightweight Web Module
 
Non Conventional Android Programming En
Non Conventional Android Programming EnNon Conventional Android Programming En
Non Conventional Android Programming En
 
Non Conventional Android Programming (English)
Non Conventional Android Programming (English)Non Conventional Android Programming (English)
Non Conventional Android Programming (English)
 
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
 

More from Michael Galpin

Android lessons you won't learn in school
Android lessons you won't learn in schoolAndroid lessons you won't learn in school
Android lessons you won't learn in school
Michael Galpin
 
Design Patterns for Tablets and Smartphones
Design Patterns for Tablets and SmartphonesDesign Patterns for Tablets and Smartphones
Design Patterns for Tablets and Smartphones
Michael Galpin
 
Scala on Android: Experiences at Bump Technologies
Scala on Android: Experiences at Bump TechnologiesScala on Android: Experiences at Bump Technologies
Scala on Android: Experiences at Bump Technologies
Michael Galpin
 
That’s My App - Running in Your Background - Draining Your Battery
That’s My App - Running in Your Background - Draining Your BatteryThat’s My App - Running in Your Background - Draining Your Battery
That’s My App - Running in Your Background - Draining Your Battery
Michael Galpin
 
Persistent Data Structures And Managed References
Persistent Data Structures And Managed ReferencesPersistent Data Structures And Managed References
Persistent Data Structures And Managed References
Michael Galpin
 
Scala on Your Phone
Scala on Your PhoneScala on Your Phone
Scala on Your Phone
Michael Galpin
 
Mobile Development 101
Mobile Development 101Mobile Development 101
Mobile Development 101
Michael Galpin
 
RIAs Done Right: Grails, Flex, and EXT GWT
RIAs Done Right: Grails, Flex, and EXT GWTRIAs Done Right: Grails, Flex, and EXT GWT
RIAs Done Right: Grails, Flex, and EXT GWT
Michael Galpin
 
Eclipse @eBay 2009
Eclipse @eBay 2009Eclipse @eBay 2009
Eclipse @eBay 2009
Michael Galpin
 
Introduction to Scala for Java Developers
Introduction to Scala for Java DevelopersIntroduction to Scala for Java Developers
Introduction to Scala for Java Developers
Michael Galpin
 
Eclipse@eBay
Eclipse@eBayEclipse@eBay
Eclipse@eBay
Michael Galpin
 

More from Michael Galpin (11)

Android lessons you won't learn in school
Android lessons you won't learn in schoolAndroid lessons you won't learn in school
Android lessons you won't learn in school
 
Design Patterns for Tablets and Smartphones
Design Patterns for Tablets and SmartphonesDesign Patterns for Tablets and Smartphones
Design Patterns for Tablets and Smartphones
 
Scala on Android: Experiences at Bump Technologies
Scala on Android: Experiences at Bump TechnologiesScala on Android: Experiences at Bump Technologies
Scala on Android: Experiences at Bump Technologies
 
That’s My App - Running in Your Background - Draining Your Battery
That’s My App - Running in Your Background - Draining Your BatteryThat’s My App - Running in Your Background - Draining Your Battery
That’s My App - Running in Your Background - Draining Your Battery
 
Persistent Data Structures And Managed References
Persistent Data Structures And Managed ReferencesPersistent Data Structures And Managed References
Persistent Data Structures And Managed References
 
Scala on Your Phone
Scala on Your PhoneScala on Your Phone
Scala on Your Phone
 
Mobile Development 101
Mobile Development 101Mobile Development 101
Mobile Development 101
 
RIAs Done Right: Grails, Flex, and EXT GWT
RIAs Done Right: Grails, Flex, and EXT GWTRIAs Done Right: Grails, Flex, and EXT GWT
RIAs Done Right: Grails, Flex, and EXT GWT
 
Eclipse @eBay 2009
Eclipse @eBay 2009Eclipse @eBay 2009
Eclipse @eBay 2009
 
Introduction to Scala for Java Developers
Introduction to Scala for Java DevelopersIntroduction to Scala for Java Developers
Introduction to Scala for Java Developers
 
Eclipse@eBay
Eclipse@eBayEclipse@eBay
Eclipse@eBay
 

Recently uploaded

Uncharted Together- Navigating AI's New Frontiers in Libraries
Uncharted Together- Navigating AI's New Frontiers in LibrariesUncharted Together- Navigating AI's New Frontiers in Libraries
Uncharted Together- Navigating AI's New Frontiers in Libraries
Brian Pichman
 
Figma AI Design Generator_ In-Depth Review.pdf
Figma AI Design Generator_ In-Depth Review.pdfFigma AI Design Generator_ In-Depth Review.pdf
Figma AI Design Generator_ In-Depth Review.pdf
Management Institute of Skills Development
 
Best Practices for Effectively Running dbt in Airflow.pdf
Best Practices for Effectively Running dbt in Airflow.pdfBest Practices for Effectively Running dbt in Airflow.pdf
Best Practices for Effectively Running dbt in Airflow.pdf
Tatiana Al-Chueyr
 
July Patch Tuesday
July Patch TuesdayJuly Patch Tuesday
July Patch Tuesday
Ivanti
 
Using LLM Agents with Llama 3, LangGraph and Milvus
Using LLM Agents with Llama 3, LangGraph and MilvusUsing LLM Agents with Llama 3, LangGraph and Milvus
Using LLM Agents with Llama 3, LangGraph and Milvus
Zilliz
 
Girls Call Churchgate 9910780858 Provide Best And Top Girl Service And No1 in...
Girls Call Churchgate 9910780858 Provide Best And Top Girl Service And No1 in...Girls Call Churchgate 9910780858 Provide Best And Top Girl Service And No1 in...
Girls Call Churchgate 9910780858 Provide Best And Top Girl Service And No1 in...
maigasapphire
 
Salesforce AI & Einstein Copilot Workshop
Salesforce AI & Einstein Copilot WorkshopSalesforce AI & Einstein Copilot Workshop
Salesforce AI & Einstein Copilot Workshop
CEPTES Software Inc
 
High Profile Girls Call ServiCe Hyderabad 0000000000 Tanisha Best High Class ...
High Profile Girls Call ServiCe Hyderabad 0000000000 Tanisha Best High Class ...High Profile Girls Call ServiCe Hyderabad 0000000000 Tanisha Best High Class ...
High Profile Girls Call ServiCe Hyderabad 0000000000 Tanisha Best High Class ...
aslasdfmkhan4750
 
find out more about the role of autonomous vehicles in facing global challenges
find out more about the role of autonomous vehicles in facing global challengesfind out more about the role of autonomous vehicles in facing global challenges
find out more about the role of autonomous vehicles in facing global challenges
huseindihon
 
(CISOPlatform Summit & SACON 2024) Digital Personal Data Protection Act.pdf
(CISOPlatform Summit & SACON 2024) Digital Personal Data Protection Act.pdf(CISOPlatform Summit & SACON 2024) Digital Personal Data Protection Act.pdf
(CISOPlatform Summit & SACON 2024) Digital Personal Data Protection Act.pdf
Priyanka Aash
 
Premium Girls Call Mumbai 9920725232 Unlimited Short Providing Girls Service ...
Premium Girls Call Mumbai 9920725232 Unlimited Short Providing Girls Service ...Premium Girls Call Mumbai 9920725232 Unlimited Short Providing Girls Service ...
Premium Girls Call Mumbai 9920725232 Unlimited Short Providing Girls Service ...
shanihomely
 
RPA In Healthcare Benefits, Use Case, Trend And Challenges 2024.pptx
RPA In Healthcare Benefits, Use Case, Trend And Challenges 2024.pptxRPA In Healthcare Benefits, Use Case, Trend And Challenges 2024.pptx
RPA In Healthcare Benefits, Use Case, Trend And Challenges 2024.pptx
SynapseIndia
 
IPLOOK Remote-Sensing Satellite Solution
IPLOOK Remote-Sensing Satellite SolutionIPLOOK Remote-Sensing Satellite Solution
IPLOOK Remote-Sensing Satellite Solution
IPLOOK Networks
 
CHAPTER-8 COMPONENTS OF COMPUTER SYSTEM CLASS 9 CBSE
CHAPTER-8 COMPONENTS OF COMPUTER SYSTEM CLASS 9 CBSECHAPTER-8 COMPONENTS OF COMPUTER SYSTEM CLASS 9 CBSE
CHAPTER-8 COMPONENTS OF COMPUTER SYSTEM CLASS 9 CBSE
kumarjarun2010
 
TrustArc Webinar - 2024 Data Privacy Trends: A Mid-Year Check-In
TrustArc Webinar - 2024 Data Privacy Trends: A Mid-Year Check-InTrustArc Webinar - 2024 Data Privacy Trends: A Mid-Year Check-In
TrustArc Webinar - 2024 Data Privacy Trends: A Mid-Year Check-In
TrustArc
 
Types of Weaving loom machine & it's technology
Types of Weaving loom machine & it's technologyTypes of Weaving loom machine & it's technology
Types of Weaving loom machine & it's technology
ldtexsolbl
 
Data Integration Basics: Merging & Joining Data
Data Integration Basics: Merging & Joining DataData Integration Basics: Merging & Joining Data
Data Integration Basics: Merging & Joining Data
Safe Software
 
Active Inference is a veryyyyyyyyyyyyyyyyyyyyyyyy
Active Inference is a veryyyyyyyyyyyyyyyyyyyyyyyyActive Inference is a veryyyyyyyyyyyyyyyyyyyyyyyy
Active Inference is a veryyyyyyyyyyyyyyyyyyyyyyyy
RaminGhanbari2
 
Pigging Unit Lubricant Oil Blending Plant
Pigging Unit Lubricant Oil Blending PlantPigging Unit Lubricant Oil Blending Plant
Pigging Unit Lubricant Oil Blending Plant
LINUS PROJECTS (INDIA)
 
The Role of IoT in Australian Mobile App Development - PDF Guide
The Role of IoT in Australian Mobile App Development - PDF GuideThe Role of IoT in Australian Mobile App Development - PDF Guide
The Role of IoT in Australian Mobile App Development - PDF Guide
Shiv Technolabs
 

Recently uploaded (20)

Uncharted Together- Navigating AI's New Frontiers in Libraries
Uncharted Together- Navigating AI's New Frontiers in LibrariesUncharted Together- Navigating AI's New Frontiers in Libraries
Uncharted Together- Navigating AI's New Frontiers in Libraries
 
Figma AI Design Generator_ In-Depth Review.pdf
Figma AI Design Generator_ In-Depth Review.pdfFigma AI Design Generator_ In-Depth Review.pdf
Figma AI Design Generator_ In-Depth Review.pdf
 
Best Practices for Effectively Running dbt in Airflow.pdf
Best Practices for Effectively Running dbt in Airflow.pdfBest Practices for Effectively Running dbt in Airflow.pdf
Best Practices for Effectively Running dbt in Airflow.pdf
 
July Patch Tuesday
July Patch TuesdayJuly Patch Tuesday
July Patch Tuesday
 
Using LLM Agents with Llama 3, LangGraph and Milvus
Using LLM Agents with Llama 3, LangGraph and MilvusUsing LLM Agents with Llama 3, LangGraph and Milvus
Using LLM Agents with Llama 3, LangGraph and Milvus
 
Girls Call Churchgate 9910780858 Provide Best And Top Girl Service And No1 in...
Girls Call Churchgate 9910780858 Provide Best And Top Girl Service And No1 in...Girls Call Churchgate 9910780858 Provide Best And Top Girl Service And No1 in...
Girls Call Churchgate 9910780858 Provide Best And Top Girl Service And No1 in...
 
Salesforce AI & Einstein Copilot Workshop
Salesforce AI & Einstein Copilot WorkshopSalesforce AI & Einstein Copilot Workshop
Salesforce AI & Einstein Copilot Workshop
 
High Profile Girls Call ServiCe Hyderabad 0000000000 Tanisha Best High Class ...
High Profile Girls Call ServiCe Hyderabad 0000000000 Tanisha Best High Class ...High Profile Girls Call ServiCe Hyderabad 0000000000 Tanisha Best High Class ...
High Profile Girls Call ServiCe Hyderabad 0000000000 Tanisha Best High Class ...
 
find out more about the role of autonomous vehicles in facing global challenges
find out more about the role of autonomous vehicles in facing global challengesfind out more about the role of autonomous vehicles in facing global challenges
find out more about the role of autonomous vehicles in facing global challenges
 
(CISOPlatform Summit & SACON 2024) Digital Personal Data Protection Act.pdf
(CISOPlatform Summit & SACON 2024) Digital Personal Data Protection Act.pdf(CISOPlatform Summit & SACON 2024) Digital Personal Data Protection Act.pdf
(CISOPlatform Summit & SACON 2024) Digital Personal Data Protection Act.pdf
 
Premium Girls Call Mumbai 9920725232 Unlimited Short Providing Girls Service ...
Premium Girls Call Mumbai 9920725232 Unlimited Short Providing Girls Service ...Premium Girls Call Mumbai 9920725232 Unlimited Short Providing Girls Service ...
Premium Girls Call Mumbai 9920725232 Unlimited Short Providing Girls Service ...
 
RPA In Healthcare Benefits, Use Case, Trend And Challenges 2024.pptx
RPA In Healthcare Benefits, Use Case, Trend And Challenges 2024.pptxRPA In Healthcare Benefits, Use Case, Trend And Challenges 2024.pptx
RPA In Healthcare Benefits, Use Case, Trend And Challenges 2024.pptx
 
IPLOOK Remote-Sensing Satellite Solution
IPLOOK Remote-Sensing Satellite SolutionIPLOOK Remote-Sensing Satellite Solution
IPLOOK Remote-Sensing Satellite Solution
 
CHAPTER-8 COMPONENTS OF COMPUTER SYSTEM CLASS 9 CBSE
CHAPTER-8 COMPONENTS OF COMPUTER SYSTEM CLASS 9 CBSECHAPTER-8 COMPONENTS OF COMPUTER SYSTEM CLASS 9 CBSE
CHAPTER-8 COMPONENTS OF COMPUTER SYSTEM CLASS 9 CBSE
 
TrustArc Webinar - 2024 Data Privacy Trends: A Mid-Year Check-In
TrustArc Webinar - 2024 Data Privacy Trends: A Mid-Year Check-InTrustArc Webinar - 2024 Data Privacy Trends: A Mid-Year Check-In
TrustArc Webinar - 2024 Data Privacy Trends: A Mid-Year Check-In
 
Types of Weaving loom machine & it's technology
Types of Weaving loom machine & it's technologyTypes of Weaving loom machine & it's technology
Types of Weaving loom machine & it's technology
 
Data Integration Basics: Merging & Joining Data
Data Integration Basics: Merging & Joining DataData Integration Basics: Merging & Joining Data
Data Integration Basics: Merging & Joining Data
 
Active Inference is a veryyyyyyyyyyyyyyyyyyyyyyyy
Active Inference is a veryyyyyyyyyyyyyyyyyyyyyyyyActive Inference is a veryyyyyyyyyyyyyyyyyyyyyyyy
Active Inference is a veryyyyyyyyyyyyyyyyyyyyyyyy
 
Pigging Unit Lubricant Oil Blending Plant
Pigging Unit Lubricant Oil Blending PlantPigging Unit Lubricant Oil Blending Plant
Pigging Unit Lubricant Oil Blending Plant
 
The Role of IoT in Australian Mobile App Development - PDF Guide
The Role of IoT in Australian Mobile App Development - PDF GuideThe Role of IoT in Australian Mobile App Development - PDF Guide
The Role of IoT in Australian Mobile App Development - PDF Guide
 

Android workshop

  • 2. ABOUT: ME ‣ Android engineer, Bump Technologies ‣ ex-eBay: eBay Mobile for Android ‣ Android in Practice ‣ Social info ‣ @michaelg ‣ +Michael Galpin
  • 3. Bump Technologies • Creators of Bump app • Android + iOS • 65M+ Downloads • Creators of BumpCube • Hiring!
  • 4. You down with AIP? • Chapter 11: “Appeal to the senses using multimedia.” • Slideshow app MediaMogul.apk • http:// code.google.com/p/ android-in-practice/
  • 7. “Of all of our inventions for mass communication, pictures still speak the most universally understood language.” -- Walt Disney
  • 14. AndroidManifest.xml <uses-feature android:name="android.hardware.camera" android:required="true" /> <uses-feature android:name="android.hardware.camera.autofocus" android:required="true"/> <uses-feature android:name="android.hardware.camera.flash" android:required="false" /> <uses-feature android:name="android.hardware.camera.front" android:required="false" /> <uses-feature android:name="android.hardware.microphone" android:required="true"/> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.RECORD_AUDIO" />
  • 15. Check the front private boolean hasFrontFacingCamera(){ PackageManager mgr = this.getPackageManager(); for (FeatureInfo fi : mgr.getSystemAvailableFeatures()){ if (fi.name.equals(PackageManager.FEATURE_CAMERA_FRONT)){ return true; } } return false; } private Camera getFrontFacingCamera(){ for (int i=0;i<Camera.getNumberOfCameras();i++){ Camera.CameraInfo info = new Camera.CameraInfo(); Camera.getCameraInfo(i, info); if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT){ return Camera.open(i); } } return null; }
  • 16. Check the front private boolean hasFrontFacingCamera(){ PackageManager mgr = this.getPackageManager(); for (FeatureInfo fi : mgr.getSystemAvailableFeatures()){ if (fi.name.equals(PackageManager.FEATURE_CAMERA_FRONT)){ return true; } } return false; } private Camera getFrontFacingCamera(){ for (int i=0;i<Camera.getNumberOfCameras();i++){ Camera.CameraInfo info = new Camera.CameraInfo(); Camera.getCameraInfo(i, info); if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT){ return Camera.open(i); } } return null; }
  • 17. But I have to support Android 2.1
  • 21. LOLZ // Can't use Build.VERSION_CODES.GINGERBREAD if (Build.VERSION.SDK_INT >= 9){ PostFroyoClass wontThisBlowUp = new PostFroyoClass(); }
  • 22. These are my customers!
  • 23. These are my customers!
  • 24. Proprietary APIs FTW! import com.sprint.hardware.twinCamDevice.FrontFacingCamera; Camera evoCam = FrontFacingCamera.getFrontFacingCamera();
  • 30. MediaPlayer.framework? [MPMusicPlayerController iPodMusicPlayer] ?? [MusicLibrary sharedMusicLibrary] ??? UIImagePickerController ?
  • 31. MediaPlayer.framework? [MPMusicPlayerController iPodMusicPlayer] ?? [MusicLibrary sharedMusicLibrary] ??? UIImagePickerController ?
  • 32. MediaPlayer.framework? [MPMusicPlayerController iPodMusicPlayer] ?? [MusicLibrary sharedMusicLibrary] ??? UIImagePickerController ? Files !!!!
  • 33. Inside your APK External
  • 34. Just give it to me /res/raw Resources res = this.getResources(); InputStream stream = res.openRawResource(R.raw.sunflower); MediaPlayer.create(this, R.raw.constancy).start();
  • 35. I like big / assets and I cannot lie
  • 36. MediaPlayer player = new MediaPlayer(); AssetManager mgr = getResources().getAssets(); String audioDir = "audio"; final LinkedList<FileDescriptor> queue = new LinkedList<FileDescriptor>(); for (String song : mgr.list("audio")){ queue.add( mgr.openFd(audioDir + "/" + song).getFileDescriptor()); } if (!queue.isEmpty()){ FileDescriptor song = queue.poll(); player.setDataSource(song); player.prepare(); player.start(); } player.setOnCompletionListener(new OnCompletionListener(){ @Override public void onCompletion(MediaPlayer mp) { if (!queue.isEmpty()){ FileDescriptor song = queue.poll(); player.setDataSource(song); player.prepare(); player.start(); } } });
  • 38. File picturesDir = Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES);
  • 39. File picturesDir = Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES);
  • 42. Loading local images InputStream stream = new FileInputStream(imgFile); Bitmap bm = BitmapFactory.decodeStream(stream);
  • 43. Loading local images InputStream stream = new FileInputStream(imgFile); Bitmap bm = BitmapFactory.decodeStream(stream); // calculate desired width and height Bitmap thumb = ThumbnailUtils.extractThumbnail(bm, width, height); Bitmap thumb = Bitmap.createScaledBitmap(bm, width, height, false);
  • 45. Loading without exploding public static Bitmap decodeDownsizedBitmapStream(File file, int target, Context context) throws IOException { FileInputStream stream = new FileInputStream(file); Pair<Integer, Integer> source = getDimensionsForStream(stream); stream.close(); FileInputStream in = new FileInputStream(file); Options options = new Options(); options.inSampleSize = 1 + getDownSampleSize(max(source.first, source.second), target); return BitmapFactory.decodeStream(in, null, options); } public static Pair<Integer, Integer> getDimensionsForStream(InputStream in){ Options options = new Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeStream(in, null, options); return new Pair<Integer, Integer>(options.outWidth, options.outHeight); } public static int getDownSampleSize(int source, int target){ int size = 1; if (source <= 2*target){ int power = (int) ((log (source / target)) / log(2)); size = (int) pow(2, power); } return size; }
  • 46. Loading web images URL url = new URL(urlString); // NOTE, be careful about just doing "url.openStream()" // it's a shortcut for openConnection().getInputStream() and doesn't set timeouts // the defaults are "infinite" so it will wait forever if endpoint server is down // do it properly with a few more lines of code . . . URLConnection conn = url.openConnection(); conn.setConnectTimeout(3000); conn.setReadTimeout(5000); Bitmap bitmap = BitmapFactory.decodeStream(conn.getInputStream());
  • 48. AsyncTask FTW! private class RetrieveImageTask extends AsyncTask<String, Void, Bitmap> { private ImageView imageView; public RetrieveImageTask(ImageView imageView) { this.imageView = imageView; } @Override protected Bitmap doInBackground(String... args) { try { URL url = new URL(args[0]); URLConnection conn = url.openConnection(); conn.setConnectTimeout(3000); conn.setReadTimeout(5000); return BitmapFactory.decodeStream(conn.getInputStream()); } catch (Exception e) { } return null; } @Override protected void onPostExecute(Bitmap bitmap) { if (bitmap != null) { imageView.setImageBitmap(bitmap); } } }
  • 49. Loading a dozen images isn’t cool. Y’know what’s cool? Loading a billion images.
  • 50. Hot or Not? private class DealsAdapter extends ArrayAdapter<Item> { @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.list_item, parent, false); } TextView text = (TextView) convertView.findViewById(R.id.deal_title); ImageView image = (ImageView) convertView.findViewById(R.id.deal_img); Item item = getItem(position); if (item != null) { text.setText(item.getTitle()); new RetrieveImageTask(image).execute(item.getSmallPicUrl()); } return convertView; } }
  • 51. Watch out for leaks public class LeakProofActivity extends Activity { LeakProofAsyncTask task; private class LeakProofAsyncTask extends AsyncTask<String, Void, Bitmap>{ Context potentialLeak = LeakProofActivity.this; @Override protected Bitmap doInBackground(String... arg0) { // Do something that takes a long time // Note if you need a Context here, use Application return null; } @Override protected void onPostExecute(Bitmap result){ // update UI, etc. } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); task = (LeakProofAsyncTask) getLastNonConfigurationInstance(); if (task != null){ task.potentialLeak = this; } } @Override protected void onDestroy() { super.onDestroy(); if (task != null){ task.potentialLeak = null; } } @Override public Object onRetainNonConfigurationInstance() { return task; } }
  • 53. How to build a cache? • WeakReferences? • SoftReferences? • WeakHashMap? • MapMaker?
  • 54. LinkedHashMap!? private static class ImageCache extends LinkedHashMap<String, Bitmap>{ private final int capacity; public ImageCache(int capacity){ super(capacity/2, 0.75f, true); this.capacity = capacity; } @Override protected boolean removeEldestEntry(Entry<String, Bitmap> eldest) { return this.size() > capacity; } }
  • 55. Disk Cache • Context.getCacheDir() • SQLite • Environment.getExternalStorage()
  • 56. Sidebar: Bitmaps & Heap Reported by andreas....@googlemail.com, May 22, 2010 Note: This is NOT a requst for assistance! In my applications, I keep getting the following exception: E/AndroidRuntime( 1420): java.lang.OutOfMemoryError: bitmap size exceeds VM budget E/AndroidRuntime( 1420): at android.graphics.BitmapFactory.nativeDecodeStream(Native Method) E/AndroidRuntime( 1420): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:459) E/AndroidRuntime( 1420): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:515) E/AndroidRuntime( 1420): at de.schildbach.bitmapbug.MyActivity.bitmap(MyActivity.java:38) Comment 1 by romaingu...@gtempaccount.com, May 23, 2010 Your app needs to use less memory. http://code.google.com/p/android/issues/detail?id=8488
  • 58. Use Placeholders ImageView image = (ImageView) convertView.findViewById(R.id.deal_img); image.setImageBitmap( BitmapFactory.decodeResource( getResources(), R.drawable.temp)); Item item = getItem(position); new RetrieveImageTask(image). execute(item.getSmallPicUrl());
  • 59. @Override View Holders public View getView(final int position, View cell, ViewGroup parent) { ViewHolder holder = (ViewHolder) cell.getTag(); if (holder == null){ holder = new ViewHolder(cell); cell.setTag(holder); } Bitmap thumb = (Bitmap) getItem(position); holder.img.setImageBitmap(thumb); File file = getImageFile(position); if (selectedFiles.contains(file)){ holder.cbox.setChecked(true); } else { holder.cbox.setChecked(false); } return cell; } static class ViewHolder { final ImageView img; final CheckBox cbox; ViewHolder(View cell){ img = (ImageView) cell.findViewById(R.id.thumb); cbox = (CheckBox) cell.findViewById(R.id.cbox); } }
  • 62. SQL? NoSQL? SortOfSQL!
  • 63. Queries Cursor cursor = getContentResolver().query(table, columns, whereClause, paramValues, sortOrder); while (cursor.moveToNext()){ // process results } cursor.close();
  • 64. Music import static android.provider.BaseColumns._ID; import static android.provider.MediaStore.Audio.AudioColumns.ARTIST; import static android.provider.MediaStore.Audio.AudioColumns.IS_MUSIC; import static android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; import static android.provider.MediaStore.MediaColumns.DATA; import static android.provider.MediaStore.MediaColumns.TITLE; String[] columns = {TITLE,ARTIST,_ID, DATA}; // where clause so we don't get ringtones, podcasts, etc. String whereClause = IS_MUSIC + " = ?"; String[] whereValues = {"1"}; cursor = managedQuery(EXTERNAL_CONTENT_URI, columns, whereClause, whereValues, null );
  • 65. Contacts String[] projection = {Phone.CONTACT_ID, Phone.NUMBER}; String selection = Data.IN_VISIBLE_GROUP + "=1 AND " + Phone.NUMBER + " LIKE ?"; String[] selectionArgs = {"%" + phoneSubStr + "%"}; Cursor phoneCursor = resolver.query(Phone.CONTENT_URI, projection, selection, selectionArgs, null); String[] projection = new String[] {StructuredName.GIVEN_NAME, StructuredName.FAMILY_NAME, StructuredName.RAW_CONTACT_ID, StructuredName.CONTACT_ID}; String selection = StructuredName.CONTACT_ID+ " = ? AND " + Data.MIMETYPE + " = '" + StructuredName.CONTENT_ITEM_TYPE +"'"; String[] selectionArgs = new String[] {contact.id}; Cursor nameCursor = resolver.query(Data.CONTENT_URI, projection, selection, selectionArgs, null);
  • 68. Scanning 101 MediaScannerConnection conn = new MediaScannerConnection(this, new MediaScannerConnectionClient(){ public void onMediaScannerConnected(){ scanFile("/some/path/SomeSong.mp3", "audio/mpeg3"); scanFile("/some/other/path/IMG1999.jpg", "image/jpeg"); } public void onScanCompleted(String path, Uri uri){ Log.d("LogTag", "Media scanned uir=" + uri.toString()); } }); conn.connect();
  • 69. Cursor Adapter
  • 71. Avoid
  • 72. Use Other Apps private static final int SELECT_VIDEO = 1; private Uri videoUri; @Override protected void onCreate(Bundle savedInstanceState) { Button vidBtn = (Button) findViewById(R.id.vidBtn); vidBtn.setOnClickListener(new OnClickListener(){ @Override public void onClick(View button) { Intent videoChooser = new Intent(Intent.ACTION_GET_CONTENT); videoChooser.setType("video/*"); startActivityForResult(videoChooser, SELECT_VIDEO); } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == SELECT_VIDEO && resultCode == RESULT_OK){ videoUri = data.getData(); } }
  • 75. Dissolve Animation private void nextSlide() { AlphaAnimation animation = new AlphaAnimation(0.0f, 1.0f); if ((count % 2) == 0) { animation = new AlphaAnimation(1.0f, 0.0f); } animation.setStartOffset(TIME_PER_SLIDE); animation.setDuration(TIME_PER_SLIDE); animation.setFillAfter(true); animation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) {} @Override public void onAnimationRepeat(Animation animation) {} @Override public void onAnimationEnd(Animation animation) { if (playingSlides){ nextImage = getNextImage(); ImageView backgroundImage = (count % 2 == 0) ? rightSlide : leftSlide; backgroundImage.setImageBitmap(nextImage); count++; nextSlide(); } } }); rightSlide.startAnimation(animation); currentImage = nextImage; }
  • 77. Animators ImageView backgroundImage = (count % 2 == 0) ? rightSlide : leftSlide; ObjectAnimator anim = ObjectAnimator.ofFloat(backgroundImage, "alpha", 0.0f, 1.0f); anim.addListener(new AnimatorListenerAdapter(){ public void onAnimationEnd(Animator animator){ nextSlide(); } });
  • 81. playBtn.setOnClickListener(new OnClickListener(){ private Handler handler = new Handler(); MediaPlayer player = null; long maxTime = 15L*1000; // 15 seconds long timeLeft = maxTime; Audio Preview Runnable autoStop; @Override public void onClick(View view) { if (player == null){ player = MediaPlayer.create(activity, song.uri); } if (!playingSongs.contains(song.id)){ Start/Resume player.start(); playingSongs.add(song.id); autoStop = new Runnable(){ Timer @Override public void run() { player.pause(); player.seekTo(0); playingSongs.remove(song.id); playBtn.setText(R.string.play); timeLeft = maxTime; } }; handler.postDelayed(autoStop, timeLeft); playBtn.setText(R.string.pause); } else { player.pause(); Pause playingSongs.remove(song.id); timeLeft = maxTime - player.getCurrentPosition(); playBtn.setText(R.string.play); Calc time left handler.removeCallbacks(autoStop); } } });
  • 83. Handler? Pipeline Thread Looper.prepare(); handler = new Handler(); // handle tasks in queue Looper.loop();
  • 84. Handler? Thread Pipeline Thread Looper.prepare(); handler = new Handler(); // handle tasks in queue Looper.loop(); // long running task Message msg = handler.obtainMessage(); handler.sendMessage(msg);
  • 85. Handler? Thread Pipeline Thread Thread Looper.prepare(); handler = new Handler(); // handle tasks in queue // long running task handler.post( Looper.loop(); new Runnable() {... }); // long running task Message msg = handler.obtainMessage(); handler.sendMessage(msg);
  • 86. Theme Muzak private MediaPlayer player; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setupThemeMusic(); } @Override public void onResume() { super.onResume(); if (player != null){ player.start(); } @Override } public void onPause(){ super.onPause(); if (player != null && player.isPlaying()){ player.pause(); } } @Override protected void onDestroy() { super.onDestroy(); if (player != null && player.isPlaying()){ player.stop(); } player.release(); }
  • 89. Video Playback Uri videoUri = ...; VideoView video = (VideoView) findViewById(R.id.video); video.setVideoURI(videoUri); MediaController controller = new MediaController(this); controller.setMediaPlayer(video); video.setMediaController(controller); video.requestFocus(); video.start();
  • 92. Use the Camera (app) import static android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI; Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); photoUri = getContentResolver().insert( EXTERNAL_CONTENT_URI, new ContentValues()); intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); startActivityForResult(intent,TAKE_PHOTO); @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == Activity.RESULT_OK && requestCode == TAKE_PHOTO){ ImageView img = (ImageView) findViewById(R.id.photoThumb); InputStream stream = getContentResolver().openInputStream(photoUri); Bitmap bmp = BitmapFactory.decodeStream(stream); img.setImageBitmap(bmp); } }
  • 94. EXIF!
  • 96. Correctly Oriented Options photoImageOptions = new BitmapFactory.Options(); Matrix matrix = new Matrix(); ExifInterface ei = new ExifInterface(somePath); int orientation = ei.getAttributeInt(TAG_ORIENTATION, ORIENTATION_UNDEFINED); int angle = 0; switch (orientation) { case ORIENTATION_ROTATE_90 : angle=90; break; case ORIENTATION_ROTATE_180 : angle=180; break; case ORIENTATION_ROTATE_270 : angle=270; break; default: break; } Bitmap bm = BitmapFactory.decodeFile(path, photoImageOptions); if (angle > 0){ matrix.setRotate(angle); Bitmap bm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true); }
  • 97. Geo Tagging ExifInterface exif = new ExifInterface(filename); exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, latitude); exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, longitude); exif.saveAttributes(); “dd/1,mm/1,ss/1”
  • 99. Getting a (geo) fix LocationManager mgr = getSystemService(LOCATION_SERVICE); for (String provider : mgr.getAllProviders()){ Location last = mgr.getLastKnownLocation(last); mgr.requestLocationUpdates(provider, 60000, 500, new LocationListener(){ public void onLocationChanged(Location loc){ // do stuff } // other methods }); }
  • 101. Uploading a photo String url = "http://my/server"; HttpClient client = new DefaultHttpClient(); HttpContext context = new BasicHttpContext(); HttpPost post = new HttpPost(url); File imgFile = new File("/path/to/my/image"); MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE); entity.addPart("image", new FileBody(imgFile)); post.setEntity(entity); HttpResponse response = client.execute(httpPost, localContext);
  • 103. Upload Service UploadService extends IntentService { protected void onHandleIntent(Intent i){ String imgPath = i.getStringExtra("file"); // upload code goes here } } Intent i = new Intent(this, UploadService.class); i.putExtra("file", "/path/to/my/image"); startService(i);
  • 105. Process Priority Foreground Visible Service Background Empty
  • 108. Video Preview private SurfaceHolder holder; private Camera camera; private MediaRecorder mediaRecorder; private File tempFile; private SurfaceView preview; private boolean isRecording = false; private final int maxDurationInMs = 20000; private final long maxFileSizeInBytes = 500000; private final int videoFramesPerSecond = 20; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); preview = new SurfaceView(this); holder = preview.getHolder(); holder.addCallback(cameraman); holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); setContentView(preview); tempFile = new File(getCacheDir(), "temp.mov"); if (tempFile.length() > 0){ tempFile.delete(); } }
  • 109. Video Preview private Callback cameraman = new Callback(){ @Override public void surfaceCreated(SurfaceHolder holder) { camera = Camera.open(); camera.setPreviewDisplay(holder); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) { Parameters params = camera.getParameters(); List<Size> sizes = params.getSupportedPreviewSizes(); Size optimalSize = getOptimalPreviewSize(sizes, width, height); params.setPreviewSize(optimalSize.width, optimalSize.height); camera.setParameters(params); camera.startPreview(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { camera.stopPreview(); camera.release(); } };
  • 110. Video Preview private void startRecording(){ if (isRecording){ return; } isRecording = true; camera.unlock(); mediaRecorder = new MediaRecorder(); mediaRecorder.setCamera(camera); mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT); mediaRecorder.setMaxDuration(maxDurationInMs); mediaRecorder.setOutputFile(tempFile.getPath()); mediaRecorder.setVideoFrameRate(videoFramesPerSecond); mediaRecorder.setVideoSize(preview.getWidth(), preview.getHeight()); mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT); mediaRecorder.setPreviewDisplay(holder.getSurface()); mediaRecorder.setMaxFileSize(maxFileSizeInBytes); mediaRecorder.prepare(); mediaRecorder.start(); }

Editor's Notes

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. \n
  46. \n
  47. \n
  48. \n
  49. \n
  50. \n
  51. \n
  52. \n
  53. \n
  54. \n
  55. \n
  56. \n
  57. \n
  58. \n
  59. \n
  60. \n
  61. \n
  62. \n
  63. \n
  64. \n
  65. \n
  66. \n
  67. \n
  68. \n
  69. \n
  70. \n
  71. \n
  72. \n
  73. \n
  74. \n
  75. \n
  76. \n
  77. \n
  78. \n
  79. \n
  80. \n
  81. \n
  82. \n
  83. \n
  84. \n
  85. \n
  86. \n
  87. \n
  88. \n
  89. \n
  90. \n
  91. \n
  92. \n
  93. \n
  94. \n
  95. \n
  96. \n
  97. \n
  98. \n
  99. \n
  100. \n
  101. \n
  102. \n
  103. \n
  104. \n
  105. \n
  106. \n
  107. \n
  108. \n
  109. \n