Android workshop

1,966 views

Published on

0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,966
On SlideShare
0
From Embeds
0
Number of Embeds
21
Actions
Shares
0
Downloads
72
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Android workshop

    1. 1. INTERMEDIATEANDROIDMichael Galpin Bump Technologies
    2. 2. ABOUT: ME ‣ Android engineer, Bump Technologies ‣ ex-eBay: eBay Mobile for Android ‣ Android in Practice ‣ Social info ‣ @michaelg ‣ +Michael Galpin
    3. 3. BumpTechnologies • Creators of Bump app • Android + iOS • 65M+ Downloads • Creators of BumpCube • Hiring!
    4. 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/
    5. 5. MULTIMEDIA
    6. 6. “Of all of our inventions for masscommunication, pictures still speak themost universally understood language.” -- Walt Disney
    7. 7. DETECTINGCAPABILITIES
    8. 8. 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" />
    9. 9. Check the frontprivate 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;}
    10. 10. Check the frontprivate 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;}
    11. 11. But I have to supportAndroid 2.1
    12. 12. Reflection?
    13. 13. LOLZ// Cant use Build.VERSION_CODES.GINGERBREADif (Build.VERSION.SDK_INT >= 9){ PostFroyoClass wontThisBlowUp = new PostFroyoClass();}
    14. 14. These are my customers!
    15. 15. These are my customers!
    16. 16. Proprietary APIs FTW!import com.sprint.hardware.twinCamDevice.FrontFacingCamera;Camera evoCam = FrontFacingCamera.getFrontFacingCamera();
    17. 17. RESOURCES
    18. 18. MediaPlayer.framework?
    19. 19. MediaPlayer.framework?[MPMusicPlayerController iPodMusicPlayer] ??
    20. 20. MediaPlayer.framework?[MPMusicPlayerController iPodMusicPlayer] ?? [MusicLibrary sharedMusicLibrary] ???
    21. 21. MediaPlayer.framework?[MPMusicPlayerController iPodMusicPlayer] ?? [MusicLibrary sharedMusicLibrary] ??? UIImagePickerController ?
    22. 22. MediaPlayer.framework?[MPMusicPlayerController iPodMusicPlayer] ?? [MusicLibrary sharedMusicLibrary] ??? UIImagePickerController ?
    23. 23. MediaPlayer.framework?[MPMusicPlayerController iPodMusicPlayer] ?? [MusicLibrary sharedMusicLibrary] ??? UIImagePickerController ? Files !!!!
    24. 24. Inside your APK External
    25. 25. Just give it to me /res/rawResources res = this.getResources();InputStream stream = res.openRawResource(R.raw.sunflower);MediaPlayer.create(this, R.raw.constancy).start();
    26. 26. I like big / assetsand I cannot lie
    27. 27. 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(); } }});
    28. 28. File picturesDir = Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES);
    29. 29. File picturesDir = Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES);
    30. 30. IMAGES
    31. 31. Loading local imagesInputStream stream = new FileInputStream(imgFile);Bitmap bm = BitmapFactory.decodeStream(stream);
    32. 32. Loading local imagesInputStream stream = new FileInputStream(imgFile);Bitmap bm = BitmapFactory.decodeStream(stream);// calculate desired width and heightBitmap thumb = ThumbnailUtils.extractThumbnail(bm, width, height);Bitmap thumb = Bitmap.createScaledBitmap(bm, width, height, false);
    33. 33. Loading without explodingpublic static Bitmap decodeDownsizedBitmapStream(File file, int target, Context context) throwsIOException { 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;}
    34. 34. Loading web imagesURL url = new URL(urlString);// NOTE, be careful about just doing "url.openStream()"// its a shortcut for openConnection().getInputStream() and doesnt 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());
    35. 35. 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); } }}
    36. 36. Loading a dozen images isn’t cool. Y’know what’s cool?Loading a billion images.
    37. 37. 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; }}
    38. 38. Watch out for leakspublic 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; }}
    39. 39. How to build a cache?• WeakReferences?• SoftReferences?• WeakHashMap?• MapMaker?
    40. 40. 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; }}
    41. 41. Disk Cache• Context.getCacheDir()• SQLite• Environment.getExternalStorage()
    42. 42. Sidebar: Bitmaps & HeapReported by andreas....@googlemail.com, May 22, 2010Note: This is NOT a requst for assistance!In my applications, I keep getting the following exception:E/AndroidRuntime( 1420): java.lang.OutOfMemoryError: bitmap size exceedsVM budgetE/AndroidRuntime( 1420): atandroid.graphics.BitmapFactory.nativeDecodeStream(Native Method)E/AndroidRuntime( 1420): atandroid.graphics.BitmapFactory.decodeStream(BitmapFactory.java:459)E/AndroidRuntime( 1420): atandroid.graphics.BitmapFactory.decodeStream(BitmapFactory.java:515)E/AndroidRuntime( 1420): atde.schildbach.bitmapbug.MyActivity.bitmap(MyActivity.java:38)Comment 1 by romaingu...@gtempaccount.com, May 23, 2010Your app needs to use less memory. http://code.google.com/p/android/issues/detail?id=8488
    43. 43. 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());
    44. 44. @Override View Holderspublic 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); }}
    45. 45. Sidebar: Strict Mode
    46. 46. CONTENTPROVIDERS
    47. 47. SQL? NoSQL? SortOfSQL!
    48. 48. QueriesCursor cursor = getContentResolver().query(table, columns, whereClause, paramValues, sortOrder);while (cursor.moveToNext()){ // process results}cursor.close();
    49. 49. Musicimport 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 dont get ringtones, podcasts, etc.String whereClause = IS_MUSIC + " = ?";String[] whereValues = {"1"};cursor = managedQuery(EXTERNAL_CONTENT_URI, columns, whereClause, whereValues, null);
    50. 50. ContactsString[] 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);
    51. 51. Scanning media
    52. 52. Scanning 101MediaScannerConnection 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();
    53. 53. Cursor Adapter
    54. 54. CursorAdapter
    55. 55. Avoid
    56. 56. Use Other Appsprivate static final int SELECT_VIDEO = 1;private Uri videoUri;@Overrideprotected 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); } });}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == SELECT_VIDEO && resultCode == RESULT_OK){ videoUri = data.getData(); }}
    57. 57. ANIMATION
    58. 58. Dissolve Animationprivate 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;}
    59. 59. Honeycomb+
    60. 60. AnimatorsImageView 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(); }});
    61. 61. A/VPLAYBACK
    62. 62. 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); } }});
    63. 63. Handler?
    64. 64. Handler?Pipeline ThreadLooper.prepare();handler = new Handler();// handle tasks in queueLooper.loop();
    65. 65. Handler? Thread Pipeline Thread Looper.prepare(); handler = new Handler(); // handle tasks in queue Looper.loop();// long running taskMessage msg = handler.obtainMessage();handler.sendMessage(msg);
    66. 66. 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 taskMessage msg = handler.obtainMessage();handler.sendMessage(msg);
    67. 67. Theme Muzakprivate MediaPlayer player;@Overridepublic void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setupThemeMusic();}@Overridepublic 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(); }
    68. 68. Activity Lifecycle
    69. 69. Video PlaybackUri 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();
    70. 70. TAKE APICTURE
    71. 71. 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);@Overrideprotected 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); }}
    72. 72. EXIF!
    73. 73. Popular on Facebook
    74. 74. Correctly OrientedOptions 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);}
    75. 75. Geo TaggingExifInterface 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”
    76. 76. Where?
    77. 77. Getting a (geo) fixLocationManager 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 });}
    78. 78. To the cloud!
    79. 79. Uploading a photoString 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);
    80. 80. Upload ServiceUploadService 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);
    81. 81. Process Priority Foreground Visible Service Background Empty
    82. 82. A/VRECORDING
    83. 83. Video Previewprivate 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;@Overrideprotected 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(); }}
    84. 84. Video Previewprivate 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(); }};
    85. 85. Video Previewprivate 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();}

    ×