SlideShare a Scribd company logo
1 of 110
Download to read offline
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
CompletableFuturekoji lin
 
Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)
Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)
Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)Ontico
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best PracticesYekmer Simsek
 
Integrating React.js with PHP projects
Integrating React.js with PHP projectsIntegrating React.js with PHP projects
Integrating React.js with PHP projectsIgnacio Martín
 
Google Fit, Android Wear & Xamarin
Google Fit, Android Wear & XamarinGoogle Fit, Android Wear & Xamarin
Google Fit, Android Wear & XamarinPeter Friese
 
The redux saga begins
The redux saga beginsThe redux saga begins
The redux saga beginsDaniel 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 GrailsGR8Conf
 
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 GrailsBurt 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.jsPiotr Pelczar
 
Programming with ZooKeeper - A basic tutorial
Programming with ZooKeeper - A basic tutorialProgramming with ZooKeeper - A basic tutorial
Programming with ZooKeeper - A basic tutorialJeff Smith
 
Event driven javascript
Event driven javascriptEvent driven javascript
Event driven javascriptFrancesca1980
 
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 editionChristian 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 Presentationmseraj
 
Jisc RSC Wales ISS 260213
Jisc RSC Wales ISS 260213Jisc RSC Wales ISS 260213
Jisc RSC Wales ISS 260213Lis Parcell
 
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 coloniesPaulo Arieu
 
Mis 2 Princesas Chico 2
Mis 2 Princesas Chico 2Mis 2 Princesas Chico 2
Mis 2 Princesas Chico 2Carlos 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 RicaAndrea 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 HealthHendrik 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 skillsDeborahJane
 
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 onderzoekHendrik 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 servicesJoss Winn
 
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 2011rik panganiban
 
Szablon strony www
Szablon strony wwwSzablon strony www
Szablon strony wwwMaria Ptak
 
Lift'11 Venture Night Presentation
Lift'11 Venture Night PresentationLift'11 Venture Night Presentation
Lift'11 Venture Night PresentationSebastien Dubuis
 
Riks tips on giving great presentations
Riks tips on giving great presentationsRiks tips on giving great presentations
Riks tips on giving great presentationsrik panganiban
 
Digital literacies supporting learning
Digital literacies supporting learningDigital literacies supporting learning
Digital literacies supporting learningLis 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
 
Capture image on eye blink
Capture image on eye blinkCapture image on eye blink
Capture image on eye blinkInnovationM
 
Android programming -_pushing_the_limits
Android programming -_pushing_the_limitsAndroid programming -_pushing_the_limits
Android programming -_pushing_the_limitsDroidcon Berlin
 
Oleksandr Tolstykh
Oleksandr TolstykhOleksandr Tolstykh
Oleksandr TolstykhCodeFest
 
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 developersPavel Lahoda
 
Droidcon2013 android experience lahoda
Droidcon2013 android experience lahodaDroidcon2013 android experience lahoda
Droidcon2013 android experience lahodaDroidcon Berlin
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android InfrastructureAlexey Buzdin
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android InfrastructureC.T.Co
 
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 170105090257newegg
 
Modern Android app library stack
Modern Android app library stackModern Android app library stack
Modern Android app library stackTomáš 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 2012Amazon Web Services
 
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 gradleThierry Wasylczenko
 
Build Lightweight Web Module
Build Lightweight Web ModuleBuild Lightweight Web Module
Build Lightweight Web ModuleMorgan Cheng
 
Non Conventional Android Programming En
Non Conventional Android Programming EnNon Conventional Android Programming En
Non Conventional Android Programming Enguest9bcef2f
 
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 schoolMichael Galpin
 
Design Patterns for Tablets and Smartphones
Design Patterns for Tablets and SmartphonesDesign Patterns for Tablets and Smartphones
Design Patterns for Tablets and SmartphonesMichael 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 TechnologiesMichael 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 BatteryMichael Galpin
 
Persistent Data Structures And Managed References
Persistent Data Structures And Managed ReferencesPersistent Data Structures And Managed References
Persistent Data Structures And Managed ReferencesMichael Galpin
 
Mobile Development 101
Mobile Development 101Mobile Development 101
Mobile Development 101Michael 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 GWTMichael Galpin
 
Introduction to Scala for Java Developers
Introduction to Scala for Java DevelopersIntroduction to Scala for Java Developers
Introduction to Scala for Java DevelopersMichael 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

COMPUTER 10: Lesson 7 - File Storage and Online Collaboration
COMPUTER 10: Lesson 7 - File Storage and Online CollaborationCOMPUTER 10: Lesson 7 - File Storage and Online Collaboration
COMPUTER 10: Lesson 7 - File Storage and Online Collaborationbruanjhuli
 
Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.YounusS2
 
UiPath Studio Web workshop series - Day 7
UiPath Studio Web workshop series - Day 7UiPath Studio Web workshop series - Day 7
UiPath Studio Web workshop series - Day 7DianaGray10
 
Introduction to Matsuo Laboratory (ENG).pptx
Introduction to Matsuo Laboratory (ENG).pptxIntroduction to Matsuo Laboratory (ENG).pptx
Introduction to Matsuo Laboratory (ENG).pptxMatsuo Lab
 
AI Fame Rush Review – Virtual Influencer Creation In Just Minutes
AI Fame Rush Review – Virtual Influencer Creation In Just MinutesAI Fame Rush Review – Virtual Influencer Creation In Just Minutes
AI Fame Rush Review – Virtual Influencer Creation In Just MinutesMd Hossain Ali
 
Bird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystemBird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystemAsko Soukka
 
Linked Data in Production: Moving Beyond Ontologies
Linked Data in Production: Moving Beyond OntologiesLinked Data in Production: Moving Beyond Ontologies
Linked Data in Production: Moving Beyond OntologiesDavid Newbury
 
Igniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration WorkflowsIgniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration WorkflowsSafe Software
 
Computer 10: Lesson 10 - Online Crimes and Hazards
Computer 10: Lesson 10 - Online Crimes and HazardsComputer 10: Lesson 10 - Online Crimes and Hazards
Computer 10: Lesson 10 - Online Crimes and HazardsSeth Reyes
 
KubeConEU24-Monitoring Kubernetes and Cloud Spend with OpenCost
KubeConEU24-Monitoring Kubernetes and Cloud Spend with OpenCostKubeConEU24-Monitoring Kubernetes and Cloud Spend with OpenCost
KubeConEU24-Monitoring Kubernetes and Cloud Spend with OpenCostMatt Ray
 
Artificial Intelligence & SEO Trends for 2024
Artificial Intelligence & SEO Trends for 2024Artificial Intelligence & SEO Trends for 2024
Artificial Intelligence & SEO Trends for 2024D Cloud Solutions
 
UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6DianaGray10
 
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdf
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdfIaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdf
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdfDaniel Santiago Silva Capera
 
Empowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership BlueprintEmpowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership BlueprintMahmoud Rabie
 
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...DianaGray10
 
COMPUTER 10 Lesson 8 - Building a Website
COMPUTER 10 Lesson 8 - Building a WebsiteCOMPUTER 10 Lesson 8 - Building a Website
COMPUTER 10 Lesson 8 - Building a Websitedgelyza
 
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019IES VE
 
Nanopower In Semiconductor Industry.pdf
Nanopower  In Semiconductor Industry.pdfNanopower  In Semiconductor Industry.pdf
Nanopower In Semiconductor Industry.pdfPedro Manuel
 
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...Will Schroeder
 

Recently uploaded (20)

COMPUTER 10: Lesson 7 - File Storage and Online Collaboration
COMPUTER 10: Lesson 7 - File Storage and Online CollaborationCOMPUTER 10: Lesson 7 - File Storage and Online Collaboration
COMPUTER 10: Lesson 7 - File Storage and Online Collaboration
 
Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.
 
UiPath Studio Web workshop series - Day 7
UiPath Studio Web workshop series - Day 7UiPath Studio Web workshop series - Day 7
UiPath Studio Web workshop series - Day 7
 
Introduction to Matsuo Laboratory (ENG).pptx
Introduction to Matsuo Laboratory (ENG).pptxIntroduction to Matsuo Laboratory (ENG).pptx
Introduction to Matsuo Laboratory (ENG).pptx
 
AI Fame Rush Review – Virtual Influencer Creation In Just Minutes
AI Fame Rush Review – Virtual Influencer Creation In Just MinutesAI Fame Rush Review – Virtual Influencer Creation In Just Minutes
AI Fame Rush Review – Virtual Influencer Creation In Just Minutes
 
Bird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystemBird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystem
 
Linked Data in Production: Moving Beyond Ontologies
Linked Data in Production: Moving Beyond OntologiesLinked Data in Production: Moving Beyond Ontologies
Linked Data in Production: Moving Beyond Ontologies
 
Igniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration WorkflowsIgniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration Workflows
 
Computer 10: Lesson 10 - Online Crimes and Hazards
Computer 10: Lesson 10 - Online Crimes and HazardsComputer 10: Lesson 10 - Online Crimes and Hazards
Computer 10: Lesson 10 - Online Crimes and Hazards
 
KubeConEU24-Monitoring Kubernetes and Cloud Spend with OpenCost
KubeConEU24-Monitoring Kubernetes and Cloud Spend with OpenCostKubeConEU24-Monitoring Kubernetes and Cloud Spend with OpenCost
KubeConEU24-Monitoring Kubernetes and Cloud Spend with OpenCost
 
Artificial Intelligence & SEO Trends for 2024
Artificial Intelligence & SEO Trends for 2024Artificial Intelligence & SEO Trends for 2024
Artificial Intelligence & SEO Trends for 2024
 
UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6
 
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdf
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdfIaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdf
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdf
 
Empowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership BlueprintEmpowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership Blueprint
 
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
 
20150722 - AGV
20150722 - AGV20150722 - AGV
20150722 - AGV
 
COMPUTER 10 Lesson 8 - Building a Website
COMPUTER 10 Lesson 8 - Building a WebsiteCOMPUTER 10 Lesson 8 - Building a Website
COMPUTER 10 Lesson 8 - Building a Website
 
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
 
Nanopower In Semiconductor Industry.pdf
Nanopower  In Semiconductor Industry.pdfNanopower  In Semiconductor Industry.pdf
Nanopower In Semiconductor Industry.pdf
 
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
 

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