xml graphical layout가 정상적으로 동작하지 않을 때

 안드로이드 애플리케이션을 개발하던 도중 XML을 편집하고 graphicl layout을 확인한 순간 다음과 같은 메시지를 보게 되었습니다.



Exception raised during rendering:java.util.Locale.toLanguageTag()Ljava/lang/String;

Exception details are logged in Window > Show View > Error Log


이러한 경우 대개 2가지 경우로 보실 수 있습니다.

1.자신이 Target으로 한 버전의 SDK가 설치되어 있지 않아 Graphical Layout가 지원되지 않는 경우

2.다른 무언가에 의해 충돌이 될 경우


 거의 대부분의 경우가 1번의 경우가 많은 것으로 보입니다. 이를 해결하는 방법은 상당히 간단합니다. SDK Manager를 실행하여 자신의 프로젝트에 해당되는 프로젝트를 다운로드하여 설치하신 뒤 Eclipse를 다시 실행하시면 Graphical Layout가 정상적으로 동작하는 것을 확인해 보실 수 있습니다.



300x250

Kitkat 이후의 버전에서 SrufaceView를 활용하여 Camera 활용하기

안드로이드/카메라 2015. 2. 4. 00:57

 기존에 사용하던 Camera 애플리케이션 코드를 Kitkat에 적용해서 수행해보니 갑자기 애플리케이션이 종료되어버리는 일이 벌어지더군요.확인해 본 결과 해당 부분에 문제가 발생하여 벌어진 일이었습니다.


android.hardware.Camera.setParameters


 새로운 버전으로 바뀌게 되면서 설정되어 있던 해상도가 맞지 않는 경우 Error를 뿜어내는 듯 합니다. 이를 수정하여 애플리케이션 코드를 다시 구성해 보았습니다. 해당 코드는 Nexus5 KitKat 4.4.4에서 정상적으로 동작되는 것을 확인하였습니다.


 먼저 시작하기 전에 애플리케이션에 다음과 같은 권한을 추가하셔야 합니다.

1
2
3
4
    <uses-sdk
        android:minSdkVersion="19"
        android:targetSdkVersion="21" />
    <uses-permission android:name="android.permission.CAMERA"/>
cs



XML 레이아웃은 다음과 같이 구성해 줍니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation = "vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    tools:context=".MainActivity" >
 
    <SurfaceView
        android:id="@+id/surfaceView"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
    </SurfaceView>
 
</LinearLayout>
cs


끝으로 MainActivity 코드입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package com.example.kcamera;
 
import android.app.Activity;
import android.hardware.Camera;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;
 
import java.io.IOException;
 
public class MainActivity extends Activity {
    
    private SurfaceView surfaceView;
    private SurfaceHolder surfaceHolder;
    private Camera camera;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
        
        surfaceView = (SurfaceView)findViewById(R.id.surfaceView);
        
        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.addCallback(surfaceListener);
    }
    
    private SurfaceHolder.Callback surfaceListener = new SurfaceHolder.Callback() {
        
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            // TODO Auto-generated method stub
            camera.release();
            
        }
        
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            // TODO Auto-generated method stub
            camera = Camera.open();
            try {
                camera.setPreviewDisplay(holder);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
        }
        
        @Override
        public void surfaceChanged(SurfaceHolder holder, int formatint width, int height) {
            // TODO Auto-generated method stub
            Camera.Parameters parameters = camera.getParameters();
            parameters.setPreviewSize(width, height);
            camera.startPreview();
            
        }
    };
    
 
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
 
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}
 
 
 
 
cs


300x250

XML의 Graphical Layout이 보이지 않는 경우 해결법

 오랜만에 Linux에서 안드로이드 작업을 하려고 새로운 프로젝트를 생성한 후 작업을 하려 했더니 아래와 같은 에러가 발생하면서 아무런 화면도 뜨지 않는 현상이 발생하였습니다.



The rendering target (Android 5.0.1) is still loading.

The layout will refresh automatically once the process is finished.


 처음에는 다소 당황했었으나 차분히 원인을 분석해 본 결과 안드로이드 버전을 낮은 버전으로 설정하는 바람에 Graphical Layout가 해당 버전과 맞지 않아 위와 같은 에러가 발생하였더군요 해결 방법은 간단합니다.


1. 먼저 에러가 발생한 xml 파일을 끈 후 다시 엽니다.


2. Graphical Layout을 클릭한 후 xml 창의 왼쪽 위 부분을 자세히 보면 아래쪽 화살표 모양의 버튼이 보입니다 해당 버튼을 클릭하면 현재 설정된 버전의 번호가 보입니다 해당 버전의 번호를 클릭하면 설정할 수 있는 버전 명단이 뜨는데 그 중 자신의 프로젝트에 해당하는 버튼을 클릭합니다.



 위의 과정을 거치만 아래와 같이 Grahpical Layout가 정상적으로 출력 되는 것을 확인하실 수 있습니다.




300x250

안드로이드 프레임워크 프로그래밍(6) [Wi-Fi 접속 확인 Toast 만들기]

안드로이드/프레임워크 2015. 1. 30. 23:30

 최근 안드로이드 프레임워크 공부를 해보던 중 한 번 도전하고 싶었던 것이 있었습니다. 바로 갤럭시 S2에서 지원하던 Wi-Fi 접속 알림창이었습니다.


 ※갤럭시 S2 JellyBean 4.1에서의 모습입니다.

 위에서 보는 바와 같이 안드로이드 기기가 Wi-Fi에 접속하면 Framework를 통해 Toast가 이를 알려주는 모습을 보고 이를 Nexus 폰에도 적용해보자는 마음으로 도전하게 되었습니다.


※본 포스팅은 Nexus5 KitKat 4.4.4 환경에서 제작되었음을 알립니다.


1.  아래 굵은 표시로 추가된 소스코드를 안드로이드 소스에 추가합니다.

/frameworks/base/services/java/com/android/server/ConnectivityService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
        @Override
        public void handleMessage(Message msg) {
            NetworkInfo info;
            switch (msg.what) {
                case NetworkStateTracker.EVENT_STATE_CHANGED: {
                    info = (NetworkInfo) msg.obj;
                    NetworkInfo.State state = info.getState();
 
                    if (VDBG || (state == NetworkInfo.State.CONNECTED) ||
                            (state == NetworkInfo.State.DISCONNECTED) ||
                            (state == NetworkInfo.State.SUSPENDED)) {
                        log("ConnectivityChange for " +
                            info.getTypeName() + ": " +
                            state + "/" + info.getDetailedState());
        //APPEND
 
        if ( state == NetworkInfo.State.CONNECTED ){
            Toast.makeText(mContext, info.getExtraInfo().
                substring(1,info.getExtraInfo().length() - 1)
                + "에 연결되었습니다.", Toast.LENGTH_SHORT).show();
        }
 
        //END
                    }
 
                    // Since mobile has the notion of a network/apn that can be used for
                    // provisioning we need to check every time we're connected as
                    // CaptiveProtalTracker won't detected it because DCT doesn't report it
                    // as connected as ACTION_ANY_DATA_CONNECTION_STATE_CHANGED instead its
                    // reported as ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN. Which
                    // is received by MDST and sent here as EVENT_STATE_CHANGED.
                    if (ConnectivityManager.isNetworkTypeMobile(info.getType())
                            && (0 != Settings.Global.getInt(mContext.getContentResolver(),
                                        Settings.Global.DEVICE_PROVISIONED, 0))
                            && (((state == NetworkInfo.State.CONNECTED)
                                    && (info.getType() == ConnectivityManager.TYPE_MOBILE))
                                || info.isConnectedToProvisioningNetwork())) {
                        log("ConnectivityChange checkMobileProvisioning for"
                                + " TYPE_MOBILE or ProvisioningNetwork");
                        checkMobileProvisioning(CheckMp.MAX_TIMEOUT_MS);
                    }
    }
 
 
cs


2. 적용된 소스코드를 빌드하여 이미지를 새로 만듭니다.

$ make -j4


3. 안드로이드 기기에 이미지를 올린 후 동작을 확인합니다.




300x250

안드로이드 프레임워크 프로그래밍(5) [Toast 구현하기]

안드로이드/프레임워크 2015. 1. 25. 01:43

 지난 포스팅에서 새로 추가한 System service를 적용하여 Log를 통해 등록한 System service가 제대로 동작하는지에 대해 알아보았습니다. 이번에는 Framework 자체에서 Toast를 구현하는 작업을 해보도록 하겠습니다.


※본 포스팅은 지난 포스팅에서 사용하였던 예제를 수정하여 적용하였습니다. 그러므로 본 포스팅에서는 수정된 코드에 대해서만 다룰 것이며 상세한 코드는 이전 포스팅을 통해 확인해 주시기 바랍니다.


http://elecs.tistory.com/64


1. System service에 Toast 관련 소스를 입력합니다.

frameworks/base/services/java/com/android/server/TestService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package com.android.server;
import android.content.Context;
import android.os.Handler;
import android.os.ITestService;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.util.Log;
import android.widget.Toast;
public class TestService extends ITestService.Stub {
    private static final String TAG = "TestService";
    private TestWorkerThread mWorker;
    private TestWorkerHandler mHandler;
    private Context mContext;
    public TestService(Context context) {
        super();
        mContext = context;
        mWorker = new TestWorkerThread("TestServiceWorker");
        mWorker.start();
        Log.i(TAG, "Spawned worker thread");
    }
 
    public void setValue(int val) {
        Log.i(TAG, "setValue " + val);
        Message msg = Message.obtain();
        msg.what = TestWorkerHandler.MESSAGE_SET;
        msg.arg1 = val;
        mHandler.sendMessage(msg);
    }
 
    public void showToast(int val){
        Log.i(TAG, "showToast " + val);
        Message msg = Message.obtain();
        msg.what = 2;
        msg.arg1 = val;
        mHandler.sendMessage(msg);
    }
 
    private class TestWorkerThread extends Thread {
        public TestWorkerThread(String name) {
            super(name);
        }
        public void run() {
            Looper.prepare();
            mHandler = new TestWorkerHandler();
            Looper.loop();
        }
    }
 
    private class TestWorkerHandler extends Handler {
        private static final int MESSAGE_SET = 0;
        @Override
        public void handleMessage(Message msg) {
            try {
                if (msg.what == MESSAGE_SET) {
                    Log.i(TAG, "set message received: " + msg.arg1);
                }
        if (msg.what == 2){
            Log.i(TAG, "Show toast!!");
            Toast.makeText(mContext, "Toast message : "+msg.arg1, Toast.LENGTH_SHORT).show();
        }
        
            } catch (Exception e) {
                // Log, don't crash!
                Log.e(TAG, "Exception in TestWorkerHandler.handleMessage:", e);
            }
        }
    }
}
cs


2. AIDL 또한 변경된 System service 프로그램에 맟게 method를 추가합니다.

frameworks/base/core/java/android/os/ITestService.aidl

1
2
3
4
5
6
7
8
package android.os;
interface ITestService {
/**
* {@hide}
*/
    void setValue(int val);
    void showToast(int val);
}
cs



3. 여기까지 진행하셨다면 작성한 소스를 Build 해줍니다.

$ make -j4


4. 애플리케이션 프로젝트를 통해 Framework에서 Toast를 구현하는 프로그램을 작성합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package com.example.test;
 
import android.app.Activity;
import android.app.ActivityThread;
import android.os.Bundle;
import android.os.ITestService;
import android.os.ServiceManager;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import android.util.Log;
 
 
public class MainActivity extends Activity {
    private static final String DTAG = "HelloServer";
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        ITestService om = ITestService.Stub.asInterface(ServiceManager.getService("Test"));
        try{
            Log.d(DTAG, "Going to call service");
            om.setValue(20);
            om.showToast(30);
            Log.d(DTAG, "Service called successfully");
        }catch(Exception e){
            Log.d(DTAG, "FAILED to call service");
            e.printStackTrace();
        }
        
    }
 
 
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
 
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
 
}
cs



이제 어플리케이션을 실행하면 다음과 같은 결과를 확인하실 수 있습니다.





300x250

안드로이드 프레임워크 프로그래밍(4) [시스템서비스 추가하기]

안드로이드/프레임워크 2015. 1. 24. 04:13

 안드로이드 시스템 서비스란 운영체제가 동작하는 동안 수행할 수 있도록 구성된 어플리케이션 구성요소로 메시지 표시와 같이 시스템의 기본적인 기능들을 제공한다. 이러한 기능들을 활용하여 안드로이드 기기에서 동작하는 서비스를 개발하기 위한 클래스의 집합을 프레임워크라 한다. 본 포스팅은 이러한 시스템서비스를 추가하여 프레임워크의 동작 원리를 이해하는 것을 목표로 한다.


 다음은 서비스 레이어의 구조를 나타낸 것이다.

 


 상단의 Application에서 시스템서비스를 호출하면 해당 기능을 System Server에서 실행한다. 이 때 각 프로세스 간의 통신이 이루어져야 하는데 이는 IPC 또는 RPC 방식으로 이루어진다. Application과 System Server 사이에 있는 AIDL은 Application이 System Server로부터 해당 기능을 실행하는 프로세스를 호출할 수 있는 Interface를 제공하는 역할을 한다.


다음은 예제를 다루어 보도록 한다.


1. 시스템 서비스를 추가한다. 아래의 코드를 다음 경로에 생성한다.

frameworks/base/services/java/com/android/server/TestService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/*TestService.java */
package com.android.server;
import android.content.Context;
import android.os.Handler;
import android.os.ITestService;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.util.Log;
public class TestService extends ITestService.Stub {
    private static final String TAG = "TestService";
    private TestWorkerThread mWorker;
    private TestWorkerHandler mHandler;
    private Context mContext;
    public TestService(Context context) {
        super();
        mContext = context;
        mWorker = new TestWorkerThread("TestServiceWorker");
        mWorker.start();
        Log.i(TAG, "Spawned worker thread");
    }
 
    public void setValue(int val) {
        Log.i(TAG, "setValue " + val);
        Message msg = Message.obtain();
        msg.what = TestWorkerHandler.MESSAGE_SET;
        msg.arg1 = val;
        mHandler.sendMessage(msg);
    }
 
    private class TestWorkerThread extends Thread {
        public TestWorkerThread(String name) {
            super(name);
        }
        public void run() {
            Looper.prepare();
            mHandler = new TestWorkerHandler();
            Looper.loop();
        }
    }
 
    private class TestWorkerHandler extends Handler {
        private static final int MESSAGE_SET = 0;
        @Override
        public void handleMessage(Message msg) {
            try {
                if (msg.what == MESSAGE_SET) {
                    Log.i(TAG, "set message received: " + msg.arg1);
                }
            } catch (Exception e) {
                // Log, don't crash!
                Log.e(TAG, "Exception in TestWorkerHandler.handleMessage:", e);
            }
        }
    }
}
 
cs


2. 추가로 만든 서비스를 등록한다.

frameworks/base/services/java/com/android/server/SystemServer.java

아래 소스코드에서 굵게 표시된 부분을 소스에 추가해주면 되겠다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
 
......
 
    if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
        //Added code(363 line)
        try{
            Slog.i(TAG, "Test Service");
            ServiceManager.addService("Test"new TestService(context));
        } catch (Throwable e){
            Slog.e(TAG, "Failure starting TestService Service", e);
        }
 
            //if (!disableNonCoreServices) { // TODO: View depends on these; mock them?
            if (true) {
                try {
                    Slog.i(TAG, "Input Method Service");
                    imm = new InputMethodManagerService(context, wm);
                    ServiceManager.addService(Context.INPUT_METHOD_SERVICE, imm);
                } catch (Throwable e) {
                    reportWtf("starting Input Manager Service", e);
                }
 
                try {
                    Slog.i(TAG, "Accessibility Manager");
                    ServiceManager.addService(Context.ACCESSIBILITY_SERVICE,
                            new AccessibilityManagerService(context));
                } catch (Throwable e) {
                    reportWtf("starting Accessibility Manager", e);
                }
            }
        }
......
cs

3. aidl을 추가하여 애플리케이션에서 추가된 서비스에 접근할 수 있는 인터페이스를 만든다.

frameworks/base/core/java/android/os/ITestService.aidl

1
2
3
4
5
6
7
8
9
10
11
/*
* aidl file : frameworks/base/core/java/android/os/ITestService.aidl
* This file contains definitions of functions which are exposed by service
*/
package android.os;
interface ITestService {
/**
* {@hide}
*/
    void setValue(int val);
}
cs

4. 추가한 aidl 파일을 등록한다.

frameworks/base/Android.mk

1
2
3
4
5
6
7
8
/*
 * open frameworks/base/Android.mk and add following line
 */
......
core/java/android/os/IPowerManager.aidl \
core/java/android/os/ITestService.aidl \
core/java/android/os/IRemoteCallback.aidl \
......
cs


5. 변경사항을 적용하기 위해 소스코드를 Build 한다. 빌드 방법은 아래 블로그를 참조한다.

http://elecs.tistory.com/59


6. Build가 완료되면 새로 수정된 프레임워크 라이브러리를 추출한다. 라이브러리는 다음 경로에서 구할 수 있다.

out/target/common/obj/JAVA_LIBRARIES

자바 라이브러리들을 확인할 수 있다. 우리들이 새로 추가한 시스템 서비스는 framework_intermediate 폴더 내에 있다.


폴더 내에 classes.jar 파일이 있는데 이 안에 우리들이 만든 서비스가 들어있다. 이를 직접 확인해보면


class 파일이 내부에 있는 것을 확인할 수 있다. 이것이 안드로이드 기기 전원이 ON 상태인 동안 백그라운드에서 기기가 OFF될 때까지 계속 실행된다.


7. 이제 이를 활용한 애플리케이션을 제작해 보도록 하자. 새로운 프로젝트를 생성한 후 위에서 찾은 라이브러리를 추가한다.

Eclipse에서 Project -> Properties를 실행한다.


Java Build Path -> Libraries에 들어가면 현재 안드로이드 프로젝트 내에 있는 라이브러리들을 볼 수 있다. 위에서 확인하였던 라이브러리를 추가하기 위해 오른쪽 메뉴에 있는 "Add External JARs..."를 클릭한다.



해당 경로로 이동한 후 Classes.jar 파일을 선택한 후 확인 버튼을 누르면



위에서 보는 바와 같이 classes.jar이 추가된 것을 확인할 수 있다. OK버튼을 눌러 설정을 적용한다.


8. 이제 MainActivity.java에 추가된 서비스를 구동하는 기능을 넣어보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package com.example.test;
 
import android.app.Activity;
import android.os.Bundle;
import android.os.ITestService;
import android.os.ServiceManager;
import android.view.Menu;
import android.view.MenuItem;
import android.util.Log;
 
 
public class MainActivity extends Activity {
    private static final String DTAG = "HelloServer";
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        ITestService om = ITestService.Stub.asInterface(ServiceManager.getService("Test"));
        try{
            Log.d(DTAG, "Going to call service");
            om.setValue(20);
            Log.d(DTAG, "Service called successfully");
        }catch(Exception e){
            Log.d(DTAG, "FAILED to call service");
            e.printStackTrace();
        }
        
    }
 
 
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
 
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}
cs


9. 안드로이드 기기에 어플리케이션을 설치한 후 실행하면 LogCat에 다음과 같은 결과가 나타나는 것을 확인할 수 있다.




출저 : Android-Adding SystemService

http://processors.wiki.ti.com/index.php/Android-Adding_SystemService

300x250

리눅스로 Nexus 기기의 안드로이드 버전 다운그레이드 하기

안드로이드/프레임워크 2015. 1. 22. 19:52

 안드로이드 프레임워크에 대해 공부하게 되면서 안드로이드의 다양한 버전들을 기기에 설치하면서 동작시켜보는 일을 하고 있습니다. 지금 시점에서 가장 최신 버전인 Lollipop까지 실행을 해보면서 말이지요.

 물론 Lollipop를 사용한 프레임워크 작업도 참으로 할 만 하다고 생각합니다만 그래도 아직은 최신버전이다 보니 구글링을 해서 구할 수 있는 정보가 한정되어 있다 보니 바로 이전 버전인 Kitkat을 사용해서 작업을 해보기로 하였습니다. 그런데 여기서 문제가 발생하고 말았습니다.



 보시는 바와 같이 Lollipop에서 하위 버전인 Kitkat을 새로 설치해서 실행해보니 이렇게 로딩 화면만 주구장창 뜨기만 하고 다음 다음 화면으로 넘어갈 생각조차 하고 있지 않는 겁니다. 혹시나 해서 다시 이미지를 씌어서 입력해도 전혀 작동이 되지 않더군요. 이거 휴대폰 하나 날려먹는거 아닌가 하고 걱정했는데 다행히도 방법을 알아낼 수 있었습니다.


그렇다면 이제 안드로이드 버전의 다운그레이드 방법에 대해 살펴보도록 하겠습니다.


1. fastboot를 이용해 자신이 설치하고자 하는 버전의 이전 버전을 휴대폰에 설치합니다.

이 과정은 이전에 작성한 포스팅을 참고해 주시기 바랍니다.


http://elecs.tistory.com/59


위 링크에서 "fastboot flashall" 까지 진행하신 후 돌아오시면 되겠습니다.


2. fastboot 모드에서 Recovery Mode로 진입합니다.



fastboot 모드에 진입하신 후 휴대폰으 음량 버튼을 조작하시면 모드를 선택하실 수 있습니다.

자신이 원하는 모드를 선택하신 후 전원 버튼을 눌러 Recovery mode에 진입합니다.



 처음 진입하시면 다음과 같이 안드로이드가 배째고 있는 모습 위에 느낌표가 써진 붉은 삼각형만 덩그러니 보이실 겁니다. 여기서 당황하지 마시고 바로 음량 Up 버튼을 누르시면



 보시는 바와 같이 설정 메뉴들이 나타납니다.


 


 여기서 볼륨 Down 버튼을 눌러 "wipe data/factory reset"를 선택한 후 전원 버튼을 누릅니다.

 이제 기기가 스스로 공장 초기화에 들어간 후 리셋되는데 다시 다운그레이드된 버전이 정상적으로 동작하는 것을 확인하실 수 있을 겁니다.

300x250

error: neither -p product specified nor ANDROID_PRODUCT_OUT set

안드로이드/프레임워크 2015. 1. 21. 23:44

안드로이드를 빌드한 후 이를 안드로이드 기기에 적용하려 할 때 이러한 오류가 발생하는 경우가 있습니다.


# fastboot flashall
error: neither -p product specified nor ANDROID_PRODUCT_OUT set


이는 아직 root 의 bash 파일에 환경변수를 새로 적용하지 않을 경우 발생합니다. 따라서 root의 bashrc를 수정함으로서 이를 해결합니다.


# vi ~/.bashrc


다음으로 아래 내용을 추가합니다.



export ANDROID_TOOLS=안드로이드 소스코드가 설치된 폴더/out/host/linux-x86
export PATH=$ANDROID_TOOLS/bin:$JAVA_HOME/bin:$PATH
export ANDROID_PRODUCT_OUT=안드로이드 소스코드가 설치된 폴더/out/target/product/컴파일 형식(에뮬의 경우 generic)





안드로이드 컴파일 형식에 관해 알고 싶으신 분은 이전에 작성된 포스팅을 참고해 주시기 바랍니다.

http://elecs.tistory.com/59


위 과정까지 완료하셨다면 새로 수정한 bash를 적용한 후 실행해봅니다.

# source ~/.bashrc

# fastboot flashall


실행시 컴파일된 이미지가 안드로이드 기기에 적용되는 것을 확인하실 수 있습니다.

300x250

make: *** [out/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/classes.jar] error 41

안드로이드/프레임워크 2015. 1. 20. 00:58

안드로이드 코드를 빌드하던 도중 다음과 같은 오류를 맞닥트리는 경우가 있습니다.


Note: Some input files use or override a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
2 errors
6 warnings
make: *** [out/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/classes.jar] 오류 41
make: *** 끝나지 않은 작업을 기다리고 있습니다....


이 경우 자신의 컴퓨터 환경이 다음에 해당되는지 확인합니다.


1.자신이 Build 하는 JDK의 버전이 해당 안드로이드 버전에 맞는지 확인합니다.

(GingerBread에서 Kitkat 사이에 해당되는 버전은 JDK 6을, lollipop 이후의 버전은 JDK 7을 사용해야 합니다.)


2. 컴파일 옵션을 사용하였을 경우 컴파일 도중 오작동으로 인해 위와 같은 오류가 발생하는 경우가 있습니다. 이 경우 컴파일 시간이 느려지는 것을 감수하고 옵션 없이 컴파일을 수행합니다.


$ make


만약 다음 과정을 수행해도 같은 오류가 발생시 컴파일을 처음부터 다시 수행해야 합니다.


$ make clean

$ make

300x250

make: *** [out/target/common/obj/PACKAGING/checkapi-last-timestamp] error 38

안드로이드/프레임워크 2015. 1. 18. 02:16

 안드로이드 소스를 빌드하던 도중 다음과 같은 버그를 맞닥뜨리는 경우가 있습니다.


out/target/common/obj/PACKAGING/public_api.txt:23512: error 12: Class android.telephony.gsm.SmsManager changed static qualifier
prebuilts/sdk/api/19.txt:23496: error 9: Removed public method android.telephony.gsm.SmsManager.divideMessage
prebuilts/sdk/api/19.txt:23497: error 9: Removed public method android.telephony.gsm.SmsManager.getDefault
prebuilts/sdk/api/19.txt:23498: error 9: Removed public method android.telephony.gsm.SmsManager.sendDataMessage
prebuilts/sdk/api/19.txt:23499: error 9: Removed public method android.telephony.gsm.SmsManager.sendMultipartTextMessage
prebuilts/sdk/api/19.txt:23500: error 9: Removed public method android.telephony.gsm.SmsManager.sendTextMessage
prebuilts/sdk/api/19.txt:23501: error 10: Removed field android.telephony.gsm.SmsManager.RESULT_ERROR_GENERIC_FAILURE
prebuilts/sdk/api/19.txt:23502: error 10: Removed field android.telephony.gsm.SmsManager.RESULT_ERROR_NO_SERVICE
prebuilts/sdk/api/19.txt:23503: error 10: Removed field android.telephony.gsm.SmsManager.RESULT_ERROR_NULL_PDU
prebuilts/sdk/api/19.txt:23504: error 10: Removed field android.telephony.gsm.SmsManager.RESULT_ERROR_RADIO_OFF
prebuilts/sdk/api/19.txt:23505: error 10: Removed field android.telephony.gsm.SmsManager.STATUS_ON_SIM_FREE
prebuilts/sdk/api/19.txt:23506: error 10: Removed field android.telephony.gsm.SmsManager.STATUS_ON_SIM_READ
prebuilts/sdk/api/19.txt:23507: error 10: Removed field android.telephony.gsm.SmsManager.STATUS_ON_SIM_SENT
prebuilts/sdk/api/19.txt:23508: error 10: Removed field android.telephony.gsm.SmsManager.STATUS_ON_SIM_UNREAD
prebuilts/sdk/api/19.txt:23509: error 10: Removed field android.telephony.gsm.SmsManager.STATUS_ON_SIM_UNSENT

******************************
You have tried to change the API from what has been previously released in
an SDK.  Please fix the errors listed above.
******************************


make: *** [out/target/common/obj/PACKAGING/checkapi-last-timestamp] 오류 38
make: *** 끝나지 않은 작업을 기다리고 있습니다....
frameworks/base/api/current.txt:23496: error 9: Removed public method android.telephony.gsm.SmsManager.divideMessage
frameworks/base/api/current.txt:23497: error 9: Removed public method android.telephony.gsm.SmsManager.getDefault
frameworks/base/api/current.txt:23498: error 9: Removed public method android.telephony.gsm.SmsManager.sendDataMessage
frameworks/base/api/current.txt:23499: error 9: Removed public method android.telephony.gsm.SmsManager.sendMultipartTextMessage
frameworks/base/api/current.txt:23500: error 9: Removed public method android.telephony.gsm.SmsManager.sendTextMessage
frameworks/base/api/current.txt:23501: error 10: Removed field android.telephony.gsm.SmsManager.RESULT_ERROR_GENERIC_FAILURE
frameworks/base/api/current.txt:23502: error 10: Removed field android.telephony.gsm.SmsManager.RESULT_ERROR_NO_SERVICE
frameworks/base/api/current.txt:23503: error 10: Removed field android.telephony.gsm.SmsManager.RESULT_ERROR_NULL_PDU
frameworks/base/api/current.txt:23504: error 10: Removed field android.telephony.gsm.SmsManager.RESULT_ERROR_RADIO_OFF
frameworks/base/api/current.txt:23505: error 10: Removed field android.telephony.gsm.SmsManager.STATUS_ON_SIM_FREE
frameworks/base/api/current.txt:23506: error 10: Removed field android.telephony.gsm.SmsManager.STATUS_ON_SIM_READ
frameworks/base/api/current.txt:23507: error 10: Removed field android.telephony.gsm.SmsManager.STATUS_ON_SIM_SENT
frameworks/base/api/current.txt:23508: error 10: Removed field android.telephony.gsm.SmsManager.STATUS_ON_SIM_UNREAD
frameworks/base/api/current.txt:23509: error 10: Removed field android.telephony.gsm.SmsManager.STATUS_ON_SIM_UNSENT
out/target/common/obj/PACKAGING/public_api.txt:23512: error 12: Class android.telephony.gsm.SmsManager changed static qualifier
out/target/common/obj/PACKAGING/public_api.txt:23512: error 27: Class android.telephony.gsm.SmsManager removed final qualifier

******************************
You have tried to change the API from what has been previously approved.

To make these errors go away, you have two choices:
   1) You can add "@hide" javadoc comments to the methods, etc. listed in the
      errors above.

   2) You can update current.txt by executing the following command:
         make update-api

      To submit the revised current.txt to the main Android repository,
      you will need approval.
******************************


이는 다음과 같이 해결할 수 있습니다.


1. 특정 안드로이드 기기를 타겟으로 설정한 후 Build를 하실 경우 다음과 같이 멈추어버리는 경우가 있습니다. 이는 소스코드에 Binary와 Factory Image를 추가한 후 Build를 하여야 합니다. Binary와 Factory Image 추가법은 아래 블로그랠 참조해 주시기 바랍니다.

http://elecs.tistory.com/59


2. 다음과 같은 명령어를 입력합니다.


# make update-api

# make


※make 실행시 추가 옵선 (예를들어 -j4)을 걸고 Build를 하면 도중에 컴파일 오류를 뿜어내는 경우가 있습니다. 옵션 없이 make를 활용하시면 컴파일 시간은 늘어나지만 에러를 최대한으로 줄이실 수 있습니다.

300x250

안드로이드 프레임워크 프로그래밍(3) [NEXUS5에 소스 빌드하기]

안드로이드/프레임워크 2015. 1. 17. 23:45

 지난 포스팅에서 안드로이드 소스코드를 다운 받은 후 이를 컴파일하는 방법에 대해 알아보았습니다. 이번 포스팅에서는 소스코드를 직접 기기에 빌드하는 과정에 대해 알아보도록 하겠습니다. 작업 환경은 다음과 같습니다.


안드로이드 기기    : LG NEXUS5

빌드 버전               : Android 4.4.4(r2)

컴퓨터 운영체제    : Ubuntu 12.04(64비트)

JDK Version        : Oracle JDK 1.6


1. 자신의 안드로이드 기기에 빌드하고자 하는 안드로이드 소스코드를 다운로드 받습니다. 이 과정은 이전 포스팅을 통해 진행하실 수 있습니다.

http://elecs.tistory.com/56

본 포스팅에서 안드로이드 소스코드를 설치한 폴더는 아래와 같습니다.

~/kitkat


2. 다운로드가 완료되었다면 소스코드 빌드 환경을 초기화 합니다.

$ cd ~/kitkat

$ source build/envsetup.sh


3. 빌드 모드를 설정합니다.

$ lunch


 위에서 보시는 바와 같이 자신의 안드로이드 기기에 올리기 위한 빌드 종류를 선택해야 합니다. 다음 페이지를 참고하시면 자신의 기기에 맞는 종류를 확인하실 수 있습니다.

https://source.android.com/source/building-devices.html




 위의 사이트를 통하여 Nexus 5의 경우 aosp_hammerhead-userdebug를 사용함을 알 수 있습니다. 이를 설정하신 후 다음 단계로 넘어가시면 되겠습니다.


4. 다음으로 기기에 빌드를 하기 위해서는 해당 기기의 Binary와 Factory Image를 소스코드 폴더에 설치해야 합니다.


Binary 다운받기

https://developers.google.com/android/nexus/drivers



 자신의 기기에 해당되는 Binary를 모두 다운로드 받습니다.


Factory Image 다운받기

https://developers.google.com/android/nexus/images



 우리는 현재 4.4.4 r2를 사용하고 있으므로 해당 버전을 선택하여 다운로드 받습니다. 다운로드 받은 압축파일들의 압축을 모두 해제하신 후 해제된 파일들을 자신의 안드로이드 소스코드 폴더 상단에 다음과 같이 이동해 주시면 되겠습니다.



 5. 각 .sh 파일을 실행하여 파일을 설치합니다. 설치를 하기 위해서는 라이센스에 동의를 해야 하는데 이 과정이 살짝 골치 아픕니다.



 각 sh 파일을 실행하시면 보시는 바와 같이 라이센스 내용들이 출력됩니다. 이를 모두 읽고 동의한다만 하면 되겠지만 이 긴 글들을 일일히 읽기 귀찮아서 Enter 키를 계속 누르고 있으면 설치가 취소되는 비극(!)이 벌어집니다. 조금은 귀찮더라도 엔터키를 천천히 누르면서 동의 여부 확인이 나올 때까지 기다립니다.


동의문을 모두 읽게 되면 다음과 같이 동의 여부를 묻는 커맨드가 나옵니다. 여기서 무심코 Enter 버튼을 누르게 되면 처음부터 다시 해야 하므로 다음 커멘드가 나오면 잠시 동작을 멈춘 후 "I ACCEPT"를 입력합니다. 그러면 sh 파일이 설치되는 광경을 확인하실 수 있습니다. 다음과 같은 과정을 나머지 sh파일에서도 진행합니다.


6. 이제 빌드 조건은 모두 구축되었습니다. Make를 실행하여 본격적으로 Build 작업에 들어갑니다.


$ make update-api

$ make -j2


※make 진행시 상당히 많은 시간을 소모합니다. 만약 자신이 사용하고 있는 컴퓨터가 멀티코어를 지원할 경우 해당 코어의 갯수만큼의 옵션을 설정하시면 보다 빠르게 컴파일을 진행하실 수 있습니다. 만약 자신의 컴퓨터가 쿼드코어의 경우 다음과 같이 진행하실 수 있습니다.


$ make update-api

$ make -j4


※종종 위의 컴파일 옵션의 숫자를 너무 크게 하면 컴파일이 진행되는 도중 오류가 생기는 경우가 종종 발생합니다. 가장 안정적인 컴파일을 원하시는 분의 경우 어떠한 옵션을 설정하지 마시고 컴파일을 진행합니다.


컴파일을 무사히 끝마치실 경우 다음과 같은 화면을 보실 수 있습니다.




7. 이제 빌드한 소스코드를 안드로이드 기기에 적용해 보도록 하겠습니다. 우선 자신의 기기가 Fastboot 모드에 진입한 상태로 컴퓨터와 USB로 연결되어야 합니다. 자신이 가지고 있는 안드로이드 기기의 Fastboot 모드 진입 방법은 기기를 제공하는 회사의 웹사이트를 확인하시거나 검색 등을 통해 확인하실 수 있습니다. Nexus 5의 경우 왼쪽 음량조절 버튼의 아래버튼 + 전원버튼을 계속 누르고 있으면 Fastboot 모드에 진입하실 수 있습니다.



위에 붉은 네모로 표시한 부분을 누르시면 됩니다.

8. 위와 같은 화면이 나온다면 Fastboot 모드에 진입이 성공한 것입니다. 이제 다시 Ubuntu의 Terminal을 켜신 후 root 모드로 접근합니다.


$ su root


위의 커맨드를 입력하시면 root의 비밀번호를 묻습니다. 초기 비밀번호는 자신의 Ubuntu 로그인 아이디 혹은 0000으로 설정되어 있습니다. root 권한을 획득하셨다면 다음으로 bashrc를 수정합니다.


# vi ~/.bashrc


다음 내용을 추가합니다.


export ANDROID_TOOLS=(자신의 안드로이드 소스코드 폴더)/out/host/linux-x86
export PATH=$ANDROID_TOOLS/bin:$JAVA_HOME/bin:$PATH
export ANDROID_PRODUCT_OUT=(자신의 안드로이드 소스코드 폴더)/out/target/product/(자신의 빌드 환경)


:wq 를 입력하신 후 저장 합니다.


9. bashrc를 바로 적용합니다.


#source ~/.bashrc


10. 기기가 제대로 연결되었는지 확인합니다.


#fastboot devices



위에서 보시는 바와 같은 상황이 나온다면 안도르이드 기기가 성공적으로 연결된 것입니다. 이제 기기에 빌드를 시도해봅니다.


#fastboot oem unlock

#fastboot flashall



빌드가 완료된 안드로이드 기기의 휴대전화 정보를 확인하시면 다음과 같이 자신이 설정한 버전과 빌드 정보들을 직접 확인하실 수 있습니다.


여기까지 진행하셨다면 여러분은 드디어 안드로이드 빌드에 입문하신 겁니다!

지금까지 잘 따라오신 분들께 진심으로 축하드립니다!

중간에 에러로 인해 결과가 좋지 못하신 분들도 좀 더 자세히 들여다 보신다면 성공하실 수 있을 것입니다.




300x250

make: *** [out/target/product/generic/obj/SHARED_LIBRARIES/libwebviewchromium_intermediates/LINKED/libwebviewchromium.so] error 1

  안드로이드 커널을 다운로드한 후 열심히 빌드를 하다 보면 다음과 같은 문구가 발생합니다.


make: *** [out/target/product/generic/obj/SHARED_LIBRARIES/libwebviewchromium_intermediates/LINKED/libwebviewchromium.so] 오류 1


 이 현상은 거의 대부분이 빌드를 하는 컴퓨터의 메모리 구성에서 문제가 발생해서 생기는 것으로 보고 있습니다. 이를 해결하기 위해 다음과 같은 사항을 확인합니다.


 1. 메모리 용량이 얼마나 확보되어 있는지 확인합니다. 가상머신을 사용하시는 분의 경우 가상머신에 설정된 메모리 용량을 확인합니다.

 2. 우분투를 설치하였을 때 스왑 용량을 확인합니다. 대개 기본 설정으로 설치시 스왑 영역이 약 1~2기가 사이로 설정되어 있습니다. 이 경우 자신의 컴퓨터의 메모리가 4기가 이하의 경우 컴파일이 진행되던 도중 메모리 부족으로 프로세스가 멋대로 종료되어 버리는 경우가 발생합니다. 이를 해결하기 위해서는 처음 설치시 부터 스왑 영역을 최대한 확보하거나 설치 디스크로 부팅을 한 후 파티션을 조절하여 스왑영역을 확보합니다.


위 사항대로 수정한다면 오류 없이 컴파일이 되는 것을 확인하실 수 있습니다.


 You should have virtual memory less than 4GB. If you have the problem above, You should increase your memory size or linux-swap size.

300x250