티스토리 뷰
카메라
카메라를 이용하여 사진을 찍는 앱
프로젝트 생성 & 권한 요청
최소버전은 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에게 요청한 경우
* Activity의 onRequestPermissionsResult() 로 결과 리턴됨.
*/
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);
}
}
'Android' 카테고리의 다른 글
[Android] Android 와 Spring 연동 (2) | 2016.08.12 |
---|---|
[Android] 비콘(Beacon) (2) | 2016.08.11 |
[Android] SplashActivity ( 로딩화면 ) (1) | 2016.08.10 |
[Android] Jsoup 으로 HTML 파싱하기 (7) | 2016.08.09 |
[Android] 페이스북 타임라인에 포스팅하기, 글 검색하기 (0) | 2016.08.08 |
- Total
- Today
- Yesterday
- servlet
- table
- INSERT
- restfb
- indexOf
- order by
- 안드로이드 스튜디오
- onPostExecute
- REDIRECT
- 이클립스
- controller
- boj
- RequestMapping
- 안드로이드 비콘
- Baekjoon Online Judege
- Spring
- onBackPressed
- 자바
- list
- mybatis
- DP
- algorithm
- 예외처리
- maven
- sort
- AlertDialog.Builder
- jsp
- java
- BFS
- DFS
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |