아이폰 게임 개발

SMART_Phone/IPhone 2011. 6. 15. 19:56 Posted by Request

1.애플개발자 등록
http://developer.apple.com/iPhone/program

2.애플에서 이메일로 SDK를 다운로드 링크 발송 (확인)
또는 애플 웹사이트 SDK 다운로드 가능
-XCODE 포함 되어 있으므로 따로 다운로드 할 필요 없음.

3.Xcode
Xcode 프로젝트는 아이폰 애플리케이션을 만드는 데에 필요한 코드, 리소스, ㅣㄴ증서, 환경설정 모두를 포함하고 있다.


'Hello World' 애플리케이션을 만들어 보자.

1.Xcode 연다.
2.File -> New Project
3.다이얼로그(iPhone OS) 선택 , View - Based Application 선택 , Choose 클릭.


[만들어진 파일 설명]

HelloworldAppDelegate.m, HelloWorldAppDelegate.h
 이 파일들에 담긴 클래스는 애플리케이션의 시작점이 되는 메인  코드이다.
app delegate
메인 창과 메인 뷰 컨트롤러를 제어 하고 ,  화면을 구성하는 역할을 한다.


HelloworldViewController.m, HelloworldViewController.h
메인 View를 지니고 있으며, 'Hello World' 입력 하는 곳이다.


Mainwindow.xib
이 인터페이스 빌더 파일은 프로젝트를 컴파일하면 애플리케이션하는 nib 파일이다.
Load할때, app delegate를 만들고, 메인 창과 뷰 컨트롤러를 불러 온다.


HelloworldViewController.xib
이 파일은 HelloWorldViewController 의 뷰에 쓰는 디자인을 정한다.




안드로이드는 UI 그릴 때

layout -> Measurement -> Arrangement -> draw

순으로 그립니다.

requestLayout() 은 함수명대로 layout을 하도록 요청하는 거고.
invalidate() 는 화면이 유효하지 않게 되었으니가 다시 그리라는 것입니다.

[출처 : requestLayout() 와 invalidate()  차이점 답변 댓글]

Device 연결해서 구동시 아래 에러 발생 해결법.

[2011-04-07 14:50:14 - EcoAgentUITest1] Failed to install xxxxxxxx.apk on device 'M110axxxxx': timeout

[2011-04-07 14:50:14 - EcoAgentUITest1] Launch canceled!

Application 이 무거워 질경우 읽어 오는데 시간이 걸려서 실행 및 업데이트 시 Time out 에러가 발생한다.
기본 값이 5초여서 5초 이상 응답이 없을 경우 에러가 발생하므로 시간을 늘려 주면 된다.


Eclipse -> Preferences(환경설정) -> Android -> DDMS -> ADB connection time out (ms) : default (5000)

[출처 : http://dark2pee.tistory.com/25]
GridView 내 어댑터 선택 영역 비활성화 방법 :

<GridView
....
gridview.setselector(Resource) 이랑 android:listSelector="#00000000"
android:drawSelectorOnTop="true"
/>

EditText 커서에 대하여...

SMART_Phone/Android 2011. 6. 7. 16:08 Posted by Request


커서 보이기
소스 : setCursorVisible(true);
xml : android:cursorVisible="true"

에디트 텍스트 내용 모두 선택된 상태
소스 : setSelectAllOnFocus(true);
xml : android.selectAllOnFocus="true"

유니코드 한글 영역

SMART_Phone/Android 2011. 5. 31. 14:08 Posted by Request

유니코드 사이트(http://www.unicode.org/)

private static final char[] INITIAL_SOUND = { 'ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ', 'ㄹ',  
//    'ㅁ', 'ㅂ', 'ㅃ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅉ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ' };
 private static final char[] INITIAL_SOUND = {0x3131, 0x3132, 0x3134, 0x3137, 0x3138, 0x3139, 0x3141, 0x3142, 0x3143, 0x3145, 0x3146,
  0x3147, 0x3148, 0x3149, 0x314a, 0x314b, 0x314c, 0x314d, 0x314e };

안드로이드 권한(Permission) 종류 -


<uses-permission android:name="android.permission.INTERNET"/> 와 같은 방식으로 사용


ACCESS_CHECKIN_PROPERTIES 체크인데이터베이스의_속성테이블로_액세스

ACCESS_COARSE_LOCATION 코스_로케이션_액세스_(Cell-ID/WiFi)

ACCESS_FINE_LOCATION 파인로케이션_액세스(GPS)

ACCESS_LOCATION_EXTRA_COMMANDS 로케이션_옵션_커맨드_액세스

ACCESS_MOCK_LOCATION 목_로케이션_프로바이더_생성_(테스트용)

ACCESS_NETWORK_STATE 네트워크_상태_접근

ACCESS_SURFACE_FLINGER 서피스_플링거_접근

ACCESS_WIFI_STATE WiFi상태_접근

ADD_SYSTEM_SERVICE 시스템서비스_추가

BATTERY_STATS 배터리_상태

BLUETOOTH 블루투스

BLUETOOTH_ADMIN 블루투스_어드민

BRICK 디바이스_실효성_지정

BROADCAST_PACKAGE_REMOVED 제거된_패키지에_대한_notification_브로드캐스트

BROADCAST_SMS SMS에_대한_브로드캐스트

BROADCAST_STICKY 인텐트_브로드캐스트

CALL_PHONE 통화

CALL_PRIVILEGED 통화(긴급전화_포함)

CAMERA 카메라

CHANGE_COMPONENT_ENABLED_STATE 컴포넌트의_실효성_변경

CHANGE_CONFIGURATION 컨피그_변경

CHANGE_NETWORK_STATE 통신상태_변경

CHANGE_WIFI_STATE WiFi상태_변경

CLEAR_APP_CACHE 어플리케이션_캐시_클리어

CLEAR_APP_USER_DATA 어플리케이션의_유저데이터_클리어

CONTROL_LOCATION_UPDATES 위치정보_갱신

DELETE_CACHE_FILES 캐시파일_제거

DELETE_PACKAGES 패키지_제거

DEVICE_POWER 전원상태에_대한_로우레벨_접근

DIAGNOSTIC 진단리소스_읽고쓰기

DISABLE_KEYGUARD 키_가드_끄기_DUMP_덤?

EXPAND_STATUS_BAR 상태표시줄_확장

FACTORY_TEST 팩토리_테스트

FLASHLIGHT 플래시라이트

FORCE_BACK 포스백

GET_ACCOUNTS 어카운트_획득

GET_PACKAGE_SIZE 패키지_획득

GET_TASKS 태스크_획득

HARDWARE_TEST 하드웨어테스트

INJECT_EVENTS 유저이벤트_키/트랙볼

INSTALL_PACKAGES 패키지_인스톨

INTERNAL_SYSTEM_WINDOW 내부_시스템윈도_활용

INTERNET 인터넷

MANAGE_APP_TOKENS 어플리케이션_토큰관리

MASTER_CLEAR 마스터_클리어

MODIFY_AUDIO_SETTINGS 오디오설정_편집

MODIFY_PHONE_STATE 전화상태_편집

MOUNT_UNMOUNT_FILESYSTEMS 파일시스템_편집

PERSISTENT_ACTIVITY 액티비티_지속

PROCESS_OUTGOING_CALLS 전화_발신처리_접근

READ_CALENDAR 캘린더_읽어오기

READ_CONTACTS 주소록_읽어오기

READ_FRAME_BUFFER 프레임버퍼_읽어오기

READ_INPUT_STATE 입력상태_읽어오기

READ_LOGS 로그_읽어오기

READ_OWNER_DATA owner_data읽어오기

READ_PHONE_STATE 통화상태_읽어오기_READ_SMS_SMS읽어오기

READ_SYNC_SETTINGS 동기설정_읽어오기

READ_SYNC_STATS 동기상태_읽어오기

REBOOT reboot

RECEIVE_BOOT_COMPLETED boot완료

RECEIVE_MMS MMS수신

RECEIVE_SMS SMS수신

RECEIVE_WAP_PUSH WAP수신

RECORD_AUDIO 오디오_수신

REORDER_TASKS 태스크_Z오더

RESTART_PACKAGES 패키지_리스타트

SEND_SMS SMS송신

SET_ACTIVITY_WATCHER 액티비티_왓쳐지정

SET_ALWAYS_FINISH 액티비티_전체_종료

SET_ANIMATION_SCALE 스케일_애니메이션_지정

SET_DEBUG_APP 디버그어플리케이션_지정

SET_ORIENTATION 스크린_로테이션지정

SET_PREFERRED_APPLICATIONS 자주_사용하는_어플리케이션_지정

SET_PROCESS_FOREGROUND 포어그라운드_처리지정

SET_PROCESS_LIMIT 제한처리_지정

SET_TIME_ZONE 타임존_지정

SET_WALLPAPER 배경화면_지정

SET_WALLPAPER_HINTS 배경화면_힌트_지정

SIGNAL_PERSISTENT_PROCESSES 지속처리_시그널_지정

STATUS_BAR 상태표시줄_지정

SUBSCRIBED_FEEDS_READ 서브스트립드_피즈_읽어오기

SUBSCRIBED_FEEDS_WRITE 서브스트립드_피즈_쓰기

SYSTEM_ALERT_WINDOW 알림_윈도우

VIBRATE 진동

WAKE_LOCK 알람

WRITE_APN_SETTINGS APN설정_쓰기

WRITE_CALENDAR 캘린더_쓰기

WRITE_CONTACTS 주소록_쓰기

WRITE_GSERVICES G서비스_쓰기

WRITE_OWNER_DATA owner_data쓰기

WRITE_SETTINGS 설정_쓰기

WRITE_SMS SMS쓰기

WRITE_SYNC_SETTINGS 동기설정_쓰기

카메라 어플 만들기

SMART_Phone/Android 2011. 5. 31. 10:45 Posted by Request

4.카메라

1.Camera

렌즈로부터 영상을 얻는 카메라는 이제 스마트폰에 빠질 수 없는 필수 기능이며 실제로도 카메라가 없는 폰을 보기 힘들다. 사진을 찍는 본질적인 용도는 물론이고 이제는 영상 통화까지도 기본 기능으로 정착되었으며 바코드 스캔이나 문자 인식 등의 최신 기술에도 카메라가 두루 사용된다. 특히 최근에 화두로 떠오르는 증강 현실은 카메라로부터 입수한 영상에 가상의 정보를 가미해 상황에 맞는 최적의 정보를 제공한다.

카메라의 물리적인 성능은 장비마다 천차 만별로 다르다. 각 제조사들은 하드웨어의 모든 기능을 아낌없이 발휘하고 타사 제품과의 차별화를 위해 고유의 기능을 확장해서 적용한다. 카메라의 성능이 곧 폰의 성능으로 인식되며 선택의 중요한 기준으로 작용한다. 그래서 카메라 앱은 하드웨어에 강하게 의존적이며 제조사가 제공한 기본 카메라가 해당 장비에서는 가장 좋은 성능을 낼 수밖에 없다.

모든 장비에 두루 사용할 수 있는 앱을 제작하려면 공통적인 기본 기능만 사용하거나 특정 기능의 존재 유무를 확인한 후 하드웨어의 능력치를 최대한 활용해야 한다. 안드로이드의 카메라 서비스는 복잡도에 비해 굉장히 깔끔하게 잘 정비되어 있으며 신뢰성도 높아서 기본 API만 잘 숙지해도 원하는 품질의 영상을 쉽게 얻을 수 있다. 카메라 기능을 사용하려면 매니페스트에 다음 선언문을 작성한다.

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

<uses-feature android:name="android.hardware.camera" />

<uses-feature android:name="android.hardware.camera.autofocus" />

물리적인 하드웨어를 사용하는 것이므로 카메라를 사용하겠다는 퍼미션이 필요하며 사용자에게 허가를 받아야 한다. 퍼미션 외에도 uses-feature 엘리먼트로 카메라 하드웨어와 오토 포커스 기능을 사용한다는 것을 알려 해당 기능이 없는 장비에 앱이 설치되는 것을 방지할 필요가 있다. 카메라 기능은 운영체제의 서비스 형태로 제공되며 서비스와 앱 사이를 연결해 주는 것이 바로 Camera 클래스이다. 별도의 생성자는 없으므로 다음 메서드로 생성 및 파괴한다.

static Camera open ()

void release ()

정적 메서드로 카메라 객체를 생성하고 다 사용한 후 release 메서드로 해제한다. 카메라는 입수된 영상의 미리 보기를 표시하기 위해 표면 객체를 요구하므로 객체 생성 후 미리 보기 표면을 제공해야 한다. 미리보기 표면은 렌즈로부터 영상을 공급받으므로 별도의 버퍼를 가질 필요는 없으며 그래서 타입을 SURFACE_TYPE_PUSH_BUFFERS 로 설정한다. 다음 메서드로 미리 보기 표면과 방향을 지정한다.

void setPreviewDisplay (SurfaceHolder holder)

void setDisplayOrientation (int degrees)

미리보기는 기본적으로 가로 방향으로 표시되는데 대부분의 사진이 가로 방향으로 촬영되며 동영상도 세로로 된 것은 없기 때문이다. 그래서 카메라는 장비의 방향에 상관없이 항상 가로 전용으로 실행된다. 촬영시에 장비를 많이 움직이는데 이때 화면이 전환되면 오히려 불편하므로 일반적으로 카메라는 방향 전환을 하지 않는다. 하지만 카메라를 특수한 용도로 사용하는 앱에서는 세로로 촬영해야 하는 경우도 있어 2.2 버전부터는 미리보기의 방향을 변경하는 메서드가 추가되었다. 0, 90, 180, 270 식으로 미리보기의 각도를 지정한다.

표면을 지정한 후 카메라의 동작 방식이나 여러 가지 옵션을 지정하는 파라미터를 전달한다. 파라미터는 Camera의 내부 클래스인 Parameters 클래스로 표현되며 다음 메서드로 조사 및 변경한다. get 메서드로 현재 파라미터를 얻고 원하는 값을 수정한 후 set 메서드로 편집한 파라미터를 다시 전달하면 이후부터 카메라는 수정된 파라미터대로 동작한다. 실행중에라도 파라미터는 언제든지 수정할 수 있다.

Camera.Parameters getParameters ()

void setParameters (Camera.Parameters params)

파라미터로 조정할 수 있는 값은 해상도, 이미지 품질, 미리보기의 크기, 장면, 효과, 줌, 포커스, 플래시, 화이트 밸런스, 회전 모드 등등 아주 다양하다. 일반적인 디지털 카메라가 지원하는 옵션들이 대부분 지원된다. 그러나 모든 옵션이 항상 다 지원되는 것은 아니며 카메라의 물리적인 능력치를 초과할 수는 없다. 또 제조사별로 노출 시간, ISO, 손떨림 보정, GPS 좌표 기록 등의 고급 옵션들을 지원하기도 하며 얼굴 인식, 웃는 표정 인식 등 표준에 없는 커스텀 기능을 지원하는 모델도 있다.

따라서 파라미터를 조정할 때는 항상 장비의 능력치를 먼저 조사해 보고 사용할 수 있는 파라미터인지를 점검한 후 적용해야 한다. 플래시가 없는 카메라에 적목 감소 기능을 적용한다거나 300만 화소 카메라에 1000만 화소를 지정하는 것은 아무 의미가 없다. Parameters 클래스는 능력치를 조사하는 메서드와 옵션을 변경하는 메서드가 같이 제공된다. 다음은 미리 보기 영역의 크기 목록을 조사하고 설정하는 메서드이다.

List<Camera.Size> Camera.Parameters.getSupportedPreviewSizes ()

void Camera.Parameters.setPreviewSize (int width, int height)

카메라가 지원하는 미리 보기 크기의 목록을 먼저 구하고 표현하고자 하는 미리 보기와 비교하여 종횡비가 가장 근접하고 가급적이면 비슷한 크기로 미리 보기를 표시해야 한다. 다음은 사진의 해상도를 조사 및 지정하는데 방식은 동일하다.

List<Camera.Size> getSupportedPictureSizes ()

void setPictureSize (int width, int height)

해상도 목록으로 1600*1200, 2560*1920 등의 사용 가능한 크기가 조사된다. 이 목록을 사용자에게 보여주고 사용자가 선택한 해상도를 선택하면 이후 사진이 이 크기대로 촬영된다. 파라미터로 옵션을 설정했으면 다음 메서드로 미리 보기를 표시한다.

void startPreview ()

void stopPreview ()

startPreview를 호출하면 지정한 표면에 카메라 렌즈로부터 입수된 영상이 반복적으로 출력된다. 미리 보기의 프레임 비율이나 포맷도 파라미터로 지정할 수 있다. 미리 보기까지 나왔으면 언제든지 사진을 촬영할 수 있지만 좀 더 질좋은 이미지를 얻기 위해 오토 포커싱 과정을 거쳐야 한다.

void autoFocus (Camera.AutoFocusCallback cb)

void AutoFocusCallback.onAutoFocus (boolean success, Camera camera)

void cancelAutoFocus ()

autoFocus 메서드는 카메라와 영상간의 거리를 자동 판별하여 초점을 조절한다. 렌즈의 모터를 동작시켜 움직여야 하므로 다소 시간이 걸리며 그래서 이 메서드는 비동기적으로 동작한다. 오토 포커싱 콜백을 등록해 놓으면 포커싱 완료 후에 콜백이 호출되며 이때 인수로 포커싱 성공 여부가 전달된다. 대개의 경우 성공하겠지만 너무 근접한 거리에서는 실패할 수도 있다. 포커싱 중에 사용자의 다른 요청이 들어왔다면 중간에 취소할 수도 있다.

만약 장비가 오토 포커싱을 지원하지 않으면 콜백이 즉시 호출되며 이때 포커싱은 성공한 것으로 가정한다. 따라서 오토 포커싱은 기능의 제공 여부를 조사할 필요없이 무조건 호출해도 상관없다. 대상에 대해 초점을 정확하게 잡았으면 이제 사진을 찍을 차례이다. 이때는 다음 메서드를 호출한다.

void takePicture (Camera.ShutterCallback shutter, Camera.PictureCallback raw, [Camera.PictureCallback postview, ] Camera.PictureCallback jpeg)

사진 한장을 촬영하는데는 굉장히 많은 절차를 거쳐야 하는데다 대용량의 데이터를 조작해야 한다. 입수된 영상을 해상도에 맞게 축소하고 효과를 입히고 Jpeg 포맷으로 변환 및 압축까지 해야 하므로 상당한 시간이 걸린다. 그래서 takePicture 메서드는 카메라 서비스에게 사진 촬영 명령만 내린 후 즉시 리턴하되 각 단계마다 호출될 콜백 메서드를 전달해 놓는다. 필요치 않은 콜백은 null로 지정하여 생략할 수 있다.

셔터 콜백은 셔터를 닫을 때 호출되는데 보통 이 시점에서 찰칵 하는 셔터음을 낸다. 이 콜백에서 아무 것도 하지 않으면 소리가 안나야 정상이지만 무음 촬영이 법적으로 금지되어 있는 경우에는 강제로 소리가 나기도 한다. 우리 나라의 경우도 그런데 심지어 진동 모드인 상태에서도 촬영음이 들린다. PictureCallback 인터페이스에는 다음 콜백 메서드가 정의되어 있는데 각 단계의 이미지를 얻을 때마다 이 메서드가 호출된다.

void onPictureTaken (byte[] data, Camera camera)

data 인수는 이미지의 래스터 정보이다. 로(raw) 콜백으로는 압축하기 전의 원본 이미지 데이터가 전달되는데 용량이 대단히 크다. 바코드 리더기나 OCR처럼 손실없는 영상이 필요할 때 이 콜백을 처리하되 메모리가 충분하지 않을 경우는 원본 영상이 전달되지 않는다. 포스트 뷰 콜백은 촬영 후 액정으로 보여줄 이미지가 크기 조정이 완료된 상태로 전달된다.

카메라의 경우 가장 중요한 콜백은 이미지 데이터를 압축해서 전달하는 Jpeg 콜백이다. 미리 정한 포맷으로 압축된 이미지가 전달되는데 통상 JPEG 포맷이며 이 데이터를 파일로 저장하면 촬영된 사진 파일이 되는 것이다. 이미지를 저장할 때 GPS 좌표나 화면 방향 등의 상세 정보를 Exif 헤더에 저장할 수도 있다. 또 새 이미지가 추가되었으므로 미디어 DB에게 신호를 보내는 처리도 필요하다.

takePicture 메서드는 촬영전에 미리보기를 자동으로 중지하므로 stopPreview를 호출할 필요는 없다. 렌즈로부터 촬영 영상을 읽어들이는 동안에는 미리보기가 강제로 중지된다. 그러나 촬영이 끝난 후 미리보기를 자동으로 재시작하지는 않으므로 startPreview는 직접 호출해야 한다. 이 처리는 보통 Jpeg 콜백에서 파일 저장까지 완료한 후에 수행한다. 미리보기가 다시 나오면 다음 촬영을 계속할 수 있다.

2.간단한 카메라

앞 항에서 Camera 클래스를 프로그래밍하는 대략적인 절차에 대해 소개했는데 좀 길기는 하지만 지극히 상식적이고 작업 과정이 직선적이어서 이해하기는 쉽다. 카메라 열고 미리 보기 지정한 후 옵션 설정하고 찍으면 되는 것이다. 그러나 미리 보기 표면을 따로 준비해야 하는데다 오토 포커싱과 촬영 과정이 모두 비동기적으로 수행되므로 언제 어떤 메서드를 순서에 맞게 호출해야 하는지를 파악하는 것이 다소 어렵고 필요한 콜백을 선정하기도 쉽지 않다.

렌즈로부터 외부의 영상을 받아 파일 형태로 저장하기까지의 과정이 다소 복잡한 편이다. 이런 실습을 할 때는 고급 기능은 죄다 무시하고 가장 기본적인 촬영까지만 해 보는 간단한 예제가 도움이 된다. 다음 예제로 일단 카메라 프로그래밍의 기본을 익혀 보자. 짧지만 포커싱, 촬영, 저장 정도의 기능을 제공한다. 이 정도 길이의 소스로 카메라가 구현된다는 것이 놀랍다.

mm_Camera

public class mm_Camera extends Activity {

MyCameraSurface mSurface;

Button mShutter;

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.mm_camera);

mSurface = (MyCameraSurface)findViewById(R.id.preview);

// 오토 포커스 시작

findViewById(R.id.focus).setOnClickListener(new Button.OnClickListener() {

public void onClick(View v) {

mShutter.setEnabled(false);

mSurface.mCamera.autoFocus(mAutoFocus);

}

});

// 사진 촬영

mShutter = (Button)findViewById(R.id.shutter);

mShutter.setOnClickListener(new Button.OnClickListener() {

public void onClick(View v) {

mSurface.mCamera.takePicture(null, null, mPicture);

}

});

}

// 포커싱 성공하면 촬영 허가

AutoFocusCallback mAutoFocus = new AutoFocusCallback() {

public void onAutoFocus(boolean success, Camera camera) {

mShutter.setEnabled(success);

}

};

// 사진 저장.

PictureCallback mPicture = new PictureCallback() {

public void onPictureTaken(byte[] data, Camera camera) {

String path = "/sdcard/cameratest.jpg";

File file = new File(path);

try {

FileOutputStream fos = new FileOutputStream(file);

fos.write(data);

fos.flush();

fos.close();

} catch (Exception e) {

Toast.makeText(mm_Camera.this, "파일 저장 중 에러 발생 : " +

e.getMessage(), 0).show();

return;

}

Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);

Uri uri = Uri.parse("file://" + path);

intent.setData(uri);

sendBroadcast(intent);

Toast.makeText(mm_Camera.this, "사진 저장 완료 : " + path, 0).show();

mSurface.mCamera.startPreview();

}

};

}

// 미리보기 표면 클래스

class MyCameraSurface extends SurfaceView implements SurfaceHolder.Callback {

SurfaceHolder mHolder;

Camera mCamera;

public MyCameraSurface(Context context, AttributeSet attrs) {

super(context, attrs);

mHolder = getHolder();

mHolder.addCallback(this);

mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

}

// 표면 생성시 카메라 오픈하고 미리보기 설정

public void surfaceCreated(SurfaceHolder holder) {

mCamera = Camera.open();

try {

mCamera.setPreviewDisplay(mHolder);

} catch (IOException e) {

mCamera.release();

mCamera = null;

}

}

// 표면 파괴시 카메라도 파괴한다.

public void surfaceDestroyed(SurfaceHolder holder) {

if (mCamera != null) {

mCamera.stopPreview();

mCamera.release();

mCamera = null;

}

}

// 표면의 크기가 결정될 때 최적의 미리보기 크기를 구해 설정한다.

public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

Camera.Parameters params = mCamera.getParameters();

List<Size> arSize = params.getSupportedPreviewSizes();

if (arSize == null) {

params.setPreviewSize(width, height);

} else {

int diff = 10000;

Size opti = null;

for (Size s : arSize) {

if (Math.abs(s.height - height) < diff) {

diff = Math.abs(s.height - height);

opti = s;

}

}

params.setPreviewSize(opti.width, opti.height);

}

mCamera.setParameters(params);

mCamera.startPreview();

}

}

레이아웃에는 포커싱과 촬영을 위한 버튼 두개와 미리 보기 표면이 배치되어 있다. 버튼 영역에 118dip 폭을 할당하고 미리 보기가 나머지 262dip 폭을 차지하는데 이는 일반적으로 많이 촬영되는 해상도의 4:3 비율을 에뮬레이터 환경에 맞춘 것이다. 와이드 해상도를 지원하는 장비는 사용자가 선택한 해상도의 종횡비와 장비의 실제 해상도에 맞게 미리 보기의 크기를 동적으로 조정해야 한다.

액티비티는 가로 전용으로 설정하여 방향 전환을 금지했다. 세로 촬영도 가능하기는 하지만 아직 2.2 이상의 장비가 일반화되지 않아 호환성 확보를 위해 방향을 고정하는 것이 좋다. 사실 카메라는 촬영중에 방향이 함부로 전환되면 오히려 불편하므로 가로든, 세로든 방향을 고정하는 것이 현실적으로 합당하다. 다음은 에뮬레이터에서 실행한 모습이다.

에뮬레이터는 렌즈가 없으므로 실제 미리 보기 영상이 나타나지 않는다. 대신 체크 무늬위를 움직이는 사각형을 반복적으로 보여줌으로써 미리보기를 흉내낸다. 에뮬레이터답게 미리보기 영상까지도 그럴듯하게 흉내를 내 주는 것이다. 이 애니메이션이 실장비에서는 렌즈로부터 입수된 영상으로 대체된다. 렌즈가 없으므로 오토 포커싱도 지원되지 않지만 항상 성공하는 것으로 가정하므로 사진 촬영은 가능하다.

에뮬레이터에서 촬영을 하면 더미 이미지 하나가 생성되는데 이 역시 가짜 이미지이다. 사진이 제대로 촬영되는지 확인해 보려면 렌즈를 가진 실장비가 필요하다. 다음은 실장비에서 이 예제를 실행한 모습이다. 미리 보기가 나타나 움직이며 Focus 버튼을 누르면 초점을 잡고 Shutter 버튼을 누르면 실제 촬영도 잘 된다. UI가 극단적으로 촌스럽기는 하지만 촬영은 훌륭하게 잘 수행된다.

소스를 분석해 보자. 미리 보기는 카메라의 필수 요소이므로 아래쪽에 미리 보기를 위한 표면인 MyCameraSurface 클래스를 정의했다. 생성자에서 콜백을 스스로 처리함을 명시했으며 버퍼 타입을 설정한다. 표면과 카메라는 생명 주기가 일치하며 표면이 먼저 준비되어야 카메라가 동작할 수 있다. 그래서 카메라의 초기화와 해제 코드는 표면의 콜백 메서드에 작성된다. 표면이 생성될 때 카메라를 생성하고 자신을 미리 보기 영역으로 제공한다.

표면이 변경될 때, 즉 표면의 크기가 처음 결정될 때 미리 보기의 크기를 결정하는데 이 코드는 다소 복잡하다. 장비가 지원하는 미리 보기 영역의 목록을 파라미터에서 구하고 그 중 표면의 실제 크기와 가장 근접한 크기를 선택한다. 만약 지원 목록을 구할 수 없으면 어쩔 수 없이 표면의 크기를 그대로 전달한다. 크기를 정한 후 startPreview를 호출하면 표면에 미리 보기가 출력된다. 표면이 파괴될 때는 미리 보기를 끝내고 카메라도 해제한다.

표면의 콜백만 제대로 처리해도 미리 보기까지는 잘 나오며 이 상태에서 바로 촬영할 수 있다. Focus 버튼을 누르면 셔터 버튼을 잠시 사용 금지시키고 autoFocus 메서드를 호출하여 초점을 잡는다. 포커스 콜백에서 포커싱이 성공하면 셔터 버튼을 허가한다. 포커싱과 촬영 두 과정을 명확하게 보이기 위해 의도적으로 버튼을 따로 두었는데 버튼 하나로 두 작업을 순차 처리할 수도 있다. 다만 중간에 버튼을 놓으면 취소하는 과정이 좀 복잡해진다.

촬영 버튼을 누르면 takePicture 메서드로 촬영을 한다. 카메라는 결국 사진을 얻는 것이 궁극의 목적이므로 다른 콜백은 무시하고 Jpeg 콜백만 처리했다. 파일에 래스터 데이터를 저장하고 새로 촬영된 이미지를 DB에 추가하기 위해 SCAN_FILE 방송을 보낸다. 좀 더 신속하게 삽입하려면 방송을 하는 대신 미디어 DB에 직접 레코드를 삽입하는 방법도 가능하다. 촬영 후 갤러리를 열어 보면 새로 찍은 사진이 보일 것이다.

이 예제는 비록 짧지만 카메라 제작의 기본 뼈대를 잘 보여준다. 디자인을 좀 더 쌈박하게 장식하고 해상도 변경이나 타이머 정도의 기능만 넣어도 실용성이 훨씬 더 개선될 것이다. mm_SHCamera 예제는 기본 기능에 약간의 추가 기능을 더해 실용적으로도 쓸만하게 만들어 본 것이되 이 정도 되면 예제로서의 가치는 떨어지므로 소스 분석은 생략하기로 한다. 원고 집필에 시달리다 보니 요즘은 다음 간식을 종종 먹어야 한다.

앞 예제와는 다소 달라졌는데 주로 오른손으로 촬영을 하므로 버튼들을 오른쪽으로 옮겼으며 몇 가지 기능을 더 넣었다. 촬영 버튼을 누르면 포커스 잡고 바로 촬영을 하는데 화면 터치 시점과 촬영 시점을 분리하여 떨림을 방지하자는 의도이다. 간단한 아이디어지만 터치폰에서는 화질 향상에 꽤 도움이 된다. 해상도 선택 기능과 접사 모드 정도를 추가했고 최후로 찍은 사진이 제대로 찍혔는지 확인하는 리뷰 기능도 제공한다.

이외에도 아주 많은 기능들을 더 넣을 수 있지만 그다지 실용성은 없어 보인다. 장면 모드니 반전, 세피아 같은 효과들은 찍은 후에 적용하는 것이 더 품질이 좋고 디지털 줌은 있으나 마나한 기능이다. 가장 빈번하게 사용하는 기능이 싱글 샷이므로 이 기능에만 집중해서 간단하게 만들어 본 것이며 개인적으로 유용하게 잘 쓰고 있다. 여러분들도 자신만의 카메라를 만들어 사용해 보기 바란다.

[출처 : http://www.winapi.co.kr/android/annex/18-4.htm ]

[android]ImageView 클래스 분석하기

SMART_Phone/Android 2011. 5. 30. 18:40 Posted by Request
ImageView 클래스는 상위 클래스 SurfaceView 클래스 상속받으며
SurfaceHolder.Callback 인터페이스 구현

 public class ImageView extends SurfacefView implements SurfaceHolder.Callback{....}

표면(surface)에 그리기 위해 Canvas클래스를 가지고 있으며, 레이어와 표면을 리사이즈하기 위한 다양한 메소드들을 제공한다.

프로그래머는 Surface 클래스에 직접 사용 할수 없고, SurfaceVIew 클래스를 이용하여 표면에 접근할수 있다.

Canvas클래스그림을 그리기 위한 도구.(표준 메소드, bitmap, line, circle, rectangles, text등)
SurfaceHolder는 일종의 중간자적인 역할을 하는 인터페이스로

SurfaceView가 Surface에 접근할때 SurfaceHolder를 경유
SurfaceHolder는 SurfaceHolder.Callback 인터페이스 포함하여 표면이 변경되는 등의 변화에 대한 이벤트받고 싶다면 SurfaceHolder.Callback로 사용하면 됨.

[발생 되는 이벤트]
surfaceCreated
:surface를 생성한 후 호출

surfaceChanged
:surface가 변경되었을 경우에 호출

surfaceDestroyed
:Surface가 제거 될 때 호출. 이 메소드에서 리소스 해제 작업을 수행


[2.SurfaceHolder.lockCanvas()와 SurfaceHolder.UnlockCanvasANdPost(Canvas c)의 이해]
lockCanvas()를 통해 얻은 Canvas를 이용하여 그림을 그리는 것은 백버퍼에서 그리는 것으로 화면에 표시 하지 않는다.
unlockCanvasAndPost()메소드가 실행되어야 비로소 작성한 이미지가 화면에 표현됨.


 SurfaceHolder 구하기

(1) ImageView 에서 다음과 같이 실행하여 SurfacefaceHolder를 구한다.
 Canvas mCanvas = null;
SurfaceHolder mHolder =getHolder();

(2)ImageView 클래스의 생성자에서 다음을 실행하여 콜백을 가능하도록 한다.
 mHolder.addCallback(this);

(3)표면이 생성될때 surfaceCreated()메소드 호출된다.
try{
 mCanvas = mHolder.lockCanvas(null);
draw(mCanvas);
}finally{
if(mCanvas != null){
 mHolder.unlockCanvasAndPost(mCanvas);
}


(4)draw()메소드에서 Canvas를 이용해서 이미지를 그린다.
 canvas.drawBitmap(mImgBack0, 0, 0, null);





[android] GestureDetector 클래스

SMART_Phone/Android 2011. 5. 30. 17:47 Posted by Request
지스트럿츠디택터? 아따 길다 ㅡㅡㅋ


[Intro]

어플리케이션 개발을 하다보면 반드시 해야하는 것이 모션 이벤트 처리 입니다.

터치 이벤트 같은 것들은 DOWN - MOVE - UP의 단계를 거치면서

사용자가 어떤 동작을 입력 하는지 감지 할 수 있습니다.

이 입력의 어떤 조합으로 사용자가 어떤 동작을 했는지 감지 할 수 있겠죠.

하지만 직접 이런 제스쳐들을 구현하기란 쉬운 일만은 아닙니다. (무엇보다 귀찮죠~)

그래서 Android에서는 GestureDetector라는 클래스를 아얘 제공합니다.

[About GestureListener]

GestureDetector는 두 가지 Listener를 가지고 있습니다.

interface GestureDetector.OnDoubleTapListener
interface GestureDetector.OnGestureListener

http://developer.android.com/reference/android/view/GestureDetector.html

자세한 설명은 Reference를 보시면 됩니다.

OnDoubleTapListener는 이름 그대로 두번 터치 했을 때,

OnGestureListener는 일반적인 제스쳐들, 한번 터치나 스크롤 관련 Listner입니다.

그리고 저 두 가지 interface를 모두 가진 녀석이 있습니다.

class GestureDetector.SimpleOnGestureListener

보통 SimpleOnGestureListener만 extends 하면 모든 제스쳐를 다 사용 할 수 있습니다.

[Usage of GestureDetector]

사용법도 매우 간단합니다.

GestureDetector를 만들기만 하면 땡이죠.

mGestureDetector = new GestureDetector(this, new SimpleGestureListener());
mGestureDetector.onTouchEvent(event);

음... 너무 뜬금 없는 코드인가요? 일단 아주 간단하게 적어 봤습니다.

1. GestureDetector를 만들 때 GestureListener를 등록 하고

2. 감시할 MotionEvent를 onTouchEvent에 넣어 주면 GetstureListener가 호출이 되는 구조 입니다.

좀 더 자세하게 살펴 보면,

private final class SimpleGestureListener
extends GestureDetector.SimpleOnGestureListener {
// Implementation
}

private GestureDetector mGestureDetector;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mGestureDetector = new GestureDetector(this, new SimpleGestureListener());
}

@Override
public boolean onTouchEvent(MotionEvent event) {
return mGestureDetector.onTouchEvent(event);
}

위와 같습니다.

[Analyze Gestures]

사용법은 간단하지만 제스쳐는 그리 간단하지 않습니다.

그래서 각 제스쳐에 대해서 분석을 해봤습니다.

public boolean onDoubleTap(MotionEvent e)
public boolean onDoubleTapEvent(MotionEvent e)
public boolean onDown(MotionEvent e)
public boolean onFling(MotionEvent e1, MotionEvent e2, float vX, float vY)
public void onLongPress(MotionEvent e)
public boolean onScroll(MotionEvent e1, MotionEvent e2, float dX, float dY)
public void onShowPress(MotionEvent e)
public boolean onSingleTapConfirmed(MotionEvent e)
public boolean onSingleTapUp(MotionEvent e)

일단 제스쳐 이벤트에 대해서 간단히 살펴 봅시다.

onDoubleTap은 두 번 터치입니다.

onDoubleTap은 두 번 터치하면 이벤트가 더 이상 발생 되지 않지만,

onDoubleTapEvent는 DOWN, MOVE, UP 이벤트를 모두 포함 합니다. (나중에 살펴 보겠습니다.)

onDown은 터치하려고 손을 대기만 해도 발생되는 이벤트며,

모든 제스쳐의 시작입니다.

onFling은 onScroll에서 끝을 살짝 튕기는 동작에서 발생하는 이벤트며,

onScroll은 말 그대로 스크롤 시에 발생하는 이벤트 입니다.

onLongPress는 길게 눌렀을 때 발생 하는 이벤트며,

onShowPress는 onLongPress보다는 좀 더 짧은 시간동안 누르고 있으면 발생 하는 이벤트 입니다.

onSingleTap은 한 번 터치 했을 때 발생하는 이벤트며,

onSingleTabConfirmed는 한 번 터치 하고 다음에 다시 터치 이벤트가 들어오지 않았을 때,

한 번 터치가 확실 하다고 확인 시켜주는 이벤트 입니다.

자... 이제 시작입니다! 이건 간단히 살펴 본것 밖에 안되는...

본격적으로 실제 제스쳐에 따라서 어떤 이벤트가 호출 되는지 살펴 보겠습니다.

시간은 로그를 통해 한번만 계산된 시간이며,

대략 그 시간 범위에서 이벤트가 발생 한다고 보시면 됩니다.

1. 아주 살짝 터치

000ms onDown : ACTION_DOWN
060ms onSingleTapUp : ACTION_UP
306ms onSingleTapConfirmed : ACTION_DOWN

일단 손을 대면 무조건 onDown 이벤트 발생입니다.

살짝 터치를 하게 되면 보통 30~60ms 정도 후에 손이 떨어지게 됩니다.

손이 떨어 지면 onSingleTapUp 이벤트가 발생하며,

onDown이벤트 발생 후 약 300ms 안에 다시 onDown 이벤트가 발생 하지 않는다면

onSingleTapConfirmed 이벤트가 발생하여 확실히 한 번 터치 되었다는 이벤트를 발생 시킵니다.

2. 살짝 터치

000ms onDown : ACTION_DOWN
097ms onShowPress : ACTION_DOWN
172ms onSingleTapUp : ACTION_UP
303ms onSingleTapConfirmed : ACTION_DOWN

역시나 onDown 이벤트 부터 시작입니다.

1번 보다는 살짝 길게, 약 90~100ms 정도 터치되면 onShowPress 이벤트가 발생합니다.

172ms 이후에 손을 떼었으며,

역시나 300ms 정도 지나면 onSingleTapConfirmed 이벤트가 발생 됩니다.

3. 약간 길게 터치

000ms onDown : ACTION_DOWN
103ms onShowPress : ACTION_DOWN
460ms onSingleTapUp : ACTION_UP

2번보다 좀 더 길지만, LongPress는 아닌 상황입니다.

역시 이 때도 약 100ms 정도에 onShowPress 이벤트가 발생하긴 하지만

300ms 이후에 손을 떼었기 때문에 onSingleTapConfirmed 이벤트가 먹히는 현상이 일어납니다.

4. 아주 길게 터치

000ms onDown : ACTION_DOWN
096ms onShowPress : ACTION_DOWN
590ms onLongPress : ACTION_DOWN

LongPress가 발생 하는 상황입니다.

100ms 정도에 onShowPress 이벤트가 발생 하며,

590~600ms 정도에 onLongPress 이벤트가 발생 합니다.

이때 onSingleTapUp 이벤트는 발생 하지 않습니다.

두 번 터치 하는 경우에는 이벤트가 두 가지이기 때문에,

두 가지 조합의 경우 모두 살펴 보겠습니다.

5. 두 번 터치 (onDoubleTap)

000ms onDown : ACTION_DOWN
060ms onSingleTapUp : ACTION_UP
140ms onDoubleTap : ACTION_DOWN
140ms onDown : ACTION_DOWN (지연 될 수 있음)

먼저 onSingleTapUp 이벤트가 발생 합니다.

그리고 onSingleTapConfirmed 가 발생 하기 전에

다시 onDown 이벤트가 들어오게 되면 onDoubleTap 이벤트가 발생 합니다.

참고로 두번째 들어오는 onDown 이벤트는 onDoubleTap 이벤트보다 늦게 들어 올 수 있습니다.

(항상 같이 들어 오는게 아니라 onDoubleTap이 먼저 발생 합니다.)

6. 두 번 터치 (onDoubleTapEvent)

000ms onDown : ACTION_DOWN
041ms onSingleTapUp : ACTION_UP
130ms onDoubleTapEvent : ACTION_DOWN
130ms onDown : ACTION_DOWN (지연 될 수 있음)
190ms onDoubleTapEvent : ACTION_UP

onDoubleTap 이벤트와의 차이는 DOWN, MOVE, UP 이벤트까지 모두 캐치된다는 점이며,

마지막에 onDoubleTapEvent에 UP 액션이 들어오는 것을 확인 할 수 있습니다.

(위의 경우, 190ms 이후에 두번째 터치에서 손이 떨어졌다는 것을 확인 할 수 있습니다.)

7. 두 번 터치 (onDoubleTap + onDoubleTapEvent)

000ms onDown : ACTION_DOWN
080ms onSingleTapUp : ACTION_UP
200ms onDoubleTap : ACTION_DOWN
200ms onDoubleTapEvent : ACTION_DOWN (지연 될 수 있음)
200ms onDown : ACTION_DOWN (지연 될 수 있음)
260ms onDoubleTapEvent : ACTION_UP

같이 사용 하게 되면 onDoubleTap, onDoubleTapEvent 이벤트 둘 다 발생하며,

항상 onDoubleTap 이벤트가 먼저 발생 하게 됩니다.

(결과적으로 onDoubleTap - onDoubleTapEvent - onDown 순서로 발생 합니다.)

8. 두 번 터치, 두 번째 터치시 스크롤 (onDoubleTapEvent)

000ms onDown : ACTION_DOWN
080ms onSingleTapUp : ACTION_UP
179ms onDoubleTapEvent : ACTION_DOWN
179ms onDown : ACTION_DOWN (지연 될 수 있음)
280ms onDoubleTapEvent : ACTION_MOVE
289ms onShowPress : ACTION_DOWN

290ms onDoubleTapEvent : ACTION_MOVE
...
779ms onLongPress : ACTION_DOWN
800ms onDoubleTapEvent : ACTION_UP

평소에 절대 나올법한 제스쳐지만 onDoubleTapEvent의 특성을 살펴보기 위한 제스쳐 입니다.

두 번째 onDown 이벤트 이후에 MOVE 이벤트가 들어 오는 것을 확인 할 수 있으며,

한가지 특이한 점은 계속 스크롤 되지 않고 onLongPress 이벤트가 발생하면 끝난다는 점입니다.

손을 뗄 수 밖에 없는 상황이 오게 되죠.

위에서 보시다 시피,

조금 길게 눌러짐에 따라 onShowPressonLongPress가 도중에 발생 할 수도 있습니다.

9. 스크롤

000ms onDown : ACTION_DOWN
030ms onScroll : ACTION_DOWN, ACTION_MOVE
...

스크롤 이벤트는 간단 합니다.

최소 30ms 이후 부터는 onScroll 이벤트가 발생 할 수 있으며,

플링시키지 않고 살며시 손을 떼면 끝까지 onScroll 이벤트만 연속으로 발생 합니다.

10. 플링

000ms onDown : ACTION_DOWN
030ms onScroll : ACTION_DOWN, ACTION_MOVE
...
900ms onFling : ACTION_DOWN, ACTION_UP

마지막에 손가락을 슬며시 튕기는 플링 동작입니다.

스크롤 이벤트와 비슷하지만, 마지막에 UP 액션과 함께 onFling 이벤트가 동작합니다.

스크롤과 플링 제스쳐 모두 시간에 따라 onShowPress 이벤트가 발생 할 수 있습니다.

[스크랩 : http://blog.vizpei.kr/94697746]