sqlite

Programming/안드로이드 2018.09.29 01:03 Posted by 파란크리스마스

출처

DBManager.java

package com.bluexmas.common;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class DBManager extends SQLiteOpenHelper {

    private static String TAG = DBManager.class.getName();

    // Database 버전
    public static final int DB_VERSION = 12;
    // Database 이름 (SQLite 파일명)
    public static final String DB_NAME = "bluexmas.db";

    // DBManager 객체 - 한번만 객체가 생성되도록 static 으로 변수 선언 : singleton 패턴
    private static DBManager instance = null;

    private Context context;

    // private 생성자 : singleton 패턴
    private DBManager(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
        this.context = context;
    }

    // DBManager 객체 반환 : singleton 패턴
    public static DBManager getInstance(Context context) {
        if (instance == null)
            instance = new DBManager(context);
        return instance;
    }

    public Context getContext() {
        return this.context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        // 테이블 생성 관련 SQL 스크립트 실행
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // DB_VERSION 버전이 올라 가면 변경될 SQL 스크립트 실행
    }
}

VideoEntity.java

package com.bluexmas.common;

public class VideoEntity {

    public static final String TABLE_NAME = "video_info";

    public static final String COLUMN_NAME_MEDIA_ID = "v_id";
    public static final String COLUMN_NAME_TYPECODE = "type_code";
    public static final String COLUMN_NAME_FILEPATH = "path";
    public static final String COLUMN_NAME_REGDATE = "regdate";

    public String getTableName() {
        return TABLE_NAME;
    }

    public String genCreateSQL() {
        return "CREATE TABLE "+this.getTableName()+"( "
                + COLUMN_NAME_MEDIA_ID+" INTEGER PRIMARY KEY AUTOINCREMENT, "
                + COLUMN_NAME_TYPECODE+" CHAR(2) NOT NULL, "
                + COLUMN_NAME_FILEPATH+" TEXT NOT NULL, "
                + COLUMN_NAME_REGDATE+" TEXT NOT NULL "
                + ");";
    }
}

DBManager.java

package com.bluexmas.common;

public class DBManager extends SQLiteOpenHelper {

    //
    private static String TAG = DBManager.class.getName();

    // Database 버전
    public static final int DB_VERSION = 12;
    // Database 이름 (SQLite 파일명)
    public static final String DB_NAME = "bluexmas.db";

    // DBManager 객체 - 한번만 객체가 생성되도록 static 으로 변수 선언 : singleton 패턴
    private static DBManager instance = null;

    private Context context;

    private VideoEntity videoEntity = null;

    // private 생성자 : singleton 패턴
    private DBManager(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
        this.context = context;

        // VideoEntity 생체 생성
        this.videoEntity = new VideoEntity();
    }

    // DBManager 객체 반환 : singleton 패턴
    public static DBManager getInstance(Context context) {
        if (instance == null)
            instance = new DBManager(context);
        return instance;
    }

    public Context getContext() {
        return context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        // 테이블 생성 관련 SQL 스크립트 실행

        // VideoEntity 테이블 생성
        db.execSQL(this.videoEntity.genCreateSQL());
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // DB_VERSION 버전이 올라 가면 변경될 SQL 스크립트 실행
    }

    // 비디오 정보 추가 (레코드 추가)
    public int addVideo(String type_code, String path) {
        if (path == null)
            return;

        // DB 객체 가져오기
        SQLiteDatabase db = this.getWritableDatabase();

        //
        ContentValues values = new ContentValues();
        values.put(this.videoEntity.COLUMN_NAME_TYPECODE, type_code);
        values.put(this.videoEntity.COLUMN_NAME_FILEPATH, path);
        values.put(this.videoEntity.COLUMN_NAME_REGDATE, "-");

        // 데이터 삽입
        long newRowId = db.insert(this.videoEntity.getTableName(), null, values);

        return getLastID(this.videoEntity.getTableName());
    }

    /**
     * 마지막 추가한 ID 구하기
     * @param table_name 테이블 이름
     * @return ID
     */
    public int getLastID(String table_name) {
        // DB 객체 가져오기
        SQLiteDatabase db = this.getWritableDatabase();

        final String query = "SELECT last_insert_rowid() FROM "+ table_name;
        Cursor cur = db.rawQuery(query, null);
        cur.moveToFirst();
        int last_id = cur.getInt(0);
        cur.close();
        return last_id;
    }
}



-

출처

안드로이드 부팅 이벤트 받기

BootReceiver,java - 부팅 이벤트를 받은 BroadcastReceiver를 상속받은 클래스 생성

package com.bluexmas.common;

import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
import android.util.Log;
import android.widget.Toast;

public class BootReceiver extends BroadcastReceiver {

    private final static String TAG = BootReceiver.class.getSimpleName();

    // BroadcastReceiver를 상속하여 처리 해줍니다.
    @Override
    public void onReceive(final Context context, Intent intent) {
        // TODO Auto-generated method stub
        // 전달 받은 Broadcast의 값을 가져오기
        // androidmanifest.xml에 정의한 인텐트 필터를 받아 올 수 있습니다.
        String action = intent.getAction();
        // 전달된 값이 '부팅완료' 인 경우에만 동작 하도록 조건문을 설정 해줍니다.
        if (action.equals("android.intent.action.BOOT_COMPLETED")) {
            // TODO
            // 부팅 이후 처리해야 코드 작성
            // Ex.서비스 호출, 특정 액티비티 호출등등
            Log.d(TAG, "action = " + action);

            //
            new Handler().postDelayed(new Runnable() {
                // 3초 후에 실행
                @Override public void run() {
                    //Toast.makeText(context, "-- BootReceiver.onReceive", Toast.LENGTH_LONG).show();

                    // BackgroundService
                    Intent serviceLauncher = new Intent(context, BackgroundService.class);
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                        context.startForegroundService(serviceLauncher);
                    } else {
                        context.startService(serviceLauncher);
                    }
                }
            }, 3000);
        }
    }

    public static boolean isServiceRunning(Context context, Class serviceClass) {
        ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
            if (serviceClass.getName().equals(service.service.getClassName())) {
                Log.i (TAG,"ServiceRunning? = "+true);
                return true;
            }
        }
        Log.i(TAG,"ServiceRunning? = "+ false);
        return false;
    }
}

AndroidManifest.xml 내용추가

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.bluexmas.main" >

    <!-- 안드로이드 부팅 이벤트 받기 권한 추가 -->
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

    <application
        android:name="com.bluexmas.main.BluexmasApplication"
        android:icon="@drawable/icon"
        android:label="@string/app_name"
        android:largeHeap="true">

        <!-- 안드로이드 부팅 이벤트 받기 : BroadcastReceiver -->
        <receiver
            android:name="com.bluexmas.common.BootReceiver"
            android:enabled="true"
            android:exported="false"
            android:label="BOOTReceiver">

            <intent-filter >
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
        </receiver>

앱이 종료 이후 백그라운드 서비스 실행 유지

서비스 생성

package com.bluexmas.common;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.os.SystemClock;
import android.util.Log;

import java.util.Timer;
import java.util.TimerTask;

public class BackgroundService extends Service {

    private final static String TAG = BackgroundService.class.getSimpleName();

    private Context context = null;
    public int counter=0;

    // 생성자1 : 반듯이 필요
    public BackgroundService() {
    }

    // 생성자2
    public BackgroundService(Context applicationContext) {
        super();
        context = applicationContext;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        // 서비스에서 가장 먼저 호출됨(최초에 한번만)
        Log.d(TAG, "BackgroundService.onCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);
        // 서비스가 호출될 때마다 실행
        Log.d(TAG, "BackgroundService.onStartCommand");
        //
        startTimer();
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // 서비스가 종료될 때 실행
        Log.d(TAG, "BackgroundService.onDestroy");
        //
        Intent broadcastIntent = new Intent("com.bluexmas.common.RestartService");
        sendBroadcast(broadcastIntent);
        stoptimertask();
    }

    private Timer timer;
    private TimerTask timerTask;
    long oldTime=0;
    public void startTimer() {
        //set a new Timer
        timer = new Timer();

        //initialize the TimerTask's job
        initializeTimerTask();

        //schedule the timer, to wake up every 1 second
        timer.schedule(timerTask, 1000, 1000); //
    }

    /**
     * it sets the timer to print the counter every x seconds
     */
    public void initializeTimerTask() {
        timerTask = new TimerTask() {
            public void run() {
                Log.i(TAG, "in timer ++++  "+ (counter++));
            }
        };
    }

    /**
     * not needed
     */
    public void stoptimertask() {
        //stop the timer, if it's not already null
        if (timer != null) {
            timer.cancel();
            timer = null;
        }
    }
}

AndroidManifest.xml 내용추가 - 서비스와 종료 이벤트를 받은 receiver 등록

        <!-- BackgroundService -->
        <service
            android:name="com.bluexmas.common.BackgroundService"
            android:enabled="true" >
        </service>

        <receiver
            android:name="com.bluexmas.common.RestarterBroadcastReceiver"
            android:enabled="true"
            android:exported="true"
            android:label="RestartServiceWhenStopped">
            <intent-filter>
                <action android:name="com.bluexmas.common.RestartService" />
            </intent-filter>
        </receiver>

    </application>

종료 이벤트를 받은 receiver 클래스 생성

package com.bluexmas.common;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

public class RestarterBroadcastReceiver extends BroadcastReceiver {

    private final static String TAG = RestarterBroadcastReceiver.class.getSimpleName();

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "RestarterBroadcastReceiver.onReceive");
        context.startService(new Intent(context, BackgroundService.class));
    }
}

MainActivity - 서비스가 실행하고 있지 않는 경우 서비스 실행

    // BackgroundService
    private Intent mBackgroundServiceIntent;
    private BackgroundService mBackgroundService;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // ... 생략 ...

        // BackgroundService
        mBackgroundService = new BackgroundService(getApplicationContext());
        mBackgroundServiceIntent = new Intent(getApplicationContext(), mBackgroundService.getClass());
        // 서비스가 실행 중인지 확인
        if (!BootReceiver.isServiceRunning(this, mBackgroundService.getClass())) {
            // 서비스가 실행하고 있지 않는 경우 서비스 실행
            startService(mBackgroundServiceIntent);
        }
    }

사용자가 강제로 서비스를 종료하더라도 자동으로 서비스를 다시 시작하기

AndroidManifest.xml 내용추가 - android:stopWithTask="false"로 설정해야 onTaskRemoved 메소드가 호출됨

        <!-- BackgroundService -->
        <service
            android:name="com.bluexmas.common.BackgroundService"
            android:enabled="true"
            android:stopWithTask="false">
        </service>

기존 BackgroundService 클래스에 onTaskRemoved 오버라이드 메소드 구현

    // 사용자가 강제로 서비스를 종료하더라도 자동으로 서비스를 다시 시작하는 방법은 무엇입니까?
    @Override
    public void onTaskRemoved(Intent rootIntent) {
        Log.d(TAG, "BackgroundService.onTaskRemoved");
        //create an intent that you want to start again.
        Intent intent = new Intent(getApplicationContext(), BackgroundService.class);
        PendingIntent pendingIntent = PendingIntent.getService(this, 1, intent, PendingIntent.FLAG_ONE_SHOT);
        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        alarmManager.set(AlarmManager.RTC_WAKEUP, SystemClock.elapsedRealtime() + 5000, pendingIntent);
        super.onTaskRemoved(rootIntent);
    }

[Android7.0] - 파일의 URI 정보 조회

Programming/안드로이드 2017.10.24 09:52 Posted by 파란크리스마스

출처 : Android 7.0 Nougat OS 이미지 사진 촬영 캡처 및 자르기(1/2) - 허접샴푸로그래밍

Android7.0 이전 에서는 Uri.fromFile 함수로 파일의 URI 정보를 얻을 수 있지만, Android7.0 이후 부터는 보안상 이슈로 아래와 같이 설정하고, FileProvider.getUriForFile 함수를 이용해서 URI 정보를 얻어야 합니다.

/xml/provider_paths.xml 생성

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="storage/emulated" path="."/>
</paths>

AndroidManifest.xml 내용 추가

	<provider
	   android:name="android.support.v4.content.FileProvider"
	   android:authorities="${applicationId}.provider"
	   android:exported="false"
	   android:grantUriPermissions="true">
	    <meta-data
	        android:name="android.support.FILE_PROVIDER_PATHS"
	        android:resource="@xml/provider_paths"/>
	</provider> 
	...
</application>

FileProvider.getUriForFile 사용

Uri photoUri = FileProvider.getUriForFile(
    getApplicationContext(), 
    getApplicationContext().getPackageName() + ".provider", 
    currentFile
);

Ubuntu 11.10 - PDK, NDK 설치

Programming/안드로이드 2013.09.27 11:18 Posted by 파란크리스마스

다운로드

http://old-releases.ubuntu.com/releases/oneiric/

NDK 다운로드

http://developer.android.com/tools/sdk/ndk/index.html

SSH 서버 설치
http://pirtaja.tistory.com/9

$ sudo apt-get install openssh-server
$ sudo /etc/init.d/ssh restart

jdk 1.6 설치 (Gingerbread and newer)
Installing Java6 JDK on Ubuntu 11.10

$ sudo add-apt-repository ppa:ferramroberto/java
$ sudo apt-get update
$ sudo apt-get install sun-java6-jdk sun-java6-plugin

.bashrc 내용 추가

# Java Setting
export JAVA_HOME=/usr/lib/jvm/java-6-sun
export ANDROID_JAVA_HOME=$JAVA_HOME

Android PDK 빌드 환경 구축 (64Bit OS)
http://source.android.com/source/initializing.html
[Android/안드로이드] Ubuntu에서 E: Package 'lib32readline5-dev' has no installation candidate. 발생시 대처 방법.

$ sudo apt-get install git-core gnupg flex bison gperf build-essential \
  zip curl zlib1g-dev libc6-dev lib32ncurses5-dev ia32-libs \
  x11proto-core-dev libx11-dev lib32readline-gplv2-dev lib32z-dev \
  libgl1-mesa-dev g++-multilib mingw32 tofrodos python-markdown \
  libxml2-utils xsltproc

Libx11-dev:i386 설치

$ sudo apt-get install libx11-dev:i386

repo 스크립트 다운로드
[Android/안드로이드] 64bit Ubuntu Android ICS Source 다운받기

$ mkdir ~/bin
$ PATH=~/bin:$PATH
$ curl https://dl-ssl.google.com/dl/googlesource/git-repo/repo > ~/bin/repo
$ chmod a+x ~/bin/repo

저장소 초기화

$ sudo mkdir /opt/android-source
$ cd /opt/android-source
$ sudo chown test:test .            <-- 옵션
$ repo init -u https://android.googlesource.com/platform/manifest
$ repo init -u https://android.googlesource.com/platform/manifest -b android-4.0.3_r1

소스 내려 받기

$ repo sync

안드로이드 소스 전체빌드
[안드로이드] 안드로이드 소스 전체빌드 해보기
안드로이드 빌드하기

안드로이드 소스 빌드

$ cd /opt/android-source
$ make

빌드 오류 해결법

android build error 해결법
ICS Source download
slang_rs_export_foreach.cpp , error : variable ‘ParamName’ set but not used
Ubuntu 11.10 ics build error

make: *** [out/host/linux-x86/obj/EXECUTABLES/obbtool_intermediates/Main.o] Error 1

$ vi build/core/combo/HOST_linux-x86.mk
#HOST_GLOBAL_CFLAGS += -D_FORTIFY_SOURCE=0
HOST_GLOBAL_CFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0

make: *** [out/host/linux-x86/obj/STATIC_LIBRARIES/libGLcommon_intermediates/GLDispatch.o] Error 1

$ sudo apt-get install mesa-common-dev

make: *** [out/host/linux-x86/obj/EXECUTABLES/llvm-rs-cc_intermediates/slang_rs_export_foreach.o] Error 1

$ vi frameworks/compile/slang/Android.mk
#local_cflags_for_slang := -Wno-sign-promo -Wall -Wno-unused-parameter -Werror
local_cflags_for_slang := -Wno-sign-promo -Wall -Wno-unused-parameter

make: *** [out/host/linux-x86/obj/STATIC_LIBRARIES/liboprofile_pp_intermediates/arrange_profiles.o] Error 1

external/oprofile/libpp/format_output.h 파일의 94번행

-   mutable counts_t & counts;
+   counts_t & counts;

make: *** [out/host/linux-x86/obj/EXECUTABLES/test-librsloader_intermediates/test-librsloader] Error 1

external/llvm/llvm-host-build.mk 내용 추가

+   LOCAL_LDLIBS := -lpthread -ldl

make: *** [out/host/linux-x86/obj/STATIC_LIBRARIES/libgtest_host_intermediates/gtest-all.o] Error 1

vi external/gtest/include/gtest/internal/gtest-param-util.h 내용추가

#include <cstddef>

make: *** [out/host/linux-x86/obj/STATIC_LIBRARIES/libMesa_intermediates/src/glsl/linker.o] Error 1

vi external/mesa3d/src/glsl/linker.cpp 내용추가

#include <stddef.h>

make: *** [out/host/linux-x86/obj/STATIC_LIBRARIES/libmtp_intermediates/MtpDevice.o] Error 1

vi frameworks/base/media/mtp/MtpDevice.cpp 수정

-   int fd = ::open(destPath, O_RDWR | O_CREAT | O_TRUNC);
+   int fd = ::open(destPath, O_RDWR | O_CREAT | O_TRUNC, 0777);

Android NDK(C/C++) 설치

http://developer.android.com/tools/sdk/ndk/index.html

$ sudo mv android-ndk-r9-linux-x86_64.tar.bz2 /opt
$ sudo tar xvf android-ndk-r9-linux-x86_64.tar.bz2

.profile-ndk 파일 작성

export ANDROID_NDK_ROOT=/opt/android-ndk-r9
export NDK_TOOLCHAIN_VERSION=4.6
export TOOLCHAIN=/opt/android-9-toolchain

export PATH=$TOOLCHAIN/bin:$PATH

.profile-ndk 실행 (NDK 빌드시 사용)

$ chmod a+x .profile-ndk 
$ source .profile-ndk

ToolChain 만들기

$ $ANDROID_NDK_ROOT/build/tools/make-standalone-toolchain.sh \
--toolchain=arm-linux-androideabi-4.6 \
--ndk-dir=$ANDROID_NDK_ROOT \
--install-dir=$TOOLCHAIN \
--platform=android-9
$ sudo chown test:test -hR /opt/android-9-toolchain

HttpCallUtils

Programming/안드로이드 2013.05.03 16:54 Posted by 파란크리스마스

출처 : android.os.NetworkOnMainThreadException 예외가 발생했을 경우
android.os.NetworkOnMainThreadException
http://aroundck.tistory.com/1240

사용예

        if(android.os.Build.VERSION.SDK_INT > 9) {
            StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
            StrictMode.setThreadPolicy(policy);
        }
        
        String test;
		try {
			test = HttpCallUtils.call("aaa", "bbb");
			System.out.println("test = " + test);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

HttpCallUtils

package com.test;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpParams;

public class HttpCallUtils {

	private static String url = "https://test.com/login_check.php";
	private static String key_user = "mb_id";
	private static String key_password = "mb_password";	
	
	/*
	public static void main(String[] args) throws Exception {
		String test = HttpCallUtils.call("aaa", "bbb");
		System.out.println("test = " + test);
	}
	*/
	
	public static String call(String parma1, String param2) throws Exception {
		
		HttpClient client = new DefaultHttpClient();
		HttpPost post = new HttpPost(url);

		HttpParams params = client.getParams();
		params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION,HttpVersion.HTTP_1_1);
		params.setParameter(CoreConnectionPNames.SO_TIMEOUT, new Integer(15000));
		params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, new Integer(15000));

		ArrayList<BasicNameValuePair> nameValuePairs = new ArrayList<BasicNameValuePair>();
		nameValuePairs.add(new BasicNameValuePair(key_user, parma1));
		nameValuePairs.add(new BasicNameValuePair(key_password, param2));
		UrlEncodedFormEntity entityRequest = new UrlEncodedFormEntity(nameValuePairs, "UTF-8");
		post.setEntity(entityRequest);
		
		//
		HttpResponse response = client.execute(post);
		
		StringBuffer sb = new StringBuffer();

		// Examine the response status
		System.out.println(response.getStatusLine());

		// Get hold of the response entity
		HttpEntity entity = response.getEntity();

		// If the response does not enclose an entity, there is no need
		// to worry about connection release
		if (entity != null) {
			InputStream instream = entity.getContent();
			try {
				BufferedReader reader = new BufferedReader(new InputStreamReader(instream));
				// do something useful with the response
				String line;
				while ((line = reader.readLine()) != null)
					sb.append(line+"\n");
			} catch (Exception ex) {
				ex.printStackTrace();
			} finally {
				instream.close();
			}
		}	
		return sb.toString();
	}	
}

 

Android NDK - openssl 컴파일 하기

Programming/안드로이드 2013.04.03 10:40 Posted by 파란크리스마스

출처 : 안드로이드 c/c++ 개발환경 구축

Mac 환경에서 make-standalone-toolchain.sh 로 toolchain 사용해서 openssl 컴파일 해보았습니다.

컴파일 버전

openssl-1.0.1e.tar.gz

환경

Makefile 수정

추가

CROSS  = $(TOOLCHAIN)/bin/arm-linux-androideabi-
INCDIR = $(TOOLCHAIN)/sysroot/usr/include
LIBDIR = $(TOOLCHAIN)/sysroot/usr/lib

수정

CC= $(CROSS)gcc
AR= $(CROSS)ar $(ARFLAGS) r
RANLIB= $(CROSS)ranlib
NM= $(CROSS)nm

결과

테스트

Makefile

Makefile

-----------------------

libjson 파일컴파일

추가

CROSS  = $(TOOLCHAIN)/bin/arm-linux-androideabi-
INCDIR = $(TOOLCHAIN)/sysroot/usr/include
LIBDIR = $(TOOLCHAIN)/sysroot/usr/lib

수정

# Variables
prefix          = $(TOOLCHAIN)/sysroot/usr
exec_prefix     = $(prefix)
libdir          = lib
includedir      = include
srcdir          = _internal/Source
CXX             = $(CROSS)c++
AR              = $(CROSS)ar
PIC             = PIC
BUILD_TYPE      = "default"

안드로이드 - 정적 라이브러리 NDK 빌드

Programming/안드로이드 2012.09.07 01:22 Posted by 파란크리스마스

이전 글에서 만든 정적 라이브러리를 이용해서 안드로이드 ndk 컴파일, 
안드로이드에서 실행해보는 것을 정리보았습니다.

testlibjni.h

#include <jni.h>

#ifndef _Included_com_example_testlib_TestLib
#define _Included_com_example_testlib_TestLib
#ifdef __cplusplus
extern "C" {
#endif

JNIEXPORT jstring JNICALL Java_com_example_testlib_TestLib_get_1version(JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

testlibjni.cpp

#include "testlib.h"
#include <jni.h>
#include "testlibjni.h"

JNIEXPORT jstring JNICALL Java_com_example_testlib_TestLib_get_1version(JNIEnv *env, jobject jobj)
{
    return env->NewStringUTF(get_version());
}

Android.mk

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := testlib
LOCAL_SRC_FILES := ../../testlib/src/testlib.cpp
LOCAL_C_INCLUDES := \
   /cygdrive/c/Android/workspaceCDT/testlib/inc \
   $(call include-path-for, graphics corecg)
include $(BUILD_STATIC_LIBRARY)

# JNI
include $(CLEAR_VARS)
LOCAL_MODULE    := testlibjni
LOCAL_SRC_FILES := testlibjni.cpp
LOCAL_STATIC_LIBRARIES := testlib
LOCAL_C_INCLUDES := \
   /cygdrive/c/Android/workspaceCDT/testlib/inc \
   $(call include-path-for, graphics corecg)
include $(BUILD_SHARED_LIBRARY)

Application.mk

APP_STL := stlport_static
STLPORT_FORCE_REBUILD := true 

ndk-build

 

안드로이드 프로젝트 생성 

TestLib.java

package com.example.testlib;

public class TestLib {
	static {
		System.loadLibrary("testlibjni");
	}
	
	public native static String get_version();
}

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:padding="@dimen/padding_medium"
        android:text="@string/hello_world"
        tools:context=".MainActivity" 
        android:id="@+id/edtTitle" />

</RelativeLayout>

MainActivity.java

package com.example.testlib_android;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.widget.TextView;

import com.example.testlib.TestLib;

public class MainActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        TextView edtTitle = (TextView) findViewById(R.id.edtTitle);
        edtTitle.setText(TestLib.get_version());
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }
    
}

실행결과

 

 

player

Programming/안드로이드 2012.09.03 01:05 Posted by 파란크리스마스

gplayer.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <!--
	<SurfaceView 
	    android:id="@+id/gplayer_surfaceview"
		android:layout_height="fill_parent" 
		android:layout_width="fill_parent">
	</SurfaceView>
	-->
	
    <com.grubin.main.GrubinVideoView
        android:id="@+id/gplayer_surfaceview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >
    </com.grubin.main.GrubinVideoView>

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:gravity="top"
        android:orientation="vertical" >

        <ImageButton
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/btnBack"
            style="@style/MediaButton.Back"
            android:layout_gravity="right"
            android:layout_margin="20dip" />

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_weight="1"
            android:orientation="vertical" />

        <LinearLayout
            android:id="@+id/layoutController"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical" />
    </LinearLayout>

</FrameLayout>

VideoController.java

package com.grubin.main;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.LinearLayout;

public class VideoController extends MediaController2 {

	private Button searchButton;
	
	private ImageButton mPushButton;
	
	private View.OnClickListener mPushListener;
	
	Context _context;

	private int screenWidth;

	private int screenHeight;
	
	public VideoController(Context context, boolean useFastForward, LinearLayout layout) {
		super(context, useFastForward, layout);
		_context = context;
	}
	
	public VideoController(Context context, AttributeSet attrs) {
		super(context, attrs);
		_context = context;
	}
	
	public VideoController(Context context, LinearLayout layout) {
		super(context, layout);
		_context = context;    
	}
	
	public void setScreenSize(int screenWidth, int screenHeight) {
		this.screenWidth = screenWidth;
		this.screenHeight = screenHeight;
	}

	@Override 
	 public void setAnchorView(View view) {
	     super.setAnchorView(view);
	     
	 		LinearLayout L1 = (LinearLayout) getChildAt(0);
			for (int i = 0; i < L1.getChildCount(); i++) {
				View v = L1.getChildAt(i);
				if (v instanceof LinearLayout) {
					LinearLayout buttons = (LinearLayout) v;
					buttons.addView(makePushButton(L1));
					break;
				}
			}
	     
	     /**
	      * 0 : 컨트롤러 전체
	      * 1 : 컨트롤 버튼
	      * 2 : 탐색 바
	      */
	     //this.getc
	     
	     /*
	     LinearLayout layout = (LinearLayout) getChildAt(0);
	     // LinearLayout button = (LinearLayout)layout.getChildAt(1);
	     // LinearLayout seek = (LinearLayout)layout.getChildAt(2);
	     
	     //view.getParent()
	     
	     LayoutInflater inf = (LayoutInflater) _context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
	     LinearLayout linear = (LinearLayout) inf.inflate(R.layout.gplayer_controller, null);
	     layout.addView(linear, 0);
	     */
	}


	/*
	@Override
	public void hide() {
	}
	*/
	
	
	/**
	 * Super ugly hack
	 */
	public void extend() {
		LinearLayout L1 = (LinearLayout) getChildAt(0);
		for (int i = 0; i < L1.getChildCount(); i++) {
			View v = L1.getChildAt(i);
			if (v instanceof LinearLayout) {
				LinearLayout buttons = (LinearLayout) v;
				buttons.addView(makePushButton(L1));
				break;
			}
		}
	}

	protected View makePushButton(ViewGroup parent) {
		LayoutInflater inflate = (LayoutInflater) LayoutInflater.from(_context);
		mPushButton = (ImageButton) inflate.inflate(R.layout.push_button, parent,	false);
		if (mPushListener != null)
			mPushButton.setOnClickListener(mPushListener);
		return mPushButton;
	}  

	public void setPushListener(View.OnClickListener push) {
		mPushListener = push;
		if (mPushButton != null) {
			mPushButton.setOnClickListener(mPushListener);
		}
	}
}

MainActivity.java

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.gplayer);
		
		//
		getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

		//
		surfaceView = (GrubinVideoView) findViewById(R.id.gplayer_surfaceview);
		surfaceHolder = surfaceView.getHolder();
		surfaceHolder.addCallback(this);
		surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

		mediaPlayer = new MediaPlayer();

		mediaPlayer.setOnCompletionListener(this);
		mediaPlayer.setOnErrorListener(this);
		mediaPlayer.setOnInfoListener(this);
		mediaPlayer.setOnPreparedListener(this);
		mediaPlayer.setOnSeekCompleteListener(this);
		mediaPlayer.setOnVideoSizeChangedListener(this);
		
		btnBack = (ImageButton) findViewById(R.id.btnBack);
		btnBack.setOnClickListener(new View.OnClickListener() { 
      public void onClick(View v) {
      	GPlayer.this.finish();
      } 
		});

		mediaController = (new VideoController(this, (LinearLayout)findViewById(R.id.layoutController)) {
			@Override 
	    public void hide() {
				btnBack.setVisibility(View.INVISIBLE);
				super.hide();
	    }
		});
		
		mediaController.setPushListener(new View.OnClickListener() { 
      public void onClick(View v) {
      	GPlayer.this.finish();
      } 
		});

		Intent intent = getIntent();
		playURI = intent.getStringExtra("url");
		try {
			mediaPlayer.setDataSource(playURI);
		} catch (IllegalArgumentException e) {
			Log.v(LOGTAG, e.getMessage());
			finish();
		} catch (IllegalStateException e) {
			Log.v(LOGTAG, e.getMessage());
			finish();
		} catch (IOException e) {
			Log.v(LOGTAG, e.getMessage());
			finish();
		}
		currentDisplay = getWindowManager().getDefaultDisplay();		
		
		
		//
		mediaController.setOnClickListener(new View.OnClickListener() { 
      public void onClick(View v) {
      	GPlayer.this.finish();
      } 
		});
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		
		Log.i("xxx", "onTouchEvent=" + ev.getAction());
		
		if(ev.getAction() == MotionEvent.ACTION_DOWN) {
			
			/*
			Toast.makeText(this, "ev.getX()="+ev.getX() + "/" + btnBack.getLeft(), Toast.LENGTH_SHORT).show();
			*/
			
			/*
			Toast.makeText(this, "btnBack.isShown()="+btnBack.isShown(), Toast.LENGTH_SHORT).show();
			if (btnBack.isShown()) {  // if (btnBack.getVisibility() == View.VISIBLE) {
				btnBack.setVisibility(View.INVISIBLE);
			} else {
				btnBack.setVisibility(View.VISIBLE);
			}	
			*/
			
			if (mediaController.isShowing()) {
				mediaController.hide();
				Log.v(LOGTAG, "mediaController.hide()");
			} else {
				try {
					btnBack.setVisibility(View.VISIBLE);
					mediaController.show(10000);
				} catch (Exception e) {
					Log.e(LOGTAG,e.toString(),e);
				}
				Log.v(LOGTAG, "mediaController.show()");
			}
		}
		return false;
	}	

출처 : Android NDK FFmpeg 컴파일 강좌 (1/4)
Android NDK FFmpeg 컴파일 강좌 (4/4)
Android NDK FFmpeg 컴파일 강좌 (3/4)
Android NDK FFmpeg 컴파일 강좌 (2/4)
Android NDK FFmpeg 컴파일 강좌 (새로운 시도)
http://blog.daum.net/hopefullife/209
Android NDK Overview
Android NDK 빌드환경을 사용하지 않는 Makefile
Decoding audio via Android using FFMpeg
OpenMAX AL for ffmpeg
live-converter
read-only stream buffer interface in ffmpeg #1
FFmpeg port for Android ndk
android-ndk-r7 编译 ffmpeg-0.10
Android AudioRecord to FFMPEG encode native AAC
http://www.2cto.com/kf/201201/116171.html
http://pastebin.com/P02Fmw53
AndroidCompile

안드로이드펍에서 남은그루터기, 로봇시대 글을 보고, 컴파일 해보았는데, 작업해야될 부분이 많았어서,
인터넷에서 여러가지 글을 찾아보고, 간단하게 할 수 있는 방법을 찾아 보았습니다.

일주일 동안의 고생한 내용을 정리합니다. 안드로이드펍의 남은그루터기님과, 로봇시대님에게 감사한마음 글로나마 드립니다.

toolchain을 /opt/android-8-toolchain 설치하고, ffmpeg 폴더에 config.sh 파일을 아래와 같이 만들었습니다.
C 드라이브에 ffmpegtmp 폴더를 만들고, 남은그루터기님 처럼 configure 파일은 수정하지 않았습니다.

그리고, 남은그루터기님의 소스를 받아서 rtsp 주소로 실행하면 "Open Movie Error: -2" 라고 나오는데,
지원이 안되는 것으로 알고 있었는데, 프로젝트의 AndroidManifest.xml 파일에 인터넷 접근 권한을 추가 해야  되더군요.
2일이나 고생해서 찾았습니다.

config.sh 파일

export TMPDIR=c:/ffmpegtmp
export ANDROID_ROOT=/opt/android-8-toolchain

./configure --target-os=linux \
--arch=arm \
--enable-cross-compile \
--cc=$ANDROID_ROOT/bin/arm-linux-androideabi-gcc \
--cross-prefix=$ANDROID_ROOT/bin/arm-linux-androideabi- \
--extra-cflags="-marm -march=armv7-a -mfloat-abi=softfp -mfpu=neon" \
--extra-ldflags="-Wl,--fix-cortex-a8" \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-avdevice \
--disable-devices \
--disable-filters \
--disable-yasm \
--enable-network \
--enable-protocol=tcp \
--enable-demuxer=rtsp \
--enable-decoder=h264

남은그루터기님은 각라이브러리 폴더에 Android.mk을 만드셨지만,
config.sh 파일은 만들고 ./config.sh 실행하고 make 컴파일 실행하면,
각 라이브러리 폴더에 .a 파일로 파일이 생성됩니다.
jni 컴파일 할때도 이 라이브러리 파일만 참조 하시면 됩니다.

CPU별 --extra-cflags 추가 플래그

arm v6
    -marm -march=armv6

arm v7vfpv3
    -mfloat-abi=softfp -mfpu=vfpv3-d16 -marm -march=armv7-a

arm v7vfp
    -mfloat-abi=softfp -mfpu=vfp -marm -march=armv7-a

arm v7n
    -mfloat-abi=softfp -mfpu=neon -marm -march=armv7-a -mtune=cortex-a8

arm v6+vfp
    -DCMP_HAVE_VFP -mfloat-abi=softfp -mfpu=vfp -marm -march=armv6

컴파일

$ ./config.sh

$ make

BasicPlayer.c 수정 - 남은그루터기 소스 원본의 내용 일부

#include "avcodec.h"
#include "avformat.h"
#include "swscale.h"

수정된 소스

#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"

Application.mk

APP_ABI := armeabi armeabi-v7a
APP_PLATFORM := android-8

Android.mk

# 참조
#      http://berabue.tistory.com/67
#      http://www.newsmth.net/bbsanc.php?path=%2Fgroups%2Fcomp.faq%2FMobileDev%2Fandroid%2FM.1315568907.n0&ap=275

# 컴파일하고자 하는 소스파일 위치를 알려줍니다. Android.mk를 jni에 놔두었으니 프로젝트/jni폴더가 됩니다.
LOCAL_PATH := $(call my-dir)

FFMPEGDIR := D:/Windows/cygwin/home/bluesanta/BluePlayer/jni/ffmpeg

# LOCAL로 시작하는것들을 초기화시킨다고합니다. LOCAL_PATH는 제외.
include $(CLEAR_VARS)

LOCAL_C_INCLUDES := $(FFMPEGDIR)

# List 'cpufeatures' in your list of static library dependencies
LOCAL_STATIC_LIBRARIES := cpufeatures

# 생성될 so파일명입니다.
LOCAL_MODULE    := libbasicplayer

# 컴파일할 소스파일을 추가합니다.  
LOCAL_SRC_FILES := Interface.c BasicPlayer.c

LDFFMPEG = -L$(FFMPEGDIR)/libavformat -L$(FFMPEGDIR)/libavcodec -L$(FFMPEGDIR)/libavutil -L$(FFMPEGDIR)/libswscale
LOCAL_LDLIBS    := $(LDFFMPEG) -lavformat -lswscale -lavcodec -lavutil -lz -lm -llog -ljnigraphics

# 공유 라이브러리를 생성합니다.
include $(BUILD_SHARED_LIBRARY)

# At the end of your Android.mk, import the 'android/cpufeatures'
$(call import-module,android/cpufeatures)

컴파일

$ ndk-build

Android NDK - toolchain 사용 컴파일

Programming/안드로이드 2012.05.24 15:17 Posted by 파란크리스마스

출처 : http://stackoverflow.com/questions/9251747/record-rtsp-stream-with-ffmpeg-libavformat
http://limga.tistory.com/3
http://kaludin.egloos.com/2651893
http://dranger.com/ffmpeg/tutorial01.html
http://dc.csie.ntut.edu.tw/files/DC006lab.pdf
http://www.cantgetnosleep.com/wordpress/?p=111

main.c 파일

#include <stdio.h>

int main(int argc, char* argv[])
{
	printf("Hello Android NDK! \n");	

	return 0;
}

Makefile 파일

TARGET = hello

TOOLCHAIN = D:/Windows/cygwin/opt/android-8-toolchain

CROSS  = $(TOOLCHAIN)/bin/arm-linux-androideabi-
INCDIR = $(TOOLCHAIN)/sysroot/usr/include
LIBDIR = $(TOOLCHAIN)/sysroot/usr/lib

CC 	= $(CROSS)gcc
AR 	= $(CROSS)ar
LD 	= $(CROSS)ld
NM 	= $(CROSS)nm
RANLIB 	= $(CROSS)ranlib
STRIP = $(CROSS)strip

INCLUDE = -I. -I$(INCDIR) 

CFLAGS = -Wall
LDFLAGS = -nostdlib -Wl,--dynamic-linker,"//system/bin/linker" -L$(LIBDIR) -lc -lm -lstdc++ -ldl
#LDFLAGS = -static -lc -lm -lstdc++

# crt 
CRTOBJ = $(LIBDIR)/crtbegin_dynamic.o

# application file
APPSOURCES = main.c
APPOBJS = $(APPSOURCES:.c=.o)

# define the rule
.SUFFIXES:.c .o 

.c.o:
	@echo Compiling: $< 
	$(CC) -c $(CFLAGS)  $(INCLUDE) -o $@ $<

all: app

app: $(APPOBJS)
	@echo Linking: $(TARGET) 
	$(CC) -o $(TARGET) $(APPOBJS) $(CRTOBJ) $(LDFLAGS)
	$(STRIP) -s $(TARGET)

clean:
	@rm -vf $(APPOBJS) $(TARGET) 
	

테스트

 

Android - 일본어 TTS 설치 (SVOX 사용)

Programming/안드로이드 2011.07.04 14:15 Posted by 파란크리스마스
Android 에서 일본어 출력을 위해서 두가지 앱이 설치되어 합니다.

1. Classis Text To Speech - 무료
2. SVOX 일어 언어팩 - 2.99$

설치방법

1. 마켓에서 svox로 검색합니다.

2. 검색된 목록에서 Classis Text To Speech를 선택해서 설치합니다.


3. 다시 1번에서 검색목록에서 SVOX Japanese/日本을 선택해서 설치하십니다.


위에 2개의 앱을 설치 하셨다면 이제 환경 설정에서 TTS 엔진을 변경 하셔야 합니다.

환경설정

1. 환경설정에 들어 가셔서 음성 입력 & 출력을 선택합니다.


3. TTS(text-to-speech) 설정을 선택합니다.


4. SVOX Classic TTS의 체크 박스를 선택합니다.



5. 기본 엔진를 선택합니다.


6. 기본 엔진 목록에서 SVOX Classic TTS을 선택하시면 됩니다.



 

 

Android - OpenCV

Programming/안드로이드 2011.06.27 01:25 Posted by 파란크리스마스
출처 : http://sotddi.tistory.com/tag/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C%20opencv
http://triumphlsh.springnote.com/pages/6620993

1. cygwin 설치

Devel 확장 시킨후 gcc-core, gcc++, make, swig 를 선택하여 설치 한다.





2. Android NDK 설치

다운로드 : http://www.crystax.net/android/ndk-r4.php#download

C:\cygwin\home\[로그인계정] 폴더에
NDK파일(android-ndk-r4-windows-crystax-4.zip)을 다운받아서 압축을 푼다.


3. svn 클라이언트을 이용해서 opencv 파일을 내려받는다.

svn checkout http://android-opencv.googlecode.com/svn/trunk/


4. 빌드 환경 설정

C:\cygwin\home\[로그인계정]\.bashrc 파일 편집

export PATH=$PATH:/home/[로그인계정]/android-ndk-r4-crystax
export ANDROID_NDK_ROOT=/home/[로그인계정]/android-ndk-r4-crystax

 


5. opencv 컴파일