PERTEMUAN KE – 9 Camera dan Multimedia
A. TUJUAN Mahasiswa diharapkan dapat memahami dan mengetahui tentang komponen widget, yaitu Camera dan Multimedia yang digunakan pada aplikasi mobile.
B. TEORI SINGKAT 1. Melakukan pengecekan terhadap kamera Sebelum berusaha untuk mengakses kamera pada sebuah perangkat perangkat Android, sangat penting untuk mengimplementasikan kode untuk memverifikasi perangkat keras kamera. Hal ini sangat penting karena tidak semua perangkat android menggunakan kamera. Ada
tidaknya
kamera
bisa
diidentifikasi dengan memanggil method PackageManager.hasSystemFeature(). Untuk mengecek kehadiran front‐facing camera, kode harus mengecek kehadiran dari fitur PackageManagementFEATUR_CAMERA_FRONT. Hal ini bisa dimasukkan ke dalam method berikut ini: private boolean hasCamera() { if (getPackageManager().hasSystemFeature( PackageManager.FEATURE_CAMERA_FRONT)){ return true; } else { return false; } }
Kehadiran kamera yang arahnya sama dengan arah layar display juga bisa diverifikasi dengan menggunakan konstanta PackageManagerFEATURE_CAMERA. Pengujian untuk melihat apakah sebuah perangkat mempunyai kamera atau tidak bisa dilakukan dengan mereferensi packageManager FEATURE CAMERA ANY. 2. Memanggil Intent Video Capture Penggunaan intent video capture paling sedikit melibatkan implementasi kode untuk memanggil aktivitas intent dan sebuah method untuk menangani kembalian (return) dari aktivitas itu. Intent video recording yang built‐in di dalam android direpresentasikan oleh MediaStore ACTION VIDEO CAPTURE dan bisa dideklarasikan seperti berikut: private static final int VIDEO_CAPTURE = 101; Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); startActivityForResult(intent, VIDEO_CAPTURE);
Bila dilakukan dengan cara ini, intent akan menempatkan rekaman video ke dalam sebuah file menggunakan lokasi dan nama file default. Lokasi khusus untuk file media bisa ditentukan menggunakan method putExtra() dari intent yang mereferensi konstanta kunci MediaStoreEXTRA OUTPUT untuk melewatkan nilai URI target. Misalnya kode di bawah ini menentukan bahwa video harus disimpan pada SD card di dalam sebuah file yang diberi nama myvideo.mp4
File mediaFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/myvideo.mp4"); Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); Uri videoUri = Uri.fromFile(mediaFile); intent.putExtra(MediaStore.EXTRA_OUTPUT, videoUri); startActivityForResult(intent, VIDEO_CAPTURE);
Pada saat user menyelesaikan atau membatalkan sesi video recording, method onActivityResult() dari pemanggilan aktivitas akan dipanggil. Method ini harus memeriksa apakah kode yang diminta dilewatkan sebagai sebuah argumen sesuai dengan ketentuan pada saat intent diluncurkan, memferifikasi apakah sessi perekaman berhasil dan mengekstraks jalur file media video. 3. Memanggil Intent Image Capture Sebagai tambahan untuk intent video capture, Android juga mempunyai sebuah intent yang dirancang untuk mengambil foto diam dengan menggunakan kamera built‐in. Intent ini diluncurkan dengan mereferensi MediaStore.ACTION_IMAGE_CAPTURE: private static final int IMAGE_CAPTURE = 102; Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); startActivityForResult(intent, IMAGE_CAPTURE);
Seperti pada video capture, intent itu bisa dimasukkan ke lokasi dan nama file dimana gambar akan disimpan, atau dibebaskan untuk mengguakan lokasi dan konvensi penamaan default.
C. PRAKTIK 1. Buat project baru. Buat layout seperti berikut
2. Kode XML (activity_main.xml) adalah sebagai berikut.
<Button android:text="@string/btnIntent" android:id="@+id/btnIntent" android:layout_height="wrap_content" android:layout_width="0dp" android:layout_weight="1" /> <Button android:text="@string/btnIntendS" android:id="@+id/btnIntendS" android:layout_height="wrap_content" android:layout_width="0dp" android:layout_weight="1" />
3. Tambahkan pada resource string (strings.xml), variabel string berikut. <string <string <string <string
name="btnIntent">Ambil Gambar (ukuran besar) name="btnIntendS">Ambil Gambar (ukuran kecil) name="album_name">albumku name="cannot">tidak bisa
4. Kemudian buat file-file java berikut ini. File pertama: MainActivity.java package belajar.coba.ningrum.trymultimedia1; import import import import import import import import import import import import import import import import
android.content.Context; android.content.Intent; android.content.pm.PackageManager; android.content.pm.ResolveInfo; android.graphics.Bitmap; android.graphics.BitmapFactory; android.net.Uri; android.os.Build; android.os.Bundle; android.os.Environment; android.provider.MediaStore; android.support.v7.app.AppCompatActivity; android.util.Log; android.view.View; android.widget.Button; android.widget.ImageView;
import import import import import
java.io.File; java.io.IOException; java.text.SimpleDateFormat; java.util.Date; java.util.List;
public class MainActivity extends AppCompatActivity { private static final int ACTION_TAKE_PHOTO_B = 1; private static final int ACTION_TAKE_PHOTO_S = 2; private static final String BITMAP_STORAGE_KEY = "viewbitmap"; private static final String IMAGEVIEW_VISIBILITY_STORAGE_KEY = "imageviewvisibility"; private ImageView mImageView; private Bitmap mImageBitmap; private String mCurrentPhotoPath; private static final String JPEG_FILE_PREFIX = "IMG_"; private static final String JPEG_FILE_SUFFIX = ".jpg"; private AlbumStorageDirFactory mAlbumStorageDirFactory = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mImageView = (ImageView) findViewById(R.id.imageView1); mImageBitmap = null; Button picBtn = (Button) findViewById(R.id.btnIntent); setBtnListenerOrDisable( picBtn, mTakePicOnClickListener, MediaStore.ACTION_IMAGE_CAPTURE ); Button picSBtn = (Button) findViewById(R.id.btnIntendS); setBtnListenerOrDisable( picSBtn, mTakePicSOnClickListener, MediaStore.ACTION_IMAGE_CAPTURE ); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) { mAlbumStorageDirFactory = new FroyoAlbumDirFactory(); } else { mAlbumStorageDirFactory = new BaseAlbumDirFactory(); } }
private String getAlbumName() { return getString(R.string.album_name); }
private File getAlbumDir() { File storageDir = null; if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { storageDir = mAlbumStorageDirFactory.getAlbumStorageDir(getAlbumName()); if (storageDir != null) { if (! storageDir.mkdirs()) { if (! storageDir.exists()){ Log.d("CameraSample", "failed to create directory"); return null; } } } } else { Log.v(getString(R.string.app_name), "External storage is not mounted READ/WRITE."); } return storageDir; } private File createImageFile() throws IOException { String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String imageFileName = JPEG_FILE_PREFIX + timeStamp + "_"; File albumF = getAlbumDir(); File imageF = File.createTempFile(imageFileName, JPEG_FILE_SUFFIX, albumF);
return imageF; } private File setUpPhotoFile() throws IOException { File f = createImageFile(); mCurrentPhotoPath = f.getAbsolutePath(); return f; } private void setPic() { int targetW = mImageView.getWidth(); int targetH = mImageView.getHeight(); BitmapFactory.Options bmOptions = new BitmapFactory.Options(); bmOptions.inJustDecodeBounds = true; BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions); int photoW = bmOptions.outWidth; int photoH = bmOptions.outHeight; int scaleFactor = 1; if ((targetW > 0) || (targetH > 0)) { scaleFactor = Math.min(photoW/targetW, photoH/targetH); } bmOptions.inJustDecodeBounds = false; bmOptions.inSampleSize = scaleFactor; bmOptions.inPurgeable = true; Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions); mImageView.setImageBitmap(bitmap); mImageView.setVisibility(View.VISIBLE); } private void galleryAddPic() { Intent mediaScanIntent = new Intent("android.intent.action.MEDIA_SCANNER_SCAN_FILE"); File f = new File(mCurrentPhotoPath); Uri contentUri = Uri.fromFile(f); mediaScanIntent.setData(contentUri); this.sendBroadcast(mediaScanIntent); } private void dispatchTakePictureIntent(int actionCode) { Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); switch(actionCode) { case ACTION_TAKE_PHOTO_B: File f = null; try { f = setUpPhotoFile(); mCurrentPhotoPath = f.getAbsolutePath(); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f)); } catch (IOException e) { e.printStackTrace(); f = null; mCurrentPhotoPath = null; } break; default: break; } // switch startActivityForResult(takePictureIntent, actionCode); } private void handleSmallCameraPhoto(Intent intent) { Bundle extras = intent.getExtras(); mImageBitmap = (Bitmap) extras.get("data"); mImageView.setImageBitmap(mImageBitmap); mImageView.setVisibility(View.VISIBLE);
} private void handleBigCameraPhoto() { if (mCurrentPhotoPath != null) { setPic(); galleryAddPic(); mCurrentPhotoPath = null; } } Button.OnClickListener mTakePicOnClickListener = new Button.OnClickListener() { @Override public void onClick(View v) { dispatchTakePictureIntent(ACTION_TAKE_PHOTO_B); } }; Button.OnClickListener mTakePicSOnClickListener = new Button.OnClickListener() { @Override public void onClick(View v) { dispatchTakePictureIntent(ACTION_TAKE_PHOTO_S); } }; @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case ACTION_TAKE_PHOTO_B: { if (resultCode == RESULT_OK) { handleBigCameraPhoto(); } break; } // ACTION_TAKE_PHOTO_B case ACTION_TAKE_PHOTO_S: { if (resultCode == RESULT_OK) { handleSmallCameraPhoto(data); } break; } // ACTION_TAKE_PHOTO_S } // switch } @Override protected void onSaveInstanceState(Bundle outState) { outState.putParcelable(BITMAP_STORAGE_KEY, mImageBitmap); outState.putBoolean(IMAGEVIEW_VISIBILITY_STORAGE_KEY, (mImageBitmap != null) ); super.onSaveInstanceState(outState); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); mImageBitmap = savedInstanceState.getParcelable(BITMAP_STORAGE_KEY); mImageView.setImageBitmap(mImageBitmap); mImageView.setVisibility( savedInstanceState.getBoolean(IMAGEVIEW_VISIBILITY_STORAGE_KEY) ? ImageView.VISIBLE : ImageView.INVISIBLE ); } public static boolean isIntentAvailable(Context context, String action) { final PackageManager packageManager = context.getPackageManager(); final Intent intent = new Intent(action); List
list = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); return list.size() > 0; } private void setBtnListenerOrDisable(
Button btn, Button.OnClickListener onClickListener, String intentName ) { if (isIntentAvailable(this, intentName)) { btn.setOnClickListener(onClickListener); } else { btn.setText( getText(R.string.cannot).toString() + " " + btn.getText()); btn.setClickable(false); } } }
File kedua: FroyoAlbumDirFactory.java import android.os.Environment; import java.io.File; public final class FroyoAlbumDirFactory extends AlbumStorageDirFactory { @Override public File getAlbumStorageDir(String albumName) { // TODO Auto-generated method stub return new File( Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES ), albumName ); } }
File ketiga: BaseAlbumDirFactory import android.os.Environment; import java.io.File; public final class BaseAlbumDirFactory extends AlbumStorageDirFactory { // Standard storage location for digital camera files private static final String CAMERA_DIR = "/dcim/"; @Override public File getAlbumStorageDir(String albumName) { return new File ( Environment.getExternalStorageDirectory() + CAMERA_DIR + albumName ); } }
File keempat: AlbumStorageDirFactory import java.io.File; abstract class AlbumStorageDirFactory { public abstract File getAlbumStorageDir(String albumName); }
5. Tambahkan pada file AndroidManifest.xml dengan permission berikut (diblok abu-abu).
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.latihan.darmanto.modul8multimedia">
<uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.RECORD_AUDIO" />
6. Coba jalankan dan amati hasilnya. Jelaskan jalannya program.
D. LATIHAN • •
Latihan diberikan oleh dosen pengampu pada saat praktikum. Dikerjakan di laboratorium pada jam praktikum.
E. TUGAS • •
Tugas diberikan oleh dosen pengampu pada akhir praktikum. Dikerjakan di rumah dan dilampirkan pada laporan.