반응형

얼마 전 삼성개발자사이트에 들어가서 둘러보다가 아래와 같이 삼성 카메라 SDK 지원 중단이 된다는 공지를 보았습니다.

 

As of Dec. 1, 2019, the Camera SDK(v1.0.0 - v1.3.2) is deprecated on all devices. We reget any inconvenience.

그 아래에 몇 개월 전 배포된 SDK 버전이 처량하게 보입니다.

 

 

외부 개발자들을 참여시켜서 기존 Android 카메라 API에서 지원하지 않는 삼성 폰의 카메라 확장기능을 지원하고자 시작한 것 같은데 아쉽다는 생각이 들었습니다.

 

SDK가 별거 아니라고 생각하는 분도 계실 수 있지만, SDK 개발하고 검증하고 배포한 이후 유지 보수하는 데는 많은 시간이 걸립니다.

 

왜 지원을 중단했는지 나름대로 생각을 해보니 구글에서 발표한 CameraX와 연관이 있는 것 같습니다.

 

관련한 근거로 SDC(삼성 개발자 컨퍼런스)에 발표된 아래 영상이 19.11월 초에 올라왔습니다.

 

제목이 Introducing the CameraX with Samsung인데, 구글의 안드로이드 카메라 프레임워크쪽 PM이 등장합니다.

 

CameraX 기능도 삼성 카메라 SDK와 중복되는 것이 많습니다.

 

향후 2개가 동시에 존재하는 것이 불가능한 것이 "카메라 확장 기능"을 위해서 삼성 카메라 SDK보다 여러 단말 벤더들도 지원할 수 있는 CameraX를 개발자들이 선호하게 될 것이기에 어쩔 수 없는 선택이었다고 생각됩니다.

 

삼성 입장에서는 아쉬울 수도 있지만, 뻔한 결과가 보이는 것을 계속 붙잡고 있을 수는 없는 거니깐요.

 

구글 입장에서 삼성은 아주 고마운 존재일 것 입니다.

 

새로운 기술이나 하드웨어에 대해서 삼성이 앞장서서 나가주고 검증을 해주니깐요.

 

일례로 지금은 당연히 카메라가 2개 이상 지원하지만 전에는 안드로이드 초기에는 Camera API에서 1개의 카메라만 지원했습니다.

 

(제가 기억하기로는) 삼성이 먼저 피처폰에서처럼 전면 카메라를 넣어주었죠. 이후 구글은 Camera API에 다수 카메라 지원하도록 적용하였고요.

 

작년 갤럭시 폴드 개발 시에는 폴더블 API 지원이 되도록 구글에서 많은 공조가 있었을 것입니다.

 

이번 글은 여기까지입니다. 읽어주셔서 감사합니다. 

 

반응형

Camera API를 어떻게 사용하는지 궁금할 때 참조할 수 있는 좋은 방법을 알려 드리겠습니다.

 

안드로이드 단말이 GMS를 탑재하고 구글의 승인을 받으려면 구글의 요구하는 조건을 만족시켜줘야 합니다.

 

기본적으로 CDD부터 프레임워크 호환성 확인을 위한 CTS 등 여러 테스트를 거치게 됩니다.

 

이중 CTS는 안드로이드 플랫폼에서 프레임워크 동작의 신뢰성을 위한 각종 API를 테스트합니다.

 

이 테스트 코드는 구글에서 작성하였고 소스가 오픈되어 있습니다.

 

예를 들어보겠습니다.

 

Camera API 중에서 setFocusMode를 어떻게 사용하는지 궁금하면 구글 검색으로 stackoverflow.com에 참고할 수 있는 대부분의 답변이 나옵니다.

 

아래의 경우는 setFocusMode가 동작하지 않는다는 문의와 답변입니다.

(관련 링크: https://stackoverflow.com/questions/11623266/camera-parameters-setfocusmode-is-not-working)

  

 

 

 

 

간결하고 문제 해결을 위한 무난한 답변입니다.

 

위의 문제는 지원하지 않는 Camera Focus mode를 사용하려고 해서 발생하는 문제였습니다.

 

답변에서는 지원 여부를 체크(getSupportedFocusModes)해서 지원하면 설정(setFocusMode)하게 처리되어 있습니다.

 

그럼, CTS 쪽에서는 어떻게 사용하고 있는지 볼까요?

 

여기에서도 체크(getSupportedFocusModes)후 지원하면 설정(setFocusMode)하게 처리되어 있습니다.

 

 

stackoverflow나 cts 모두 setFocusMode 사용하는 방법에 대해서 가리키는 것은 argument인 focus mode가 지원하는지 getSupportedFocusModes로 체크해서 지원하면 사용하도록 처리해야 한다는 것을 알 수 있습니다.

 

CTS 쪽 검색은 구글에서 아래와 같이 해주면 됩니다. (검색창에 "API명 site:android.googlesource.com/platform/cts")

 

 

CTS에 있는 모든 코드가 무결하다고 할 수는 없지만, 아무래도 구글에서 작성한 코드이기에 일정 수준이 상의 신뢰성이 보장된다고 볼 수 있습니다. stackoverflow.com에 나와 있지 않거나 거기 있는 코드가 신뢰 되지 않는다면 CTS에서 코드를 찾아보실 것을 권장해 드립니다.

 

이번 글은 여기까지입니다. 도움이 되셨기를 바랍니다.

반응형

안녕하세요. Simple& Happy Dev입니다.

앞선 글에서 손전등 앱을 개발하기 위해 Camera2 API를 이용해서 카메라 플래시를 제어하는 방법을 적어보았는데, 쉽지 않으셨을 겁니다.
손전등 앱으로는 잘 사용하지 않는 방법이니 Camera2에 대해서 공부했다고 위안으로 삼으셔도 됩니다.

이번에 알려드리는 방법은 이전 방법들 대비해서 매우 간단한  Flashlight API를 이용하는 방법입니다.

Android 6.0 이전까지 플래시는 카메라 디바이스의 보조 장치이고, 손전등에 대해서 고려되지 않았습니다.
그로 인하여 Camera/Camera2 API로 구현 시 비효율적인 부분이 많이 있었습니다.

Android 6.0(Marshmello, API level 23)부터는 손전등을 고려해서 Flashlight API가 추가되었고, 또한 안드로이드 시스템 UI에서 손전등이 자체 내장이 되기 시작했습니다.

아래와 같이 퀵세팅(QuickSetting)에 가면 손전등 타일이 추가되어 있습니다.

Flashlight API는 매우 간단하면서 카메라 권한이 필요하지 않다는 장점이 있습니다. 반면에 Android 6.0 이상의 단말기에만 동작한다는 제약성도 있습니다.

[Flashlight API 이용한 손전등 앱]

Camera API와 Camera2 API를 이용한 손전등 앱에서는 AndroidManifest.xml에 카메라 권한(android.permission.CAMERA)이 명시되어 있지 않으면 Exception이 발생합니다.

Camera / Camera2 API의 openCamera()를 호출하면, 내부에서 permission check하는 루틴에서 에러를 리턴서 Exception을 발생하게 합니다.

특히, Camera2에서는 Annotation(@RequiresPermission)으로 인하여 빌드 전에 미리 오류에 대한 확인이 가능합니다. 

@RequiresPermission(android.Manifest.permission.CAMERA)
public void openCamera(@NonNull String cameraId,
@NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler)
throws CameraAccessException {

openCameraForUid(cameraId, callback, handler, USE_CALLING_UID);
}

그런데, Flashlight API의 경우 Camera2에 추가된 것이지만, 사전에 openCamera() 하지 않고 사용할 수 있습니다.
그 결과 카메라 권한이 없어도 된 것입니다.

Flashlight API(setTorchMode) 이용한 손전등 앱에서 플래시가 동작하는 과정은 아래와 같습니다.

준비작업: 플래시 존재 여부 체크 - CameraManager 객체의 인스턴스 생성

플래시 켜기: setTorchMode(cameraId, true)

플래시 끄기: setTorchMode(cameraId, false)

매우 간단하기에 바로 소스로 들어가 보겠습니다.

[소스 설명]

레이아웃 (activity_main.xml) 
 
화면 한가운데 별 모양 버튼을 하나 추가 후 이걸 누르면 플래시가 켜지도록 할 예정입니다. 그리고, 한 번 더 누르면 버튼이 토글되어서 꺼지도록 하겠습니다. 별 모양 버튼은 SDK에 내장된 리소스를 사용하시면 됩니다. (앞쪽에 있는 글들과 동일함)
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<ImageButton
android:id="@+id/ibFlashOnOff"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@android:drawable/btn_star_big_off"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>


자바 (MainActivity.java)

onCreate에서는 기기에 플래시가 지원하지 않으면 메시지 출력하고 3초 후 종료하도록 처리(delayedFinish())하도록 만들어 줍니다.
또한 별 모양 버튼에 대한 클릭 리스너를 만들어서 클릭 시 플래시를 켜주거나 꺼주고(flashlight()), 플래시 켜짐 상태에 따른 별 모양 이미지(켜짐: 노란색 별, 꺼짐: 흰색 별)를 변경하도록 처리해줍니다. (여기까지는 앞에 있는 부분과 공통)

Flashlight API(setTorchMode)를 사용하기 위해서 CameraManager 객체의 인스턴스를 획득합니다.

package com.example.help.nopermissionflashlight;

import android.content.pm.PackageManager;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageButton;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
private ImageButton mImageButtonFlashOnOff;
private boolean mFlashOn;

private CameraManager mCameraManager;
private String mCameraId;

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

if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)) {
Toast.makeText(getApplicationContext(), "There is no camera flash.\n The app will finish!", Toast.LENGTH_LONG).show();

delayedFinish();
return;
}

mCameraManager = (CameraManager) getSystemService(CAMERA_SERVICE);

mImageButtonFlashOnOff = findViewById(R.id.ibFlashOnOff);
mImageButtonFlashOnOff.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
flashlight();
mImageButtonFlashOnOff.setImageResource(mFlashOn ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off);
}
});
}

private void delayedFinish() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
finish();
}
}, 3500);
}

버튼을 눌러 flashlight()가 호출되면, CameraManager를 통해 카메라 id들을 가져온 후 필요한 카메라 특성을 구하고(getCameraCharacteristics), 원하는 조건(플래시 사용이 가능 & 화면 기준으로 뒤쪽에 있는 카메라)에 해당하는 카메라 id(주로 "0")를 구합니다.

이후 플래시 상태를 반전하기 위해서 mFlashOn을 토글시켜주고, setTorch()에 위에서 구한 카메라 id와 mFlashOn을 argument로 넘겨줍니다. setTroch()가 호출이 되면 mFlashOn 상태에 따라서 플래시가 켜지거나 꺼지게 됩니다.

void flashlight() {
if (mCameraId == null) {
try {
for (String id : mCameraManager.getCameraIdList()) {
CameraCharacteristics c = mCameraManager.getCameraCharacteristics(id);
Boolean flashAvailable = c.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
Integer lensFacing = c.get(CameraCharacteristics.LENS_FACING);
if (flashAvailable != null && flashAvailable
&& lensFacing != null && lensFacing == CameraCharacteristics.LENS_FACING_BACK) {
mCameraId = id;
break;
}
}
} catch (CameraAccessException e) {
mCameraId = null;
e.printStackTrace();
return;
}
}

mFlashOn = !mFlashOn;

try {
mCameraManager.setTorchMode(mCameraId, mFlashOn);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}

프로젝트 압축화일
NoPermissionFlashlight.zip


앱 동작 영상

 


기타정보

Flashlight API를 이용하게 되면 Flashlight를 독점적으로 소유할 수 없습니다.
이것의 의미는 Flashlight API를 사용하는 다른 앱에서 똑같이 Flashlight API를 호출하게 되면 그쪽으로 소유가 넘어간다는 의미입니다.

아래 테스트 영상과 함께 설명드리겠습니다. 영상에는 세 가지 손전등앱이 있습니다.
1. 시스템 UI인 QuickSetting의 손전등
2. Camera API로 만든 PermissionFlashlight
3. Flashlight API로 만든 NoPermissionFlashlight

[case 1]
PermissionFlashlight 앱에서 Flash를 켜고, QuickSetting의 손전등을 확인하면 아이콘이 On이지만 Dimming 된 상태입니다.
이것의 의미는 QuickSetting의 손전등에서 Flashlight를 소유해서 제어할 수 없다는 의미입니다.
그리고, QuickSetting에서 Dimming 된 손전등의 On 아이콘을 누르면, "카메라 앱에서 카메라 플래시를 사용 중이어서 손전등을 켤 수 없습니다."라는 토스트가 나옵니다. 이는 QuickSetting의 손전등에서 PermissionFlashlight 앱이 Camera API로 만들어져서 카메라 앱으로 간주하고 있습니다.

[case 2]
NoPermissionFlashlight 앱에서 Flash를 켜고, QuickSetting의 손전등을 확인하면 아이콘이 On 되어 있습니다.
이는 QuickSetting의 손전등에서 다른 앱에서 Flashlight API를 사용해서 On 시킨 것을 인지한 상태입니다.
그리고, QuickSetting에서 손전등의 On 아이콘을 누르면 Off 상태로 아이콘이 변경되면서 플래시가 꺼집니다.
이는 QuickSetting의 손전등으로 Flashlight 소유가 넘어가서 제어되고 있다는 것을 의미합니다.

그런데, NoPermissionFlashlight 앱으로 돌아오면 가운데 별 모양은 계속 On 상태로 남아있죠?
이건 왜 그럴까요? 정답은 NoPermisionFlashlight 앱에서는 다른 앱에서 Flashlight API를 사용해서 On 시킨 것을 인지하는 리스너가 구현되어 있지 않기 때문입니다. QuickSetting의 손전등처럼 리스너를 구현해주면 플래시가 꺼지면 콜백되어서 Off 상태 인지가 가능해서 아이콘 모양 변경이 가능합니다. 


이상으로 "손전등 앱 만들기 세 번째 - Flashlight API 이용방법"에 대해서 설명해 드렸습니다.
상황에 따라서 세 가지 방법을 적절히 이용하시면 손전등 앱을 구현하실 수 있을 겁니다.

조금이나마 도움이 되셨으면 아래 공감 버튼을 눌러주세요.
(If this article helps you, please press the button below.)

반응형

안녕하세요. Simple& Happy Dev입니다.

구글 플레이에는 수많은 손전등 / 플래시라이트(이하 손전등) 앱이 존재합니다.

일반적으로 스위치 버튼 하나 정도만 있으면 되는 비교적 간단한 UI에 카메라를 다뤄본 경험이 있다면 쉽게 만들 수 있기 때문일 겁니다. 여기서 카메라를 언급한 이유는 손전등의 불빛은 카메라 플래시(Camera Flash LED)를 사용하기에 그렇습니다.

손전등 앱을 만드는 방법은 몇 가지가 있습니다.
앞서 설명했듯이 카메라 플래시를 사용한다는 공통점이 있으나, 카메라 플래시 제어를 위해서 어떻게 접근하는지에 따라서 구분됩니다.

[손전등 앱의 카메라 플래시 제어하는 3가지 방법]

아래 그림에 보듯이 크게 카메라 권한을 가지고 (= 카메라 권한 필요) 플래시를 제어하는 방식과 카메라 권한 없이(카메라 권한 불필요) 플래시를 제어하는 방식으로 만들 수 있습니다.

카메라 플래시 제어 접근 방식

방법1 (Camera API 이용하는 방법)
 - 장점: 안드로이드 구버전도 지원 가능, 구현 용이
 - 단점: 카메라 권한 필요, deprecated API, 느린 속도(but, 약간 개선 가능 - 이글의 마지막에 다룰 예정)

방법2 (Camera2 API 이용하는 방법)
- 장점: 최신 Camera API
- 단점: 카메라 권한 필요, 구현 복잡, 안드로이드 5.0 (API Level 21) 이상부터 가능

방법3 (Flashlight API 이용하는 방법)
- 장점: 카메라 권한 불필요, 구현 매우 용이, 빠른 속도
- 단점: 안드로이드 6.0 (API Level 23) 이상부터 가능

Camera2 API 이용하는 방법은 거의 단점만 존재해서 일반적으로 사용하지 않는 방법입니다.
하지만, 궁금하시거나 해당 방법이 필요하신 분들이 있을 수도 있어서 다음 글에 다루도록 하겠습니다.

일단 이 글에서는 Camera API 이용해서 손전등 앱을 만드는 방법에 관해서 설명하도록 하겠습니다. 

[Camera API 이용한 손전등 앱]

애초에 플래시는 카메라를 보조해주기 위해서 들어간 디바이스입니다.
그래서, 하드웨어적인 연결이나 소프트웨어적인 접근이 카메라에 가깝게 되어 있습니다.

그 결과 플래시를 제어하기 위해서는 카메라에 접근한 이후 카메라 파라미터로 플래시를 넘겨줘야 했습니다.

플래시가 동작하는 순서는 다음과 같습니다.

플래시 켜기: 카메라 객체의 인스턴스 생성 및 연결(open)
                    - 카메라 파라미터에 플래시 모드를 Torch로 설정(setFlashMode)
                    - 카메라 프리뷰 시작(startPreview)

플래시 끄기 방법1: 카메라 프리뷰 종료 (stopPreview) - 카메라 연결 해제 및 릴리즈(release)

플래시 끄기 방법2: 카메라 파라미터에 플래시 모드를 Off로 설정(setFlashMode)
                             (중요 - 추후 카메라 프리뷰 종료 및 카메라 인스턴스를 릴리즈하는 코드가 존재해야 합니다.)

동작하는 순서에 대한 설명은 여기까지 하고 이제 소스로 들어가 보겠습니다.
아래 소스는 플래시를 끌 때 위에 있는 "플래시 끄기 방법1"로 하게 되어 있습니다.
"플래시 끄기 방법2"는 글의 마지막 부분에 설명되어 있습니다.

[소스 설명]

레이아웃 (activity_main.xml)
 

화면 한가운데 별 모양 버튼을 하나 추가해서 이걸 누르면 플래시가 켜지도록 할 예정입니다. 그리고, 한 번 더 누르면 버튼이 토글되어서 꺼지도록 하겠습니다. 별 모양 버튼은 SDK에 내장된 리소스를 사용하시면 됩니다.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<ImageButton
android:id="@+id/ibFlashOnOff"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@android:drawable/btn_star_big_off"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

자바 (MainActivity.java)

onCreate에서는 기기에 플래시가 지원하지 않으면 메시지 출력하고 3초 후 종료하도록 처리(delayedFinish())하도록 만들어 줍니다.
또한 별 모양 버튼에 대한 클릭 리스너를 만들어서 클릭 시 플래시를 켜주거나 꺼주고(flashlight()), 플래시 켜짐 상태에 따른 별 모양 이미지(켜짐: 노란색 별, 꺼짐: 흰색 별)를 변경하도록 처리해줍니다.

package com.example.help.permissionflashlight;

import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageButton;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
private static Camera mCamera = null;
private ImageButton mImageButtonFlashOnOff;
private boolean mFlashOn;

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

if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)) {
Toast.makeText(getApplicationContext(), "There is no camera flash.\n The app will finish!", Toast.LENGTH_LONG).show();
delayedFinish();
return;
}

mImageButtonFlashOnOff = findViewById(R.id.ibFlashOnOff);
mImageButtonFlashOnOff.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
flashlight();
mImageButtonFlashOnOff.setImageResource(mFlashOn ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off);
}
});
}

private void delayedFinish() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
finish();
}
}, 3000);
}

초기에는 플래시가 꺼진 상태이고, 카메라 인스턴스인 mCamera가 null이므로 onCreate에 있던 flashlight()는 openCamera()에서 카메라 객체의 인스턴스를 생성 및 연결하고 문제가 없으면 true로 리턴하고, 이후 mFlashOn를 토글시켜주어서 켜진 상태(mFlashOn => true)로 세팅됩니다.

그리고, 플래시를 Torch 모드로 파라미터 세팅을 해주고, 프리뷰를 시작해주면 플래시가 켜지게 됩니다.

반대로 플래시가 켜진 상태에서 openCamera()에 진입하면 이전에 mCamera가 생성된 상태라서 별다른 처리 없이 true로 리턴되고 mFlashOn이 토글되면서 꺼진 상태(mFlashOn => false)로 세팅됩니다.

꺼진 상태일 경우 프리뷰를 종료하도록 하고, 카메라 인스턴스를 릴리즈해줍니다. 이후 mCamera는 꼭 null로 만들어주어야 이후 오동작을 하지 않게 됩니다.

private boolean openCamera() {
if (mCamera == null) {
try {
mCamera = Camera.open();
} catch (RuntimeException e) {
Toast.makeText(getApplicationContext(), "Camera open failed", Toast.LENGTH_LONG).show();
e.printStackTrace();
return false;
}
}
return true;
}

private void flashlight() {
if (openCamera()) {
mFlashOn = !mFlashOn;

if (mFlashOn) {
Camera.Parameters params = mCamera.getParameters();
params.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);

mCamera.setParameters(params);
mCamera.startPreview();

} else {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
} else {
delayedFinish();
}
}
}

여기까지 작업 후 실행을 하게 되면 아래와 같은 에러를 만나게 되고 openCamera()의 try ~ catch 에 의해 강제 종료(Force Close)가 되지 않고, 메시지 출력 후 openCamera() 리턴을 false로 해서 3초 후 종료할 수 있게 되어 있습니다. 

W 3858     3858     ServiceManager:    Permission failure: android.permission.CAMERA from uid=10210 pid=3165
E  3858     3858     CameraService:      Permission Denial: cant use the camera pid=3165, uid=10210
W 3165     3165     CameraBase:         An error occurred while connecting to camera 0: Service not available
W 3165     3165     System.err:             java.lang.RuntimeException: Fail to connect to camera service
W 3165     3165     System.err:             at android.hardware.Camera.<init>(Camera.java:519)
W 3165     3165     System.err:             at android.hardware.Camera.open(Camera.java:379)
W 3165     3165     System.err:             at com.example.help.permissionflashlight.MainActivity.openCamera(MainActivity.java:50)
W 3165     3165     System.err:             at com.example.help.permissionflashlight.MainActivity.flashlight(MainActivity.java:61)
W 3165     3165     System.err:             at com.example.help.permissionflashlight.MainActivity$1.onClick(MainActivity.java:32)

위와 같은 현상이 일어난 것은 에러 메시지의 내용과 같이 카메라 권한이 없는 상태에서 접근했기 때문에 발생한 것입니다.


메니페스트(AndroidManifest.xml)

카메라 권한을 추가하기 위해서는 아래와 같이 <uses-permission android:name="android.permission.CAMERA" />를 메니페스트 파일에 넣어주면 됩니다.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.help.permissionflashlight">

<uses-permission android:name="android.permission.CAMERA" />

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
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>

프로젝트 압축화일
PermissionFlashlight.zip


실행 결과


cf) 플래시 끄기 방법2

플래시 끄기 1번의 방법은 stopPreview 및 release도 해주기 때문에 플래시가 꺼질 때 시간이 좀 걸립니다.
개선된 방법인 플래시 끄기 방법2에서는 카메라 플래시 모드를 FLASH_MODE_OFF로 파라미터 설정해주기만 하면 되기에 속도가 빠릅니다.

그 외에 몇 군데 다르게 처리해야 하는 부분들도 있습니다.

앞서 간단히 언급한 부분이기도 한데, 플래시 끄는 곳에서는 카메라 파라미터에 플래시 모드를 off 해주는 것 외에는 다른 처리를 하지 않고 있어서 카메라 프리뷰 종료 및 카메라 인스턴스를 릴리즈하는 코드는 onPause 쪽에 넣어주어야 합니다.

그리고, 그 코드가 onPause로 이동했기에 객체의 인스턴스 생성하는 코드는 onResume에 넣어주는 게 적당합니다.

자세한 코드는 소스를 첨부하니 참고하시길 바랍니다.
PermissionFlashlight2.zip


이상으로 "손전등 앱 만들기 첫 번째 - 개요 및 Camera API 이용방법"에 대해서 설명해 드렸습니다.
다음번에는 Camera2 API 이용해서 손전등 앱을 만들어 보도록 하겠습니다.

조금이나마 도움이 되셨으면 아래 공감 버튼을 눌러주세요.
(If this article helps you, please press the button below.)

반응형

 

결론부터 말하면 OEM / 3rd Party 모두 CameraService 로그를 확인하면 됩니다.

 

 

Android 5.0 (Lollipop) 이후부터 Camera API v2 (이하 Camera2)를 지원합니다.

 

당연히 Lollipop 이나 그 이후 OS 버전이 적용된 폰의 경우 Camera2 를 이용해서 카메라앱을 개발할 수 있습니다.

 

그럼, OEM Camera (Preload Camera)앱의 경우 Camera2 를 사용해서 개발했을까요?

 

테스트해 보면 갤럭시S7의 Preload Camera(com.sec.android.app.camera)앱의 경우 Camera2 를 사용하지 않았습니다.

 

 

 

동일폰에 설치한 Google Camera2 Sample (https://github.com/googlesamples/android-Camera2Basic/)앱의 결과는 어떨까요?

 

예상대로 Google Camera2 Sample (com.example.android.camera2basic)앱의 경우 Camera2 사용이 확인됩니다.

 

 

 

감사합니다.

+ Recent posts