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 videoharus 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.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="belajar.coba.ningrum.trymultimedia1.MainActivity">
<LinearLayout
android:orientation="horizontal"
android:layout_height="wrap_content"
android:layout_width="match_parent" >
<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" />
</LinearLayout>
<ImageView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:visibility="visible"
android:id="@+id/imageView1" />
</LinearLayout>
3. Tambahkan pada resource string (strings.xml), variabel string berikut.
<string name="btnIntent">Ambil Gambar (ukuran besar)</string>
<string name="btnIntendS">Ambil Gambar (ukuran kecil)</string>
<string name="album_name">albumku</string>
<string name="cannot">tidak bisa</string>
4. Kemudian buat file-file java berikut ini.
File pertama: MainActivity.java
package belajar.coba.ningrum.trymultimedia1;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import 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<ResolveInfo> 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).
<?xml version="1.0" encoding="utf-8"?>
<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" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
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.