안드로이드 화면 가로/세로 관련하여 가로 모드일 경우 특정 화면에서는 가로로, 세로 모드일 경우에는 특정 화면에서 세로 화면으로의 기능이 필요해서 개발을 하다 보니 가로세로의 정의가 폰과 탭이 달라서 폰과 탭을 구분지을 필요가 있어 조사를 해봤다.

테스트 예제 소스


	private int getScreenOrientationPhone(int orientation) {
		switch (orientation) {
        case Surface.ROTATION_0:
        	return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
        	
        case Surface.ROTATION_90:
        	return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;


        case Surface.ROTATION_180:
        	return ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
        	
        case Surface.ROTATION_270:
        	return ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
        }
		
		return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
	}
	
	private int getScreenOrientationTab(int orientation) {
		switch (orientation) {
        case Surface.ROTATION_0:
        	return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
        	
        case Surface.ROTATION_90:
        	return ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;


        case Surface.ROTATION_180:
        	return ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
        	
        case Surface.ROTATION_270:
        	return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
        }
		
		return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
	}
	
	private int getScreenOrientation(int orientation) {
		if (isTablet()) {
			return getScreenOrientationTab(orientation);
		} else {
			return getScreenOrientationPhone(orientation);
		}
	}

	private boolean isTablet() {
        Configuration config = getContext().getResources().getConfiguration();
        return ((config.screenLayout & Configuration.SCREENLAYOUT_SIZE_XLARGE) == Configuration.SCREENLAYOUT_SIZE_XLARGE);
	}



출처 : http://beom3x2.iptime.org/tc/Android/entry/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%BD%94%EB%93%9C%EC%83%81%EC%97%90%EC%84%9C-%EC%8A%A4%ED%81%AC%EB%A6%B0-%EC%82%AC%EC%9D%B4%EC%A6%88-%EA%B5%AC%EB%B6%84%ED%95%98%EA%B8%B0-%ED%8F%B0-%ED%83%80%EB%B8%94%EB%A6%BF-%EA%B5%AC%EB%B6%84?category=1

다음과같은코드를이용하여코드상에서폰과태블릿을구분할수있다.

(코드상에서폰인지태블릿인지를가져올수있다.)


int screenSizeType = (/*context.*/getResources().getConfiguration().screenLayout &

Configuration.SCREENLAYOUT_SIZE_MASK);

if(screenSizeType == Configuration.SCREENLAYOUT_SIZE_XLARGE) {

// 매우 화면 사이즈, 10인치 이상 태블릿 : 갤럭시탭 10.1, 갤럭시노트10.1, 기타 등등.

}

else if(screenSizeType == Configuration.SCREENLAYOUT_SIZE_LARGE) {

// 화면 사이즈, 7인치 태블릿 : 넥서스7, 갤탭, 기타 등등.;

}

else/* if(screenSizeType == Configuration.SCREENLAYOUT_SIZE_NORMAL ||

screenSizeType == Configuration.SCREENLAYOUT_SIZE_SMALL) */ {

 // 태블릿이아니다() : 갤럭시노트, 갤럭시 S, 베가, 옵티머스시리즈기타폰들.

}



이에대한 자세한 설명은 Configuration  대해서 설명한  Android Developer 사이트에서 확인할 있다.


  대략 요약하자면,context에서 가져온 Configuration 인스턴스 내부의 screenLayout 필드 값을  SCREENLAYOUT_SIZE_MASK 으로 인코딩하여 화면 사이즈 종류를 가져올 있다.  


  Android Developer 페이지에 나와있는 설명을 대충 요약하면 이렇다.


SCREENLAYOUT_SIZE_SMALL

              설명 : 소형 화면. 저밀도(low-density) QVGA 비슷한 크기. - 싸고 화면 작은 저가 폰들이 범주에 속하

 는 같다.

              레이아웃 사이즈 :  최소, 320 x 426 dp.

              :  low-density QGVA,  high-density VGA.


SCREENLAYOUT_SIZE_NORMAL

 설명 :  일반 화면,  medium-density HVGA 비슷한 크기. -  일반적인 . 갤럭시 노트 포함.

 레이아웃 사이즈 :  최소, 320x470 dp.

  :   low-density WQVGA , medium-density HVGA , high-density WVGA.


SCREENLAYOUT_SIZE_LARGE

 설명 :  대형 화면,  medium-density VGA 비슷한 크기.  - 넥서스7 갤탭등.

 레이아웃 사이즈 :  최소, 480x640 dp.

  :  medium-density VGA, medium-density  WVGA


SCREENLAYOUT_SIZE_XLARGE

 설명 :  (?)대형 화면,  medium-density VGA 비슷한 크기 - 현재까지는 갤탭 10.1 갤노트 10.1, 기타 10인 처의 타블릿등등.

 레이아웃 사이즈 :   720x960 dp 이상.

API 9 부터추가. (진저브레드부터사용할있다.)

 

 

Posted by outliers
,

매니페스트에 orientation|keyboardHidden 를 해주어도 onConfigurationChanged() 함수가 호출이 안되는 경우가 있다.
안드로이드 Android 3.2 이상 부터는 "orientation|keyboardHidden" 대신 "orientation|screenSize"로 변경해야 호출이 된다.
매니페스트에서 android:targetSdkVersion 도 같이 확인..

Posted by outliers
,

XML 에서 EditText 속성에
android:inputType="textVisiblePassword" 또는 android:inputType="textUri" 로 설정

아이스크림에서는 안나오는 경우가 발생
그럴 경우 소스 코드에서
editText.setPrivateImeOptions("defaultInputmode=english;"); 로 사용 하면 됩니다.

Posted by outliers
,
 
		// XML 에 키보드를 추가하면 Dialog 뒤의 Activity 의 화면만 줄어든다.
		// Dialog 의 window 의 값을 따로 설정
        // Dialog 의 onCreate 에서 또는 Dialog dialog.getWindow() 해서 사용한다.

		Window win = getWindow();
		WindowManager.LayoutParams winLp = win.getAttributes();
		winLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
		win.setAttributes(winLp);

'Programs > Android' 카테고리의 다른 글

onConfigurationChanged() 호출이 안되는 문제  (0) 2013.06.03
영문 키패드 나오게 하는 방법  (0) 2013.03.19
Content Observer  (0) 2013.02.27
안드로이드 멀티 해상도 지원  (2) 2012.12.04
zxing 세로 모드 스캐너  (1) 2012.11.20
Posted by outliers
,

Content Observer

Programs/Android 2013. 2. 27. 10:45

출처 : http://cafe.daum.net/superdroid/aAfL/110?docid=1MWA2aAfL11020111110130336

Content Observer

Provider는 공용 저장소를 제공하였다.

여기서 좀 찜찜한 기분이 들지 않는가?

공용 저장소라고 하면 나도 데이터를 쓰고/읽고가 가능하고

다른 패키지에서도 데이터를 쓰고/읽고가 가능할 것이다.

 

만일 내가 특정값을 Provider를 통해 읽어와 사용하고 있는 중에,

다른 패키지에서 그 값을 변경했을 경우 문제가 되지 않겠는가?

 

이러한 문제를 해결하기 위해 Content Observer라는 것이 존재한다.

이 녀석의 역할은 특정 URI에 해당하는 데이터가 변경되었는지

감시하는 역할을 한다.

 

테스트 패키지로 이해해 보자.

!!! 테스트 할 패키지는 바로 전 강좌의 소스를 그대로 사용하겠다.

 

먼저 Provider 패키지 부분을 약간 수정해 보자.

아래는 StudentsProvider.java 소스이고

delete() 함수 부분만을 수정할 것이다.

getContext().getContentResolver().notifyChange(uri,null);

이라는 부분이 존재한다.

notifyChange()라는 함수명만 보아도 대충 알만하지 않는가?

변경된 사실을 누군가에게 알린다는게 아닐까?

 

그렇다!  해당 함수는 ContentResolver들에게 DB의 내용이 변경되었다는 것을

알리는 역할을 한다.

위의 소스는 delete() 함수 즉 특정 레코드를 삭제하고 있다.

그러므로 DB의 내용이 레코드 삭제를 통해 변경 되었으므로,

ContentResolver 들에게 알리는 것이다.

 

getContext().getContentResolver().notifyChange(uri,null);

 

notifyChange()함수에서 첫번째 인자 uri 는 무엇을 말할까?

변경된 부분의 Uri 즉 경로를 말한다.

예를 들어 Uri가

content://com.provider.students/students/4

와 같다면

students 테이블의 4번째 id 레코드가 삭제되었다는 것을 의미 하는 것이다.

 

content://com.provider.students/students

와 같다면

students 테이블의 여러개의 레코드가 삭제되었다는 것을 의미 하는 것이다.

 

위의 소스와 같이 Provider 구현자는 DB가 변경되는 부분에

notifyChange() 함수를 넣우 둬야 한다.

DB가 변경된 사실을 꼭 알릴 필요가 없다면 마음대로 하라. ^^

내가 하고 싶은 말은 구현자의 몫이라는 것이다.

 

 

 

  !!! 그냥 참조만 하자.

 

 

  우리가 사용하는 ContentObserver는 System Service이다.

  위의 소스에서 ContentService 가 바로 ContentObserver를 관리하는 서비스 인 것이다.

  아래는 Framework의 ContentService 소스이다.

  ContentProvider에서 notifyChange() 함수를 호출하면 바로

  ContentService의 notifyChange() 함수가 호출되는 것이다.

 

이제는 위의 변경되었다는 사실을 받는 부분을 구현해야 한다.

이전 패키지에 Resolver 부분을 그대로 수정하자.

아래는 StudentsResolverTestActivity.java 파일이다.

1번과 같이 ContentObserver 객체 변수를 선언하고

2번과 같이 ContentObserver 를 구현한다.

ContentObserver class는 abstruct class이다.

그러므로 추가적으로 3번과 같이 0nChange ()함수를 구현해 주어야 한다.

해당 함수는 ContentProvider가 변경 사실을 알려 줄때

호출되는 Callback 함수 이다.

해당 함수가 정말 호출되었는지 확인하기 위해서 Log를 남겨 두자.

이 ContentObserver가 동작하기 위해서는

5번과 같이 ContentResolver에 등록해 주어야 한다.

등록하는 함수는 registerContentObserver()이다.

또한 해지 하는 함수는 6번과 같이 unregisterContentObserver()이다.

 

그런데 만일 해지를 하지 않으면 큰일 날까?

Framework 소스 확인해 본 결과 특별히 문제가 되진 않았다.

그런데 왜 책이나 인터넷에는 꼭 해지를 해야 한다고 할까? ^^a

 

개인적인 생각으로는

더 이상 noti를 받기 싫은 경우에 unregisterContentObserver()를 사용해서

해지 하는 것이 주 용도라고 생각한다.

하지만 등록과정이 있으므로 해당 Activity가 종료하기 전에

해제 하도록 하여 Framework의 부하를 조금이라도 줄여 주는 것이 맞다.

 

수정한 Provider와 Resolver 패키지를 모두 설치하고

Resolver를 아래와 같이 실행해 보자.

위의 1번 Insert를 눌러 ContentPorvider에 데이터를 추가하고

2번의 Delete를 눌러 데이터를 삭제해 보자.

Delete를 누르면 Provider에서 notifyChange() 가 호출될 것이다.

3번에서 정상적으로 호출된 로그가 출력되었다,

해당 notifyChange()가 Provider에서 호출된후,

Resolver 측에서 그 결과를 전달받게 된다.

4번에서 정상적으로 0nChange() 함수가 호출된 것을 볼 수 있다.

정말 간단하지 않은가? ^^

 

자 좀더 자세히 알아보기 위해

registerContentObserver() 함수에 대해서 살펴 보자.

 

해당 함수의 원형은 아래와 같다.

 

public final void registerContentObserver

(

Uri                       uri,  <<== 첫번째 인자.

boolean                notifyForDescendents,

ContentObserver    observer

)

 

위에서 세번째 인자 observer는 무엇을 의미하는지 알 것이다.

0nChange() 가 구현된 ContentObserver 객체를 넣어주면 된다.

그렇다면 첫번째 인자 URI는 무엇을 의미하는 것일까?

아래의 그림을 보고 이해해 보자.

우선 Resolver 측에서

1번에서 registerContentObserver()함수를 이용해서 등록하였다.

2번을 보면 등록할때 첫번째 인자로 URI를 넘긴다.

3번과 같이 URI는 "content :// com.provider.students / students"이다.

         즉 "content :// com.provider.students / students" 경로의 데이타가

         변경되면 알려 달라는 의미이다.

자 이제 Provider 측이다.

4번을 보면 특정 데이타가 변경되어 notifyChange() 함수를 호출하여 알린다.

5번은 변경된 데이터의 경로 Uri가 첫번째 인자로 전달된다.

6번의 Uri은 "content :// com.provider.students / students" 이다.

        즉 "content :// com.provider.students / students" 경로의 데이타가 변경되었다는 의미이다.

7번에서 ContentService 측에서

        Resolver에서 등록한 Uri와 Provider에서 알린 Uri가 같은지 체크한다.

8번에서 같으면 ContentService는 해당 Resolver에 0nChange() 함수를 호출해 주는 것이다.

 

이해가 되는가?

 

 

자 그렇다면 두번째 인자가 의미하는 것은 무엇일까?

 

public final void registerContentObserver

(

Uri                       uri,

boolean                notifyForDescendents, <<== 두번째 인자.

ContentObserver    observer

)

 

위에서 보면 Provider에서 보낸 Uri와 Resolver에서 등록한 Uri가

완전 동일해야만 noti를 받을 수 있었다.

하지만 예를들어

Resolver에서 등록한 Uri : "content :// com.provider.students / students"

Provider에서 보낸     Uri : "content :// com.provider.students / students / 4"

이라면 서로 Uri가 달라 받을 수 없을 것이다.

하지만 자세히 보라. 상위 경로는 모두 동일하고 하위 경로 "/ 4" 만 다른다.

이렇게 하위 경로만 다른 경우에도 받고 싶을 때가 많을 것이다.

(하위 경로를 일일이 다 알 수 있는 것다 아니지 않은가?)

 

그때 바로 두번째 인자인 notifyForDescendents 를 "true"로 설정하면 된다.

 

아래의 그림으로 이해해 보자.

Provier측에 7번에서 하위 경로가 "/125" 로 추가 되었다.

하지만

Resolver측에서 2번과 같이 notifyForDescendents 를 "true"로 설정하였다.

그로 인해 8번과 같이 일치하지 않아도

9번이 실행된 것이다.

 

자 테스트를 해 보자.

아래의 Resolver 소스를 약간 변경해 보자.

자 "true"로 변경하였다.

 

 

 

자 정상적으로 받을까?

실행해 보자.

 

1번버튼을 눌러 insert로 데이터를 추가해 두자.

데이터를 추가할때 화면에 "content :// com.Provider.Students / students / 3" 번 경로의 데이터가

추가된 것을 알 수 있다.

 

!!! 자 2번에 delete 버튼을 눌러 지우기 전에 한가지 소스를 더 수정해야 한다.

위와 같이 "content :// com.Provider.Students / students / 3" 이 수정 되었으므로

해당 데이터만 지원 주는 코드를 테스트를 위해 변경한 것이다.

다시 실행해 보자.

 

자 이제 2번과 같이 Delete 버튼을 눌렀 이전에 1번에서 추가된

"content :// com.Provider.Students / students / 3" 을 삭제해 보자.

과연 0nChange() 함수가 호출이 될까?

위에 로그를 보면 4번과 같이 정상적으로 호출된 것을 알 수 있다.

 

정리해 보면

 

Provider에는

    특정 레코드가 삭제되었으므로

    "content :// com.Provider.Students / students / 3"  라고 Uri이 notifyChange()를 날렸을 것이고,

Resolver에는

    "content :// com.Provider.Students / students" 라고

    Uri가 registerContentObserver() 함수로 등록되었다.

 

그렇다면 서로 Uri가 달라서 0nChange ()가 호출되지 않아야 하나.

Resolver에서 registerContentObserver() 함수로 등록할때

두번째 인자인 notifyForDescendents 를 "true"로 설정했지 때문에

하위 경로가 추가되어도 호출이 된 것이다.

 

아~ 늘 말하는 거지만 간단한 것을 글로 설명하자니 또 길어 졌다. ^^;;

 

자 마지막으로

ContentObserver 객체를 생성할때

구현해 주어야 하는 0nChange() 함수를 자세히 보자.

1번과 같이 첫번째 인자로 selfChange 라는 녀석이 있다.

무엇을 위해 존재하는 것일까?

테스트를 위해 바로 전에 수정한 내용을 모두 원복하고

2번과 같이 selfChange 값이 어떻게 넣어 오는지 로그를 남겨 보자.

 

자 실행하자.

1번 버튼을 눌러 데이터를 추가하고

2번 버튼을 눌러 지워보자.

3번과 같이 로그를 확인해 보면 0nChange() false" 라고 출력 되었다.

 

이 값은 늘 "false" 일 것이다. ^^;

그렇다면 "true"인 경우가 없는가?

물론 존재한다.

위에서 늘 "false"라고 했던 이유는 우리가 특별한 처리를 해 주지 않은 경우이다.

 

자 그 특별한 경우가 무엇일까?

 

잠시 아래의 내용을 고민해 보자.

만일 Provider에서 notifyChange()를 날렸을때 말고

Resolver에서 강제로 0nChange ()를 호출 되게 할 방법이 없을까?

존재한다.

아래의 Resolver 소스를 수정해 보자.

위의 1번은 insert 버튼을 눌렀을때

생성된 ContentObserver 객체 멤버 함수인 dispatchChange() 함수를 호출하는 것이다.

 

이 함수가 바로 0nChange () 함수를 강제로 호출하게 해준다.

 

dispatchChange()  함수 인자에는 boolean 값이 들어 간다.

이 값을 "true"라고 넣자.

 

자 이제 실행해 보자.

1번에 insert 버튼을 누르면

2번과 같이 dispatchChange()  함수 호출되면서 0nChange () 함수가 강제로 호출되고

         로그가 남았다.

         여기서 주목할 것은 0nChange () 함수의 인자가 "true"로 넣어 온 것이다.

         즉 dispatchChange(boolean) 함수의 인자 값에 따라

         0nChange() 의 인자가 결정되는 것이다.

         우리가 강제로 dispatchChange() 함수를 호출할때는

         우리 스스로가 호출한 것을 구분하기 위해 dispatchChange() 함수의

         인자를 "true"로 넣어 준다.

         그렇다면 0nChange () 함수 내에서 인자 "selfChange" 를 보고

         구분에서 원하는 처리를 하면 된다.

 

 

위에서 작성된 테스트 코드는 아래의 첨부를 참조하자.

 

Posted by outliers
,

참고링크 : http://www.androidpub.com/2207296

 

단순 번역이 아니라, 필요없는 부분(내가 생갈할 때, 굳이 언급안 해도 되는 부분)은 과감히 삭제하였으며, 이해를 돕기 위해 필요한 부분은 덧 붙이기도 했습니다.


Multiple-Screen 관련 이슈 가지고 계신 분들께 큰 힘이 되길 바랍니다.


=======================================================================


Supporting Multiple Screens


안드로이드는 서로 다른 screen size 및 density 를 갖는 device 에서 구동됩니다.

안드로이드 system 은 application 을 위해, 이런 특성을 care 할 수 있도록 개발 환경을 제공 하며, 대부분 device 의 screen UI 에 적용할 수 있는 feature 를 가지고 있습니다.

또한, 특정 screen size 및 density 에 맞게 조절할 수 있도록,(서로 다른 screen configuration 에 맞게 UI design을 최적화할 수 있도록) API 도 제공해 줍니다.


안드로이드 자체가 App 을 서로 다른 screen 에 맞게 scaling 및 resizing 을 수행해주지만, 각각의 device screen size 및 density 에 맞게 application을 최적화시켜주는 건 당신(개발자) 몫입니다.

그렇게 함으로써, user experience를 극대화 시킬 수 있으며, 사용자들은 당신의 app 이 그들의 device 에 맞게 design 되었다고 느끼게 될 것입니다.


이 문서 내용을 익힘으로써, 당신은 하나의 apk 로 모든 android supported screen configurations 에서 정확하게 동작하는 application 을 개발할 수 있습니다.


Overview of Screens Support

Terms and concepts


Screen size
- 물리적인 화면 크기

Screen density
- 물리적인 크기 안의 pixel 개수. 즉, pixel 밀도라고 보면 됩니다.
크기가 클 수록 pixel 밀집도가 올라가므로 선명하게 보이겠죠?

Orientation
- Landscape or Portrait (가로/세로 뷰)

Resolution (해상도)
- screen 의 총 pixel 개수.가로/세로 표시함으로써 총 pixel 개수를 알 수 있다.

Density-independent Pixel (dp)
- 절대 길이를 표시해 주는 단의.
- 160 dpi 에서의 1 pixel 길이는 1 dp 와 동일하다.

Range of screens supported

Android 1.6(API Level 4) 부터, 안드로이드는 Multiple screen sizes, densities 에 대한 지원기능을 제공해 왔습니다. 이러한 안드로이드 시스템의 feature 를 사용함으로써, 각 screen configurations 에 맞게 UI 최적화할 수 있으며, 각 screen 에 맞는 최고의 user experience 를 제공해줄 수 있습니다.
당신이 multiple screens 를 위한 UI 설계하기 위한 방법을 단순화시키기 위해, 안드로이드는 screen configuration 을 다음과 같은 range로 나누어서 관리합니다.
(수 많은 device screen 의 각각의 특성에 따라서 일일히 대응하기는 불가능하겠죠.)

- A set of four generalized sizes : small, normal, large, and xlarge
- A set of four generalized densities: ldpi(low), mdpi(medium), hdpi(high), and xhdpi(extra high)

이들은 Normal size and mdpi (HVGA)를 기준으로 arranged 되었으며, 이 기준은 최초의 android powered device 인 T-Mobile G1 의 screen configuration 이었다.
이 device 는 HVGA screen 이었으며 이는 Android 1.6 까지 android 가 지원하는 유일한 screen configuration 이었다.

Device 마다 각 size 와 denisty 는 조금씩 미세하게 다를 수 있다. 예를 들면, 동일한 screen size 를 가진다는 서로 다른 device 도 실제로는 약각 size 또는 가로/세로 비율(ratio)이 다를 수 있다는 것이다.
density 도 마찬가지로 pixel 밀도가 약간씩 다를 수 있다.
안드로이드는 이런 미묘한(미세한) 차이점들을 간단하게 추상화시킴으로, 이로 인해 당신은 generalized size 와 generalized density 만을 위해 UI design 을 하고, 나머지는 system 이 최종 적용하도록 하도록 하면 된다.

Figure 1. Illustration of how Android roughly maps actual sizes and densities to generalized sizes and densities (figures are not exact).


위에 표시된 각 generalized size 들은 각 특성에 맞게 최소한의 해상도 값을 갖게 된다.

  • xlarge screens are at least 960dp x 720dp
  • large screens are at least 640dp x 480dp
  • normal screens are at least 470dp x 320dp
  • small screens are at least 426dp x 320dp

  • 당신은 서로 다른 화면 사이즈와 density 에 대한 Application 의 UI 를 최적화하기 위해, 각 generalized sizes and density 에 맞는 resource 를 제공해 주면 된다.

    예를 들면, 당신은 각 screen size 에 맞는 각각의 레이아웃을 만들 수 있으며, run time 때에 시스템은 현 실행되는 device 의 화면 설정값에 따라서 적당한 resource 를 사용할 수 있을 것이다.


    당신은 모든 screen size 와 density 조합을 갖는 각 screen 을 위한 resource 를 제공할 필요는 없다.

    안드로이드 시스템은 당신의 Application을 각 device screen의 configuration 값에 따라서 rendering 하는 강력한 호환성을 제공해준다.(당신이 이 문서에 명시된 practice 데로 구현할 경우에 한한다.)


    Density independence

    당신 App 이 각 device 의 density 에 상관없이, 동일한 element size 를 유지하고 있다면, 당신 App 은 "Density independence" 특성을 가지고 있는 것이다.

    Density independence 를 유지한다는 것은 매우 중요하다. 왜냐하면, 그것 없이는 UI element size 가 low density 에서는 크게 보이며, high density 에서는 더 작게 보이기 때문이다.
    Application 의 element들이 screen density 에 따라 size 가 달라진다면, 사용성에서 큰 문제를 야기할 수 있다.

    Figure 2. Example application without support for different densities, as shown on low, medium, and high density screens.

    Figure 3. Example application with good support for different densities (it's density independent), as shown on low, medium, and high density screens.


    안드로이드 시스템은 이를 위해 두 개의 방법을 제공해준다.

    - 시스템은 현 device density 에 맞게 dp units 을 적절히 scale(확대/늘리다.) 해준다.

    - 시스템은 현 device density 에 맞게 drawble resources 들을 scale 해준다.


    Figure 2 의 경우, Text view 와 Bitmap drawble 은 px units 으로 명시되어 있으며, 그래서 screen density 에 따라서 그 크기가 달리 보인다. 이는 screen size 는 같을지라도, high density 스크린의 경우, 인치당 pixel 수가 더 많기 때문이다.

    Figure 3 의 경우, dp units 으로 명시되었다. medium denisty 의 경우, Figure 2 와 동일하게 보이지만, low/high density 에서는 screen 에 맞게 상대적으로 scale up/down 해주므로 결국medium density 와 동일하게 보인다.


    대부분의 경우, dp units 명시와 "wrap_content" 의 사용만으로, 시스템은 현 screen density 의 scaling factor 에 따라서 bitmap drawables 을 적절하게 scaling up/down 해 주며, 이로 인해서 Application 의 density independence 를 보장할 수 있게 된다.


    하지만, bitmap scaling 은, 위 화면에서 알아챌 수도 있겠지만, 흐릿하게 보이거나 부분 부분 보이도록 하는 결과가 나올 수 있다.

    이러한 문제를 피하기 위해서는 당신은 각각의 density 에 맞는 resource 를 제공해 줄 필요가 있다.

    예를 들면, high-density screens 을 위해 higher-resolution bitmap 을 제공한다면, 시스템은 default(medium-density) resource 를 resizing 하는 것 대신에 제공된 resource 를 사용하게 될 것이다.

    다음 장에서는 이런 방법에 대해 좀 더 살펴보겠다.


    How to Support Multiple Screens

    안드로이드의 '멀티플 스크린 지원하기'의 기본은 현 스크린 정보에 맞게 적절한 방법으로 어플리케이션의 layout 과 bitmap drawables 를 렌더링하는 기법에 대한 것이다.
    시스템은 스크린 사이즈와 Density 에 맞게 Layout 을 scaling 하고, Bitmap drawables 은 스크린 Density 에 맞게 적절하게 scaling 한다.
    하지만, 각 스크린 사이즈에 맞게, 좀 더 완벽하게 대응하기 위해서는 당신은 하기 항목들을 수행해야 한다.

    - manifest 파일안에 지원하는 스크린 사이즈 선언하기
    지원하는 스크린 사이즈를 선언해 놓음으로써, 오직 지원가능한 스크린 사이즈를 가진 해당 Device 에서만 당신의 App.을 다운로드가 가능하도록 하는 방법이다.

    - 각각의 스크린 사이즈에 맞는 각각의 Layout 작성하기.
    물론, 안드로이드가 당신의 App.을 스크린 사이즈에 맞게 resize 해주지만, 상황에 따라서는 스크린 사이즈별 레이아웃이 필요할 수 있다. 예를 들면, 좀 더 큰 스크린일 경우, 남아도는 여백의 스크린 공간을 활용하기 위해, 당신은 elements 의 position 이나 size 를 변경할 필요성을 느낄 것이다.
    이를 위한 size-specific 한 resource 를 명시해 주는 qualifiers 는 small, normal, large 그리고 xlarge 이다. 예를 들면 xlarge screen 을 위한 layout 은 "layout-xlarge" 폴더안에 넣어두면 된다.

    하지만,~~ Anroid 3.2(API Level 13) 에 와서 위의 size groups 들은 사용하지 않으며, 대신, sw<N>dp 형식의 qualifiers 로 명시해 준다. 예를 들어 당신의 multi-pane tablet layout 이 적어도 600 dp screen width 을 가져야 한다면 해당 layout resource 는 "layout-sw600dp" 폴더안에 넣어 두면 된다.

    - 각각의 스크린 Density 에 맞는 Bitmap drawables 제공하기.
    안드로이드는 기본적으로 각 스크린 사이즈에 맞추기 위해 당신의 bitmap drawables (.png, .jpg and .gif files) 과 Nine-Patch drawables (.9.png files) scaling 한다.
    예를 들면, 당신이 bitmap 파일을 medium screen density (mdpi) 용으로만 제공한다면 시스템은 알아서 hdpi 또는 ldpi device screen 에 맞게 scale up/down 해준다.

    Density-specific resources를 위해 명시해주는 qualifier 는 ldpi(low), mdpi(medium), hdpi(high), 그리고 xhdpi (extra high) 이다.
    예를 들어 high-density 용으로 제작된 bitmap 파일은 "drawable-hdpi" 폴더에 넣어주면 된다.

    Runtime 에, 시스템은 아래의 과정으로 가능한한 최적의 display 를 보장해준다.

    1. 시스템은 적절한 대체 resource 를 사용한다.
    스크린 사이즈와 Density 에 맞게 시스템은 당신의 App 에서 필요한 qualifier 가 붙은 폴더를 찾아 해당 폴더내에 있는 resource 를 사용할 것이다.

    2. 만약 매칭되는 resource 가 없다면, default resource(mdpi) 를 사용하며, 이를 스크린 사이즈와 Density 에 맞게 scale up/down 한다.
    default resource 란, tag(qualifier) 가 붙지 않은 폴더내에 존재하는 resource 를 말한다.(layout or drawable)
    시스템은 이를 기준 size 와 density 로 가정하고 각각의 스크린 configuration 에 맞게 scale up/down 한다. 그렇다고 항상 default 폴더에서 가져오는 것은 아니다. 경우에 따라서는 좀 더 좋은 결과를 얻기 위해, 다른 폴더에서 resource 를 가져오는 경우가 있다.
    예를 들면, 시스템이 ldpi 용 resource 를 찾고 있는데, 이게 없다면, hdpi resource 를 scale down 할 것이다. hdpi resource 에서 ldpi 로 factor 0.5 값으로 scale down 하기 좀 더 쉽고, 결함없이 가능하기 때문이다. mdpi resource 에서 ldpi 로 scale down 할 경우, factor 값은 0.75 가 된다.

    Using configuration qualifiers


    안드로이드는 시스템이 현 스크린 특성에 맞게 적절한 resource 를 선택할 수 있도록 여러개의 Configuration Qualifiers 를 제공해 준다.

    Configuration Qualifiers 는 resource directory name 에 덧 붙일 수 있도록 string 으로 표시되며 이 값으로 어떤 resource 들이 해당 폴더안에 들어있는지 파악할 수 있게 된다.


    Table 1. Configuration qualifiers that allow you to provide special resources for different screen configurations.

    Screen characteristic Qualifier Description
    Size small            Resources for small size screens.
    normal Resources for normal size screens. (This is the baseline size.)
    large Resources for large size screens.
    xlarge Resources for extra large size screens.
    Density ldpi Resources for low-density (ldpi) screens (~120dpi).
    mdpi Resources for medium-density (mdpi) screens (~160dpi). (This is the baseline density.)
    hdpi Resources for high-density (hdpi) screens (~240dpi).
    xhdpi Resources for extra high-density (xhdpi) screens (~320dpi).
    nodpi Resources for all densities. These are density-independent resources. The system does not scale resources tagged with this qualifier, regardless of the current screen's density.
    tvdpi Resources for screens somewhere between mdpi and hdpi; approximately 213dpi. This is not considered a "primary" density group. It is mostly intended for televisions and most apps shouldn't need it—providing mdpi and hdpi resources is sufficient for most apps and the system will scale them as appropriate. If you find it necessary to provide tvdpi resources, you should size them at a factor of 1.33*mdpi. For example, a 100px x 100px image for mdpi screens should be 133px x 133px for tvdpi.
    Orientation land Resources for screens in the landscape orientation (wide aspect ratio).
    port Resources for screens in the portrait orientation (tall aspect ratio).
    Aspect ratio long Resources for screens that have a significantly taller or wider aspect ratio (when in portrait or landscape orientation, respectively) than the baseline screen configuration.
    notlong Resources for use screens that have an aspect ratio that is similar to the baseline screen configuration.

    Note: If you're developing your application for Android 3.2 and higher, see the section about Declaring Tablet Layouts for Android 3.2 for information about new configuration qualifiers that you should use when declaring layout resources for specific screen sizes (instead of using the size qualifiers in table 1).



    Designing alternative layouts and drawables

    Layout 과 Drawable 사용 유형은 전적으로 Application 의 요구사항에 따른다. 보통, 일반적으로 Layout 을 위해서는 size 와 orientation qualifier 를 사용하며, Bitmap drawables 를 위해서는 density qualifiers 를 사용한다.

    Alternative layouts

    일단 다른 screen size 의 device 에서 여러가지 테스트를 해보다보면, Application 이 추가적인 Layout 이 필요한지, 불필요한지 알아볼 수 있다.

    - 작은 스크린에서 테스트한다면, 버튼 크기가 스크린 width 와 맞지 않을 경우, 버튼 크기 및 위치를 조정해 주는 새로운 layout 이 필요하다.
    - 큰 스크린에서 테스트한다면, 너무 많은 쓸모없는 여백이 생긴다는 걸 알게 될 것이다.
    - 가로 세로 화면에 대한 테스트를 해 본다면, 세로 뷰(Portrait mode)에서 바닥에 있던 버튼이, 가로 뷰(Landscape mode)에서는 우측에 있어야 한다고 느낄 수도 있다.

    이 들을 요약해 보면, 결국 하기 사항들을 확인해 보면 된다.

    - small screen 에 적합한가?
    - 큰 screen 의 여백의 이점을 활용할 수 있도록 최적화 되었는가?
    - 가로/세로 뷰에 모두 최적화 되었는가?

    만약 내부 view 에 의해 size 가 변경되어야 하는 bitmap 을 사용한다면,(버튼의 background image) Nine-Patch bitmap files 를 사용해야 한다. Nine-Patch 파일은 stretchable 한 영역 정보가 명시되어 있는 png 파일이다. 시스템은 늘여야 한다고 판단할 경우, 이 영역만을 반복함으로써, 늘려서(stretch) display 해준다. Nine-Patch 이미지는 어떤 사이즈에도 맞출 수 있으므로, screen size 마다 별개의 file 을 만들 필요가 없다.
    하지만, screen density 에 따라서는 각각의 버젼에 대한 Nine-Patch 파일을 제공해줘야 한다.
    (Density 에 따라서 각각의 padding 영역이 조정 된 파일이 적용되어야 한다.)

    Alternative drawables

    거의 모든 application 들은 density 에 해당하는 각 drawable resource 를 가지고 있다. 기본적으로 application은 Launcher icon 을 가지고 있기 때문이다. 이들은 모든 density 에서 명확하게 표시되어야 한다.
    마찬가지로 다른 bitmap resource 를 사용하고 싶다면, 각 density 별로 폴더에 가지고 있어야 한다.

    이렇게 각 density 별로 bitmap resource 를 생성할 경우, 4개의 generalized densities 에 따라서 3:4:6:8 scaling ratio 를 따라서 생성하면 된다.

    Figure 4. Relative sizes for bitmap drawables that support each density.


    예를 들어 mdpi 용 48X48 image 파일이 있다면, 각 density 별 image size 는 아래와 같다.


    • 36x36 for low-density
    • 48x48 for medium-density
    • 72x72 for high-density
    • 96x96 for extra high-density

    Best Practices

    이 문서의 목적은 Android 가 지원하는 어떠한 screen configuration 에서도 적절히 동작하며 제대로 보이는 application 을 작성하는 것이다. 앞서 이를 위해, Application 이 각 screen configuration 에 맞게 적용시키는 방법, 그리고 어떻게 customize 하는지에 대한 방법에 대해 기술했다. 이번 section 에서는 몇 가지 Tip 과 적절한 scale 방법에 대한 technique 에 대한 overview 를 하겠다.

    다음은 서로 다른 스크린에서 application 이 적절하게 display 되는지를 보장할 수 있는 방법에 대한 Quick checklist 입니다.

    1. XML Layout file 에서 치수를 명시할 때는 wrap_content, fill_parent 또는 dp 단위를 사용해라.
    2. Application Code 내에서 pixel value 를 절대 사용하지 말라.
    3. AbsoluteLayout 을 사용하지 말라.(Deprecated)
    4. 서로 다른 screen density 에 따른 각각의 bitmap drawables 를 제공하라.

    다음은 각 항목에 대한 자세한 설명이다.

    1. XML Layout file 에서 치수를 명시할 때는 wrap_content, fill_parent 또는 dp 단위를 사용해라.

    android:layout_width 또는 android:layout_height 를 명시할 때는 wrap_content, fill_parent 또는 dp 단위를 사용하면 각 device screen size 에 맞게 적절한 size 로 변경될 것이다.
    예를 들면, layout_width="100dp" 로 명시했다면, medium density 에서는 100 pixel 로 표시되겠지만, high density screen 에서는 150 pixel 로 알아서 표시될 것이다.
    결과적으로 물리적으로는 동일한 길이로 표시된다.
    마찬가지로 text size 를 명시할 때도 sp 단위를 사용해라.

    2. Application Code 내에서 pixel value 를 절대 사용하지 말라.

    성능문제와 코드 단순화를 위해 android system 은 내부에서는 모두 pixel 단위를 표준으로 사용한다. 즉 view 의 크기는 항상 pixel 값으로 처리되며, 이는 항상 현재 screen 의 density 에 따른 계산 결과를 기반으로 한다.

    3. AbsoluteLayout 을 사용하지 말라.(Deprecated)

    대신에 RelativeLayout 을 사용해라.

    4. 서로 다른 screen density 에 따른 각각의 bitmap drawables 를 제공하라.

    비록 system 이 알아서 현 screen density 에 맞게 scale 해주겠지만, 좀 더 선명하게 보여주기 위해 density 에 따른 최적화 작업은 필요하다.

     

     

    Posted by outliers
    ,


    zxing 에서 가로모드로만 되어 있는 것을 세로 모드로 바꾸어 보겠습니다.
    zxing 버전은 2012년 11월 20일 ZxingDemo versionCode=87 입니다.
    zxing : https://github.com/zxing/zxing

    많은 블로그에서 가져와서 테스트 해본 결과 입니다.

    1. AndroidManifest.xml 에서 android:screenOrientation="portrait" 로 설정
    2. CameraConfigurationManager.java
    3.  
      	void initFromCameraParameters(Camera camera) {
      		Camera.Parameters parameters = camera.getParameters();
      		WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
      		Display display = manager.getDefaultDisplay();
      		int width = display.getWidth();
      		int height = display.getHeight();
      		// We're landscape-only, and have apparently seen issues with display thinking it's portrait 
      		// when waking from sleep. If it's not landscape, assume it's mistaken and reverse them:
      		// 아래 if 문을 주석 처리를 합니다.
      //		if (width < height) {
      //			Log.i(TAG, "Display reports portrait orientation; assuming this is incorrect");
      //			int temp = width;
      //			width = height;
      //			height = temp;
      //		}
      		screenResolution = new Point(width, height);
      		Log.i(TAG, "Screen resolution: " + screenResolution);
      		cameraResolution = findBestPreviewSizeValue(parameters, screenResolution);
      		Log.i(TAG, "Camera resolution: " + cameraResolution);
      	}
      
    4. void setDesiredCameraParameters(Camera camera, boolean safeMode) 함수에서 제일 아래 부분의 
      camera.setParameters(parameters); 전에 camera.setDisplayOrientation(90); 를 추가 합니다.
    5. CameraManager.java 파일에서 getFramingRectInPreview() 에 아래와 같은 코드를 추가 합니다.
    6.  
            rect.left = rect.left * cameraResolution.y / screenResolution.x;
            rect.right = rect.right * cameraResolution.y / screenResolution.x;
            rect.top = rect.top * cameraResolution.x / screenResolution.y;
            rect.bottom = rect.bottom * cameraResolution.x / screenResolution.y;
      

       

    7. DecodeHandler.java 파일에서 private void decode(byte[] data, int width, int height) 함수에 아래와 같은 코드를 추가 합니다.
     
        byte[] portraitData = new byte[data.length];
        for (int y = 0; y < height; y++) {
        	for (int x = 0; x < width; x++) {
        		portraitData[x * height + height - y - 1] = data[x + y * width];
        	}
    	}
    	int tmp = width;
    	width = height;
    	height = tmp;
      	// 회전한 데이터를 buildLuminanceSource 에서 사용 해야 함
      	PlanarYUVLuminanceSource source = activity.getCameraManager().buildLuminanceSource(portraitData, width, height);
    
      간단한 QR Code 생성은 다음에 작성하도록 하겠습니다.
      Posted by outliers
      ,

      Activity 에서 onKeyDown()를 아래와 같이 Override 하면 된다.

       

      	@Override
      	public boolean onKeyDown(int keyCode, KeyEvent event) {
      		switch (keyCode) {
      		case KeyEvent.KEYCODE_BACK:
      			return true;
      		}
      		return super.onKeyDown(keyCode, event);
      	}
      
      Posted by outliers
      ,
       
      	// 키 가드 위로 화면을 표시 하고 싶을 경우 설정 한다.
      	Window win = getWindow();
      	win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED 
      					| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
      
      	// 안드로이드 Clock 소스
      	final Window win = getWindow();
      	win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
      	        | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
      	// Turn on the screen unless we are being launched from the AlarmAlert
      	// subclass. 
      	if (!getIntent().getBooleanExtra(SCREEN_OFF, false)) { 
      	    win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
      	            | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
      	            | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON);
      	}
      	
      
      FLAG_SHOW_WHEN_LOCKED : Lock 화면 위로 실행(full-screen 만 지원)
      FLAG_DISMISS_KEYGUARD : Keyguard를 해지한다.
      FLAG_KEEP_SCREEN_ON : Screen 을 켜진 상태로 유지한다.
      FLAG_TURN_SCREEN_ON : Screen On

      FLAG_KEEP_SCREEN_ON 과 FLAG_DISMISS_KEYGUARD 를 같이 사용 해야 함.
      Posted by outliers
      ,

       

      xml 에서 속성으로 하면 정상동작 하지 않음.
      webView.setVerticalScrollbarOverlay(true); 로 설정을 해주어야 함.
      아이스크림 버전은 속성을 주지 않아도 정상 동작 함.

      Posted by outliers
      ,