2012년 3월 22일 목요일

[안드로이드] 사용자 정의 permission의 선언

------------ 요기는 삽질 내용입니다. permission의 선언법만 궁금하시면 넘어가세요.
간단한  ContentProvider를 테스트 하기 위해 샘플 프로젝트를 만들어 보았다. 액티비티 하나,  ContentProvider  하나. 이 App를 CPTestApp1 이라 명명해 보았다.

<provider
            android:name="TestContentProvider"
            android:authorities="com.hermina.testcontent">
</provider>


잘동작한다.

이번엔 신규 App CPTestApp2를 생성해 CPTestApp1에서 만든  ContentProvider를 사용해 보기로 하였다.
뭐 잘 된다.

이번엔 CPTestApp1의 ContentProvider에 permission을 지정 해 보았다. 기왕 하는거 퍼미션명도 다르게 지정해 보았다.

<provider
            android:name="TestContentProvider"
            android:authorities="com.hermina.testcontent"
            android:readPermission="com.hermina.permission.CP_READ" >
</provider>



그리고 나서 CPTestApp2에 해당 권한을 넣어 준다.
<uses-permission android:name="com.hermina.permission.CP_READ"/>

젠장 이번엔 안된다.
"com.hermina.testcontent"에 접근 하려면 "com.hermina.permission.CP_READ"권한이 있어야 한다는데...

이쯤에서 인터넷 검색해보고 별짓 다해봤다. ContentProvider에 관련된 자료와 책을 보고 또보고 다른 소스 코드들을 열심히 보았지만 이유를 몰랐다.
그러던중 <permission android:name="xxx.xxxxxx.xxxxx" /> 를 발견하게되고...
분을 삭힐수 있게 되었는데...
어릴땐 책을 사면 아까워서 글자 한톨 그림 구석구석 정독을 했었다. 하지만 언제부턴가 책을 사도 빠르게 필요한 부분만 뽑아 보게 되었다. 내가 만약 안드로이드 permission에 관해 먼저 자세히 알고 있었다면 이런 한심한 삽질은 하지 않았으랴...

------------ 본론입니다.
안드로이드에서 사용자 정의 퍼미션을 선언하는 방법은 다음과 같다.

<receiver android:name=".NewPhotoReceiver">

컨텐트 프로바이더에서 해당 퍼미션을 사용 하려면 다음과 같이 하면 되고

<provider
            android:name="TestContentProvider"
            android:authorities="com.hermina.testcontent"
            android:readPermission=" xxx.xxxxxx.xxxxx " >
</provider>


이를 사용 하는 어플리케이션에서 해당퍼미션을 허용하려면

<uses-permission android:name=" xxx.xxxxxx.xxxxx "/>

처럼 사용 하면 된다.

2012년 3월 20일 화요일

[안드로이드] Broadcast - 카메라로 사진을 찍을 경우 발생하는 인텐트



카메라에서 사진을 찍으면 com.android.camera.NEW_PICTURE 라는 브로드 케스트가 생성 된다.
이걸 처리하는 인텐트 필터를 선언 하고 브로드 케스트 리시버를 만들어 주면 사진이 찍힐때 마다 하고자 하는 일을 할 수 있게 된다.

* XML 선언 예
<receiver android:name=".NewPhotoReceiver">
<intent-filter>
<action android:name="com.android.camera.NEW_PICTURE" />
<data android:mimeType="image/*"/>
</intent-filter>
</receiver>

* 브로드케스트리시버 샘플
public class NewPhotoReceiver extends BroadcastReceiver
{
 @Override
 public void onReceive(Context context, Intent intent) {
  Log.d("Test", "START OF NewPhotoReceiver");
  
  Uri uri = intent.getData();
  
  Toast.makeText(context, "Photo taken - " + uri, Toast.LENGTH_SHORT).show();
  
  Log.d("Test", "[onReceive] URI - " + uri);
 }
}

[안드로이드] animation 리소스의 특정 프레임을 Bitmap으로 바꾸는 법

android.R.drawable.stat_sys_upload
이녀석은 움직이는 이미지다.
따라서 다음과 같이 하면 null값이 리턴되는데...
Resources res = ctx.getResources();
Bitmap bmpOneFrame = BitmapFactory.decodeResource(res, 
                                                android.R.drawable.stat_sys_upload);
그럼 움직이는 이미지의 특정 프레임을 Bitmap으로 얻어 오려면 어떻게 해야 할까?

1. 먼저 움직이는 이미지의 리소스 ID로 AnimationDrawable을 얻어 온다.
2. AnimationDrawabled의 특정 프레임을 Drawable로 얻어온다.
3. Drawable을 Bitmap으로 변환 한다.

이것을 코드로 나타내면,

public static Bitmap getFrameToBitmap(Context ctx, int resId, int nFrame)
{
    Resources res = ctx.getResources();     
    Bitmap bmpOneFrame = BitmapFactory.decodeResource(res, resId);
     
    if(bmpOneFrame == null)
    {
        AnimationDrawable ani = (AnimationDrawable)res.getDrawable(resId);
        Drawable drawableFrame = ani.getFrame(nFrame);
   
        bmpOneFrame = Bitmap.createBitmap(drawableFrame.getIntrinsicWidth(), 
                                          drawableFrame.getIntrinsicHeight(), 
                                          Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bmpOneFrame);
        drawableFrame.setBounds(0, 0, drawableFrame.getIntrinsicWidth(), 
                                      drawableFrame.getIntrinsicHeight());
        drawableFrame.draw(canvas);
    }
  
    return bmpFirstFrame;
}
참고로 리소스가 그냥 Drawable인 경우는 바로 Bitmap이 리턴된다.
또한 프레임 번호에 관련한 에러 처리는 없다 ^^;;

[안드로이드] ICS에서 Notification에 ProgressBar가 깨짐

ICS에서 RemoteView를 이용해 ProgressBar를 그리면 ProgressBar의 끝부분이 꺽여서 보기 흉해지는 경우가 있다.
원인은 잘모르겠으나 아마 ICS의 새로운  ProgressBar 는 (직접 그리는게 아니고)이미지로 되어 있기 때문인듯 한데...
그렇게 깨지는 경우 padding값이나 margin 값을 주어 ProgressBar의 위치를 조정해 주면된다.
상당히 꼴사나운 방법이지만 다른 방법은 찾지 못했다.
참고로 padding값이나 margin 값을 px가 아닌 dp로 줘야 한다.
요즘엔 폰마다 해상도가 천차 만별 -ㅁ-;;

아 그리고 ProgressBar의 스타일은 예전 버전처럼 주면 꺽이는 문제는 발생하지 않는다.
다만 촌스럽게 보일뿐 ^^;;
뭐 개인차겠지만;;
스타일에 Widget.ProgressBar.Horizontal 지정하여 사용 하시길...

[안드로이드] ICS에서 Notification RemoteView 사용하기

ICS에선 노티피케이션이 좀 멋있어 졌다.
좌측의 아이콘 화면이 노티피케이션 항목의 높이 만큼 커졌는데..
리모트 뷰를 사용 하던 기존 소스를 이용하면 새로운 노티피케이션과 어울리지않는 촌스러운 화면으로 보여 지게 된다.
그렇다고 RemoteView로 ICS스타일 처럼 똑같이 만들자니 쉽지가 않다.

자 그럼 왼쪽에 큰 아이콘을 유지 하면서 그 오른쪽에 RemoteView를 그리려면?
방법은 간단하다.
1. 먼저 기존의 RemoteView 의 레이아웃에서 아이콘을 제거 한다.
2. 좌측에 큰 아이콘을 넣을 것 이므로 그에 맞춰 레이아웃을 조정한다. 그럼 xml은 완성.
3. 다음으로 Notification을 만드는 코드에서 다음과 같이 largeIcon 값을 지정한다.
noti.largeIcon = BitmapFactory.decodeResource(res, resourceID);
    Notification.builder를 이용한다면 다음과 같이 지정 하면 된다.
notiBuilder.setLargeIcon(BitmapFactory.decodeResource(res, resourceID));
이렇게 하면 ICS에서도 이쁘게 보이는 Notification이 된다.