2012년 4월 13일 금요일

안드로이드 라운드 테이블에 여러분을 초대합니다.


안드로이드 라운드테이블 행사에 여러분을 초대합니다.

안드로이드 라운드테이블 (Android Roundtable)은 안드로이드에 관심있는 개발자들이 모여서 서로의 관심사와 경험을 공유하는 자리입니다. 안드로이드 라운드 테이블은 모두가 참여하는 행사입니다. 라운드테이블에 앉아 자유롭게 경험을 공유하는 자리입니다.

함께 저녁 식사를 하고 자유롭게 이야기를 나누었으면 좋겠습니다.

일시: 2012년 4월 17일 오후 7시 ~ 9시 30분
장소: 구글코리아 21층 회의실

참석하신 분들에게는 구글 코리아가 마련한 식사와 소정의 선물이 있습니다.

참가신청은 4월 16일 오후 2시까지 받겠습니다.
참가자로 선정된 분들에게는 4월 16일까지 입력해주신 이메일로 연락드리겠습니다.
선착순이 아니기 때문에 급하게 신청하지 않으셔도 됩니다.
(단 4월 16일 2시까지 신청을 끝마쳐 주십시요.)


참여신청:
https://docs.google.com/spreadsheet/viewform?formkey=dHIxNjBJb0V5ZVRZOWxUUjJDaTNlc3c6MQ


PS: 구글 코리아가 장소와 식사 협찬을 해주셨습니다.

작업물을 공개한 리포지토리를 묻는 이유는 서로의 오픈소스 프로젝트를 소개하고 공유했으면 하는 바람에서 입니다. :)

PS: 마감 시간을 오후 2시까지로 바꾸어 죄송합니다. 4월 16일 밤까지 받는 경우에는 사실 상 당일 날에 스케쥴이 확정되어 불편함이 있다는 분들이 많아 변경하게 되었습니다. 양해 부탁드립니다.

2012년 3월 21일 수요일

렌더스크립트로 레벨 바꾸기

Levels in Renderscript | 2012년 1월 10일 오후 1시 43분에 팀 브레이(Tim Bray)가 작성.


[이 글은 그래픽, 성능 튜닝, 소프트웨어 아키텍쳐 전문인 안드로이드 프레임워크 엔지니어 R. 제이슨 샘스(R. Jason Sams)가 작성하였습니다. - 팀 브레이]

애플리케이션에 계산 가속(compute acceleration)을 추가하는 것을 단순화 하기 위해 ICS의 렌더스크립트(RS, Renderscript) 는 몇가지 특성을 개선했습니다. 중요한 처리를 해야할 대용량 데이터 버퍼가 있다면 렌더스크립트는 흥미롭습니다. 예를 들어 비트맵에 레벨(level)과 포화도(saturation)를 적용하겠습니다. (주: 렌더스크립트는 계산 용도와 그래픽 용도로 분리되며 계산 용도의 렌더스크립트 코드는 rsForEach를 이용하여 분산 수행할 수 있습니다. 이 글에서 계산 가속은 전자를 의미합니다.)

포화도의 경우는 매 픽셀에 대해 컬러 메트릭스를 곱해 구현합니다.

레벨은 보통 여러 연산으로 구현됩니다. (주: 컴퓨터 이미지는 디스플레이에 선형적인 밝기로 표현되지 못하기 때문에 밝기가 왜곡되어 있습니다. 이미지 처리에서 이를 보정하는 것을 감마 보정이라 합니다.)
  1. 입력 레벨이 조정됩니다.
  2. 감마 보정합니다.
  3. 출력 레벨이 조정됩니다.
  4. 유효 범위로 자릅니다.
아래는 단순화된 구현입니다.

for (int i=0; i < mInPixels.length; i++) {
    float r = (float)(mInPixels[i] & 0xff);
    float g = (float)((mInPixels[i] >> 8) & 0xff);
    float b = (float)((mInPixels[i] >> 16) & 0xff);

    float tr = r * m[0] + g * m[3] + b * m[6];
    float tg = r * m[1] + g * m[4] + b * m[7];
    float tb = r * m[2] + g * m[5] + b * m[8];
    r = tr;
    g = tg;
    b = tb;

    if (r < 0.f) r = 0.f;
    if (r > 255.f) r = 255.f;
    if (g < 0.f) g = 0.f;
    if (g > 255.f) g = 255.f;
    if (b < 0.f) b = 0.f;
    if (b > 255.f) b = 255.f;

    r = (r - mInBlack) * mOverInWMinInB;
    g = (g - mInBlack) * mOverInWMinInB;
    b = (b - mInBlack) * mOverInWMinInB;

    if (mGamma != 1.0f) {
        r = (float)java.lang.Math.pow(r, mGamma);
        g = (float)java.lang.Math.pow(g, mGamma);
        b = (float)java.lang.Math.pow(b, mGamma);
    }

    r = (r * mOutWMinOutB) + mOutBlack;
    g = (g * mOutWMinOutB) + mOutBlack;
    b = (b * mOutWMinOutB) + mOutBlack;

    if (r < 0.f) r = 0.f;
    if (r > 255.f) r = 255.f;
    if (g < 0.f) g = 0.f;
    if (g > 255.f) g = 255.f;
    if (b < 0.f) b = 0.f;
    if (b > 255.f) b = 255.f;

    mOutPixels[i] = ((int)r) + (((int)g) << 8) + (((int)b) << 16)
                    + (mInPixels[i] & 0xff000000);
}
이 코드는 비트맵이 적재되고 처리를 위해 정수 배열로 옮겨졌다고 가정합니다. 비트맵이 이미 읽어졌다고 가정하면 단순합니다.

        mInPixels = new int[mBitmapIn.getHeight() * mBitmapIn.getWidth()];
        mOutPixels = new int[mBitmapOut.getHeight() * mBitmapOut.getWidth()];
        mBitmapIn.getPixels(mInPixels, 0, mBitmapIn.getWidth(), 0, 0,
                            mBitmapIn.getWidth(), mBitmapIn.getHeight());
반복문에 의해 데이터가 한번 처리한 후 그리기 위해 비트맵으로 넣는 것은 간단합니다.

        mBitmapOut.setPixels(mOutPixels, 0, mBitmapOut.getWidth(), 0, 0,
                             mBitmapOut.getWidth(), mBitmapOut.getHeight());
필터 핵심부를 위한 상수, 제어의 조작, 이미지 표시를 포함한 애플리케이션의 전체 코드는 232 줄입니다. 800x423 이미지를 실제 기기에서 처리하는데 대략 140~180 밀리 초가 소요되었습니다.

꽤 빠르죠?

이 이미지 처리의 핵심을 렌더스크립트로 옮기는 것(android-renderscript-samples에 코드가 있습니다.)은 정말 쉽습니다. 위의 픽셀 처리 핵심을 렌더스크립트로 재구현하였습니다.

void root(const uchar4 *in, uchar4 *out, uint32_t x, uint32_t y) {
    float3 pixel = convert_float4(in[0]).rgb;
    pixel = rsMatrixMultiply(&colorMat, pixel);
    pixel = clamp(pixel, 0.f, 255.f);
    pixel = (pixel - inBlack) * overInWMinInB;
    if (gamma != 1.0f)
        pixel = pow(pixel, (float3)gamma);
    pixel = pixel * outWMinOutB + outBlack;
    pixel = clamp(pixel, 0.f, 255.f);
    out->xyz = convert_uchar3(pixel);
}

부동소수점 벡터에 대한 내장 지원, 매트릭스 연산, 포맷 변환 때문에 몇 줄의 코드로 됩니다. 게다가 반복문도 없습니다.

설정 코드는 스크립트를 불러야 하기 때문에 약간 더 복잡합니다.

        mRS = RenderScript.create(this);
        mInPixelsAllocation = Allocation.createFromBitmap(mRS, mBitmapIn,
                                                          Allocation.MipmapControl.MIPMAP_NONE,
                                                          Allocation.USAGE_SCRIPT);
        mOutPixelsAllocation = Allocation.createFromBitmap(mRS, mBitmapOut,
                                                           Allocation.MipmapControl.MIPMAP_NONE,
                                                           Allocation.USAGE_SCRIPT);
        mScript = new ScriptC_levels(mRS, getResources(), R.raw.levels);

이 코드는 렌드 스크립트 문맥을 만듭니다. 다음으로 이 문맥을 이용하여 비트맵 데이터의 렌더스크립트 복제본을 유지하기 위해 두 개의 메모리 할당을 만듭니다. 마지막으로 데이터를 처리하기 위해 스크립트를 읽습니다.

또 소스에서 값이 바뀌었을 때 스크립트로 계산 상수를 복사하기 위한 작은 코드 블록이 있습니다. 스크립트로 부터 전역적으로 반영하기 때문에 이 과정은 쉽습니다.

        mScript.set_inBlack(mInBlack);
        mScript.set_outBlack(mOutBlack);
        mScript.set_inWMinInB(mInWMinInB);
        mScript.set_outWMinOutB(mOutWMinOutB);
        mScript.set_overInWMinInB(mOverInWMinInB);

이전에 모든 픽셀을 처리하기 위해 루프가 필요없다는 점을 이야기했습니다. 비트맵 데이터를 처리하고 그 결과를 다시 복제하는 렌더스크립트 코드는 다음과 같습니다.

        mScript.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
        mOutPixelsAllocation.copyTo(mBitmapOut);

첫 줄은 스크립트를 이용하여 입력 할당을 처리하고 결과를 출력 할당에 넣는 것입니다. 이는 위에 나온 스크립트를 네이티브로 컴파일하여  할당의 모든 픽셀에 한번씩 호출합니다. 달빅 구현과는 다르게 기본으로 일을 처리하기 위한 여분의 스레드를 시작합니다. 네이티브 코드와 결합되어 큰 성능을 만듭니다. 감마 기능이 비용이 많이 들어서 그것을 넣은 결과와 넣지 않은 결과를 나누어 열거합니다.

800x423 image

DeviceDalvikRSGain
Xoom174ms39ms4.5x
Galaxy Nexus139ms30ms4.6x
Tegra 30 device136ms19ms7.2x

800x423 image with gamma correction

DeviceDalvikRSGain
Xoom994ms259ms3.8x
Galaxy Nexus787ms213ms3.7x
Tegra 30 device783ms104ms7.5x

위에 보인 간단한 코드를 투자해 큰 결과를 얻은 것을 볼 수 있습니다.

2012년 1월 11일 수요일

안드로이드 4.03 플랫폼과 갱신된 SDK 툴

[이 글은 안드로이드 SDK 테크 리드인 Xavier Durochet이 쓴 글입니다.](Android 4.0.3 Platform and Updated SDK tools의 번역입니다.)

오늘(12월 16일) 안드로이드 4.0.3을 공개했습니다. 4.0.3 버전은 안드로이드 4.0 (아이스크림 샌드위치) 플랫폼의 향상된 버전입니다. 이 릴리즈는 폰과 개발자를 위한 몇몇 새로운 API를 포함하였고, 폰과 타블렛을 위한 다양한 최적화와 버그 수정을 포함합니다. 새 API 레벨은 15입니다.

4.0.3에 새로 추가된 API들입니다.


  • 컨택트 프로바이더의 소셜 스트림 API: 소셜 스트림은 상태 갱신과 체크인 등입니다. 이제 소셜 스트림을 지원하는 애플리케이션은 사진까지 포함된 스트림 항목들을 각 사용자의 연락처 데이터에 동기화할 수 있습니다. 이 사용자 API가 적용된 앱은 사용자에게 사람들이 그들의 사진, 연락처 정보와 함께 무엇을 하고 어떤 말을 했는지 보여줍니다.
  • 캘린더 프로바이더 강화. 이벤트를 쉽게 추적할 수 있게 앱이 이벤트에 색상을 넣을 수 있고, 새로운 참석자 타입과 상태가 추가되었습니다.
  • 새로운 카메라 능력. 앱은 비디오 안정화를 측정하거나 관리할 수 있고, 필요하다면 QVGA 해상도 프로파일을 사용합니다.
  • 접근성 개량. 스크린 리더에 대한 컨텐츠 접근, TTS (Text-to-speech) 엔진을 위한 새로운 상태와 에러 보고를 향상시켰습니다.
  • 그래픽, 데이타베이스, 철자검사, 블루투스 등에서 점진적인 향상이 있었습니다.
플랫폼에서 새로워진 점의 전체적인 개요는 안드로이드 API 4.0.3 개요를 보세요.

더 나아가 우리는 우리의 파트너가 아이스크림 샌드위치의 기반 버전으로 안드로이드 4.0.3로 집중하도록 할 것입니다. 새로운 플랫폼은 수 주내에 폰과 타블렛으로 선보일겁니다. 가능한 빨리 안드로이드 4.0.3에서 애플리케이션을 시험할 수 있도록 강력히 격려하겠습니다.

그리고 최근에 릴리즈된 SDK 툴의 새버전 (r16)과 이클립스 플러그인 (ADT 16.0.1)도 환기드리고 싶습니다. NDK도 r7 버전으로 올렸습니다.

안드로이드 4.0.3과 다른 플랫폼 버전에 대한 더 많은 정보를 얻으려면 안드로이드 개발자 사이트로 방문하세요. 새 플랫폼을 개발하고 테스트하라면 안드로이드 SDK 관리자를 사용하여 새버전을 SDK에 받을 수 있습니다.

2012년 1월 9일 월요일

어디에서나 Holo

[스타일을 다루는 안드로이드 프레임워크 엔지니어 Adam Powell가 쓴 글입니다. -Tim Bray](이 글은 Holo Everywhere의 번역입니다.)

안드로이드 4.0에서 Holo 테마 패밀리를 소개했습니다. 안드로이드 3.0부터 소개된 Holo가 더 세련되어진 것입니다. 하지만 이전에는 몇몇 디바이스에선 시스템 테마가 Holo로 갱신되지  않았거나 일반적으로 쓸 수 없었습니다. 많은 개발자들이 이 점을 알고 있었죠. 시스템 테마를 쓰면 사용자가 기존에 원하던 대로 쓸 수 있고, 개발자가 개발 기간을 줄일 수 있는 이점이 있습니다. 이런 이점은 앱 개발자가 결과를 신뢰성 있게 예측할 수 있을 때 만 가능합니다. 안드로이드 4.0 이전에는 장비마다 시스템 테마가 차이났기에 예측 가능한 하나의 룩 앤 필을 가지는 앱을 만드는게 어려웠습니다. 우리는 개발자 커뮤니티를 위해 아이스크림샌드위치부터 이 상황을 개선하였습니다.

Theme.Holo
만약 안드로이드 스타일과 테마 시스템에 낯설다면 아래 글을 계속 보기 전에 스타일과 테마를 먼저 읽는 것을 추천합니다.


호환성 표준

안드로이드 4.0에서 Holo부터는 사정이 달라졌습니다. 구글은 Holo 테마 패밀리를 안드로이드 4.0 이상의 디바이스 호환성 요구사항으로 포함시켰습니다. 디바이스가 안드로이드 마켓을 탑재할려면 오리지날 Holo 테마를 그대로 포함해야 합니다.

표준화는 Holo 위젯 스타일 전체에도 해당됩니다. Widget.Holo 스타일은 모든 디바이스에서 안정화되기 때문에 여러 분의 앱에서 점진적인 수정용 부모 스타일로 안전하게 쓸 수 있습니다. (주: 안드로이드의 스타일도 부모로 부터 상속을 받을 수 있습니다.)

안드로이드 4.0의 Holo 테마 패밀리는 Theme.Holo, Theme.Holo.Light, Theme.Holo.Light.DarkActionBar를 포함합니다. 작동중인 테마들의 예는 이 글의 스크린 샷들에서 볼 수 있습니다.

Holo 테마를 사용하려면 메니페스트(manifest)나 애플리케이션 요소에서 하나를 명시적으로 지정합니다. (예: android:theme="@android:style/Theme.Holo".) 모든 안드로이드 4.0 호환 디바이스에서 변경없이 그대로 뜰 것입니다. Holo 테마는 앱에서 커스터마이징을 하기 위한 안정된 부모 테마입니다.
Theme.Holo.Light

디바이스 테마는 어때요?

우리는 제조사가 그들의 디바이스 전반에 자사의 테마로 사용자 경험을 만드는 것을 막을 생각은 없습니다. 사실은 우리는 제조사가 커스터마이징하기 더 쉽도록 더 나아간 것입니다. 안드로이드 4.0 API (레벨 14)에서 안드로이드 3.0에 소개된 Holo 패밀리를 보완할 새로운 공용 테마 패밀리, DeviceDefault 추가했습니다. DeviceDefault 테마는 디바이스의 고유의 룩 앤 필에 대한 별명입니다. DeviceDefault 테마 패밀리와 위젯 스타일 패밀리는 개발자로 하여금 온전한 디바이스 고유 테마를 선택할 수 있게 합니다.

공식적으로 이 테마들의 분리는 디바이스의 업데이트를 더 빠르게 만들고, 제조사가 추후에 새로운 플랫폼 버전을 통합하는 걸 쉽게 하는 것입니다. 구글 넥서스 디바이스들은 수정안된 Holo 테마를 DeviceDefault라고 별칭 붙였습니다.

선택한 테마를 사용하기

우리는 테마를 적용한 앱에 여러 공통 미터법과 색상 팔레트를 사용할 수 있도록 여러 테마 속성을 추가하였습니다. 리스트 아이템과 같은 UI  공통 요소에서 사용될 하이라이트 색상, 기본 패딩, 마진등의 속성을 포함하였습니다. (Holo와 DeviceDefault를 포함해서) 선택된 테마를 앱에 통합하기 위해 아래 예제처럼 테마 속성을 지정할 수 있습니다.

시스템 내장된 터치 하이라이트를 사용한 샘플 버튼

<ImageButton android:id="@+id/my_button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/button_icon"
    android:background="?android:attr/selectableItemBackground" />

시스템 테마의 값을 사용한 사용자 pressedHighLightColor 속성을 지닌 샘플 위젯

<MyWidget android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    myapp:pressedHighlightColor="?android:attr/colorPressedHighlight" />

시스템 제공된 미터법과 텍스트 외향을 사용한 열거 항목 배치 샘플

<LinearLayout android:layout_width="match_parent"
    android:layout_height="?android:attr/listPreferredItemHeight"
    android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
    android:paddingRight="?android:attr/listPreferredItemPaddingRight">
    <TextView android:id="@+id/text"
        android:textAppearance="?android:attr/textAppearanceListItem" />
    <!-- Other views here -->
</LinearLayout>

Theme.Holo.DarkActionBar
(API 레벨 14이상 가능)
옛날 앱을 위한 디폴트

만약 앱이 메니페스트에 명시적으로 테마를 정하지 않으면 안드로이드 4.0은 앱의 앱의 원래 기대치를 담고 있는 targetSdkVersion를 기초로 기본 테마를 결정합니다. 11보다 적으면 @android:style/Theme,11부터 13사이면 @android:style/Theme.Holo, 14 이상이면 @android:style/Theme.DeviceDefault입니다.

안드로이드 2.x을 지원하며 Holo 사용하기

기존 디바이스가 업데이트 되거나 새로운 디바이스가 출시될 동안 많은 안드로이드 개발자들은 2.x 버전 디바이스까지 지원하길 원합니다. 그렇다고 새로운 테마를 지원하는 디바이스에서 새로운 테마를 사용하는 이점을 포기할 수 없죠. 디바이스에 동작하는 플랫폼 버전에 기반해 자동으로 선택되는 테마를 안드로이드 리소스 시스템을 사용하여 만들 수 있습니다.

Theme.Holo와 Theme.Holo.Light는 API 레벨 11부터 사용가능하지만Theme.Holo.Light.DarkActionBar는 API 레벨 14에 추가되었습니다.

res/values/themes.xml

<resources>
    <style name="MyTheme" parent="@android:style/Theme">
        <!-- Any customizations for your app running on pre-3.0 devices here -->
    </style>
</resources>

res/values-v11/themes.xml

<resources>
    <style name="MyTheme" parent="@android:style/Theme.Holo">
        <!-- Any customizations for your app running on devices with Theme.Holo here -->
    </style>
</resources>

마지막으로 AndroidManifest.xml

<!-- [...] -->
    <application android:name="MyApplication"
            android:label="@string/application_label"
            android:icon="@drawable/app_icon"
            android:hardwareAccelerated="true"
            android:theme="@style/MyTheme">
<!-- [...] -->

이 아이디어가 맘에 든다면 당신의 리소스에 설정해 다른 값의 테마 속성을 만들 수 있습니다. 안드로이드 리소스 시스템에 대해 더 알고 싶으면 애플리케이션 리소스를 보세요.

끝으로

4.0 이상에서 동작하는 안드로이드 앱은 Holo 테마를 사용할 수 있습니다. 사용자 스킨을 가진 디바이스에서 앱을 돌릴 때에도 Holo의 룩 앤 필은 동일하게 보이는 것이 보장됩니다. 디바이스의 기본 스타일을 사용하고 싶은 앱은 이제 공개 API인 DeviceDefault 테마를 사용하면 됩니다. 이 변화는 어떤 디바이스에서 다른 디바이스로 갈 때의 걱정할 시간을 줄이고 더 많은 시간을 설계에 사용할 수 있게 합니다. 마지막으로 안드로이드 리소스 시스템은 오래된 디바이스를 위한 우아한 폴백을 제공하며 최신 플랫폼의 특성을 사용할 수 합니다. (주: 폴백은 새로운 기능이 동작하지 않은 구형 장비를 위해 대체 기능을 제공하는 것입니다.)