티스토리 뷰

Android

[Android] 카메라

best 2016. 8. 13. 15:00

카메라 


카메라를 이용하여 사진을 찍는 앱



프로젝트 생성 & 권한 요청


최소버전은 16(젤리빈)으로 프로젝트를 생성한다.


Manifest에서 카메라 이용권한과 외장 메모리 쓰기 권한을 요청한다.


<!-- Camera 를 사용한다고 사용자에게 알린다. -->
<uses-feature android:name="android.hardware.camera2" />

<!-- 찍힌 사진을 외장 메모리에 저장하기 위해서 외장 USB에 쓰기 권한을 요청한다.-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />



activity_main.xml 수정


사진찍기 버튼을 만들기 위해 activity_main.xml에서 버튼을 추가한다.


그리고 찍은 사진을 보이기 위한 ImageView를 추가한다.


<?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="com.ktds.jmj.mycameraapp.MainActivity">

<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/btnTakeCamera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="사진 찍기" />

</LinearLayout>

<ImageView
android:id="@+id/lvPicture"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>



PermissionRequest 자바 클래스 파일 생성


package com.ktds.jmj.mycameraapp;

import android.app.Activity;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Build;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;

/**
* Created by Minchang Jang on 2016-06-12.
*/
public class PermissionRequester {

/**
* 요청 AndroidOS의 버젼이 마쉬멜로우 이상 버젼이 아닐 경우
*/
public static final int NOT_SUPPORT_VERSION = 2;

/**
* 요청 권한을 이미 가지고 있을 경우
*/
public static final int ALREADY_GRANTED = -1;

/**
* 권한을 System에게 요청한 경우
* ActivityonRequestPermissionsResult() 로 결과 리턴됨.
*/
public static final int REQUEST_PERMISSION = 0;

private Activity context;
private Builder builder;

private void setBuilder(Builder builder) {
this.builder = builder;
}

private PermissionRequester(Activity context) {
this.context = context;
}

public int request(final String permission, final int requestCode, final OnClickDenyButtonListener denyAction) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
/*
* 해당 App이 특정 권한을 가지고 있는지 검사함.
* 리턴결과는 PackageManager.PERMISSION_DENIED PackageManager.PERMISSION_GRANTED로 나눠짐.
* PackageManager.PERMISSION_DENIED : 권한이 없음
* PackageManager.PERMISSION_GRANTED : 권한이 있음.
*/
int permissionCheck = ContextCompat.checkSelfPermission(context, permission);

/*
* 해당 권한이 없을 경우 처리 방법
*/
if (permissionCheck == PackageManager.PERMISSION_DENIED) {

/*
* 권한을 취득할 때 사용자로부터 확인을 받아야 하는지 확인
* 여기서 true가 나올 경우는 해당 앱에서 한번이라도 권한을 Deny한 경우일 때 말고는 없음.
* 권한에 대해서 허가하지 않은 경우 다시 한번 권한의 취득을 위해 사용자에게 이유를 고지해야 함.
* Marshmellow 버젼 이상부터 사용가능함.
*/
if (context.shouldShowRequestPermissionRationale(permission)) {

/*
* 권한 취득해야 하는 이유를 Dialog 등을 통해서 알린다.
*/
AlertDialog.Builder dialog = new AlertDialog.Builder(context);
dialog.setTitle(builder.getTitle())
.setMessage(builder.getMessage())
.setPositiveButton(builder.getPositiveButtonName(), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
/*
* 권한의 취득을 요청한다.
* 취득하고자 하는 권한을 배열에 넣고 요청한다.
* 뒤에 들어가는 파라미터(requestCode) onRequestPermissionsResult() 에서 권한 취득 결과에서 사용된다.
* startActiviryForResult Request Code와 유사함.
*/
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
context.requestPermissions(new String[]{permission}, requestCode);
}
}
})
.setNegativeButton(builder.getNegativeButtonName(), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
denyAction.onClick(context);
}
}).create().show();

return REQUEST_PERMISSION;
} else {
/*
* 권한의 취득 요청을 처음 할 때
* 권한의 취득을 요청한다.
* 취득하고자 하는 권한을 배열에 넣고 요청한다.
* 뒤에 들어가는 파라미터(1000) onRequestPermissionsResult() 에서 권한 취득 결과에서 사용된다.
* startActiviryForResult Request Code와 유사함.
*/
context.requestPermissions(new String[]{permission}, requestCode);
return REQUEST_PERMISSION;
}

} else {
/*
* 이미 권한을 가지고 있을 경우
* 해야할 일을 수행한다.
*/
return ALREADY_GRANTED;
}

}

return NOT_SUPPORT_VERSION;
}

public static class Builder {

private PermissionRequester requester;

public Builder(Activity context) {
requester = new PermissionRequester(context);
}

private String title = "권한 요청";
private String message = "기능의 사용을 위해 권한이 필요합니다.";
private String positiveButtonName = "";
private String negativeButtonName = "아니요";

public String getTitle() {
return title;
}

public Builder setTitle(String title) {
this.title = title;
return this;
}

public String getMessage() {
return message;
}

public Builder setMessage(String message) {
this.message = message;
return this;
}

public String getPositiveButtonName() {
return positiveButtonName;
}

public Builder setPositiveButtonName(String positiveButtonName) {
this.positiveButtonName = positiveButtonName;
return this;
}

public String getNegativeButtonName() {
return negativeButtonName;
}

public Builder setNegativeButtonName(String negativeButtonName) {
this.negativeButtonName = negativeButtonName;
return this;
}

public PermissionRequester create() {
this.requester.setBuilder(this);
return this.requester;
}

}

public interface OnClickDenyButtonListener {

public void onClick(Activity activity);

}

}





MainActivity 수정


카메라 앱이 있는지 확인하고, 카메라 앱을 실행시킨다.


저장장소를 설정한 뒤 파일을 저장하고 ImageView에 사진을 보여준다.


package com.ktds.jmj.mycameraapp;

import android.Manifest;
import android.app.Activity;
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.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 android.widget.Toast;

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 Button btnTakeCamera;
private ImageView lvPicture;

private String imagePath;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

btnTakeCamera = (Button) findViewById(R.id.btnTakeCamera);
lvPicture = (ImageView) findViewById(R.id.lvPicture);

btnTakeCamera.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//1. Camera Application 이 있는지 조사한다.
if ( isExistsCameraApplication() ) {
// 2. Camera Application을 실행한다.
Intent cameraApp = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

// 3. 찍은 사진을 보관할 파일 객체를 만들어서 보낸다.
File picture = savePictureFile();
if ( picture != null) {
cameraApp.putExtra(MediaStore.EXTRA_OUTPUT, picture);
startActivityForResult(cameraApp, 10000);
}
}
}
});

}


private boolean isExistsCameraApplication() {

// 안드로이드의 모든 어플리케이션을 얻어온다.
PackageManager packageManager = getPackageManager();

//카메라 앱
Intent cameraApp = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

// MediaStore.ACTION_IMAGE_CAPTURE Intent 를 처리할 수 있는 Application 을 가져온다.
List<ResolveInfo> cameraApps = packageManager.queryIntentActivities(cameraApp, PackageManager.MATCH_DEFAULT_ONLY);


return cameraApps.size() > 0;
}

private File savePictureFile() {

PermissionRequester.Builder requester = new PermissionRequester.Builder(this);
int result = requester
.create()
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE, 20000, new PermissionRequester.OnClickDenyButtonListener() {
@Override
public void onClick(Activity activity) {

}
});

// 거부를 누르지 않았다면 ( 권한 수락시 )
if ( result == PermissionRequester.ALREADY_GRANTED || result == PermissionRequester.REQUEST_PERMISSION ) {
// 사진 파일의 이름을 만든다.
String timeStamp = new SimpleDateFormat("yyyyMMdd HHmmss").format(new Date());
String fileName = "IMG" + timeStamp;

// 사진 파일이 저장될 장소를 구한다.
File pictureStorage = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
"MYAPP/");

if ( !pictureStorage.exists() ) {
pictureStorage.mkdirs();
}

try {
File file = File.createTempFile(fileName, ".jpg", pictureStorage);
// 사진 파일의 절대경로를 얻어온다.
// 나중에 ImageView에 보여줄 때 필요하다.
imagePath = file.getAbsolutePath();

Intent mediaScanIntent = new Intent( Intent.ACTION_MEDIA_SCANNER_SCAN_FILE );

File f = new File( imagePath);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
this.sendBroadcast(mediaScanIntent);

return file;
} catch (IOException e) {
e.printStackTrace();
}

}

return null;
}



@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {

if ( requestCode == 10000 && resultCode == RESULT_OK ){
// 사진을 IMAGE_VIEW 에 저장한다.

BitmapFactory.Options factory = new BitmapFactory.Options();
// factory.inJustDecodeBounds = true;
// BitmapFactory.decodeFile(imagePath);

factory.inJustDecodeBounds = false;
factory.inPurgeable = true;

Bitmap bitmap = BitmapFactory.decodeFile(imagePath, factory);
lvPicture.setImageBitmap(bitmap);
}
super.onActivityResult(requestCode, resultCode, data);
}
}


댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함