2013년 7월 18일 목요일

[Android] (구 v1) GoogleMap API 사용전 설정해야 하는 부분

*중요:구글에서 제공하는 구글맵 등을 사용하려면 아래와같은 절차를 거처서 설정하시면 됩니다.

1. 구글 API 설치

-eclipse에서 구글 API 패키지를 설치하려면 이클립스의 [Window]->[Android SDK Manager] 메뉴를 클릭하면 위 아래와같은 창이 뜬다.

-여기에서 자기가 하고싶은 안드로이드 버전에 Google APIs 체크후 설치하면 된다.

2. 에뮬레이터 추가

제작된 프로젝트는 실행, 디버그, 프로파일링 및 테스트할 수 있어야 합니다. Android 에뮬레이터에서 지도 기반 애플리케이션을 실행하려면 Google API 애드온을 사용하도록 구성된 AVD(Android Virtual Device)를 설정해야 합니다. AVD를 설정하려면 Android AVD Manager를 사용합니다.

옵션 없이 android 명령을 사용하여 AVD Manager를 시작합니다. Eclipse/ADT에서 개발하는 경우에는 Window > Android SDK 및 AVD Manager에서 이 도구에 액세스 할 수도 있습니다.

- 새 AVD를 만들려면 '새로 만들기' 버튼을 클릭합니다.

- 대화상자가 표시되면 AVD의 이름을 지정하고 AVD에서 사용할 시스템 이미지 대상을 선택합니다. 'Google API(Google Inc.)' 타겟 중 하나를 선택하여 위에서 설명한 것처럼 API 수준이 애플리케이션의 매니페스트에서 선언된 android:minSdkVersion 특성과 일치하는 버전을 선택해야 합니다.

- 기타 옵션을 구성한 다음 'AVD 만들기'를 클릭합니다.

- AVD 만들기가 완료되면 AVD Manager UI에서 AVD를 실행하거나 에뮬레이터의 명령줄 인터페이스를 사용할 수 있습니다. Eclipse에서 개발하는 경우 AVD를 시작하도록 실행 구성을 설정하고 애플리케이션을 AVD에 설치할 수 있습니다.




3-1. 구글맵 API key 발급 받기(1)

3-1.1 디버그 서명 증명서의 MD5인증서 지문의 확인

- 디버그 서명 증명서 (debug.keystore 파일)는 Android SDK가 장동으로 생성
- 디버그 서명 증명서 (OS) 에 따라 생성되는 경로가 다르다.


3-1.2 Console 에서 OS 버전에 맞는 debug.keystore가 있는 경로로 이동한다.

3-1.3 명령어를 입력해준다

- 명령어: keytool -list -alias androiddebugkey -keystore debug.keystore -storepass android -keypass android -v
- JDK 7 부터는 기본값으로 SHA1 인증서 지문이 출력, 그래서 꼭 -v 옵션을 넣어야한다.
- JDK 6 에서는 MD5 인증서 지문이 기본값
- MD5 인증서 지문 저장


3-2. 구글맵 API key 발급 받기(2)

3-2.1 Google Map Service 에 접속해서 key 발급 요청

- 구글맵 API 키 얻는 URL: http://code.google.com/intl/ko/android/maps-api-signup.html
- Android Maps API key 사용에 관한 조건에 동의하고 위단계에서 얻은 MD5 인증서 지문을 입력란에 입력한다.

3-2.2 Android Maps API key 확인

[Android] GPS를 이용해 현재 위치 지도에서 보여주기(심화)

1. 사전 준비과정 및 지식

1.1 맵뷰와 맵액티비티

- 애플리케이션에 지도를 넣기 위해서는 화면 영역을 할당 받을 수 있도록 맵뷰(MapView)사용한다.
- 맵뷰를 사용할 때는 맵액티비티(MapActivity)를 같이 사용한다.

1.2 지도 API 키

- 구글맵을 사용할 때는 지도 API키를 발급받아 등록해야 구글서버에서 지도 데이터를 받을 수 있다.
- 지도키 받는 절차 링크 : http://ilililililililililili.blogspot.kr/2013/07/android-googlemap-api.html

1.3 구글 라이브러리의 사용

- 구글맵은 Google API가 포함된 플랫폼으로 에뮬레이터를 실행해야 한다.

1.4 매니페스트 수정

-지도를 추가하게 되면 크게 두 가지 권한(인터넷 접속 권한, GPS 위치정보 확인 권한)이 필요하다.
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
-구글 라이브러리를 사용할때는 application 태그 안에 아래와같은 태그를 넣어주어야한다
    <uses-library android:name="com.google.android.maps"/>

1.5 레이아웃에 맵뷰 추가하기

-xml 코드
    <com.google.android.maps.MapView
        android:id="@+id/mapview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_above="@+id/scrollview"
        android:layout_below="@+id/button01"
        android:clickable="true"
        android:apikey="xxx" />
2. 예제
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;

public class MyLocationMapActivity extends MapActivity {

 TextView text01;
 LocationManager manager;
 MapView mapview;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  
  text01 = (TextView) findViewById(R.id.text01);
  mapview = (MapView) findViewById(R.id.mapview);
  
  // 줌인 줌아웃 버튼이 나오게 하는 설정
  mapview.setBuiltInZoomControls(true);
  
  Button button01 = (Button) findViewById(R.id.button01);
  button01.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View v) {
    // LocationManager 객체 초기화 , LocationListener 리스너 설정
    getMyLocation();
   }
  });
  

 }

 // LocationManager 객체 초기화 , LocationListener 리스너 설정
 private void getMyLocation() {
  if (manager == null) {
   manager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
  }
  // provider 기지국||GPS 를 통해서 받을건지 알려주는 Stirng 변수
  // minTime 최소한 얼마만의 시간이 흐른후 위치정보를 받을건지 시간간격을 설정 설정하는 변수
  // minDistance 얼마만의 거리가 떨어지면 위치정보를 받을건지 설정하는 변수
  // manager.requestLocationUpdates(provider, minTime, minDistance, listener);

  // 10초
  long minTime = 10000;
  
  // 거리는 0으로 설정 
  // 그래서 시간과 거리 변수만 보면 움직이지않고 10초뒤에 다시 위치정보를 받는다
  float minDistance = 0;

  MyLocationListener listener = new MyLocationListener();

  manager.requestLocationUpdates(LocationManager.GPS_PROVIDER, minTime, minDistance, listener);

  appendText("내 위치를 요청 했습니다.");
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.my_location, menu);
  return true;
 }

 private void appendText(String msg) {
  text01.append(msg + "\n");
 }

 class MyLocationListener implements LocationListener {

  // 위치정보는 아래 메서드를 통해서 전달된다.
  @Override
  public void onLocationChanged(Location location) {
   appendText("onLocationChanged()가 호출되었습니다");

   double latitude = location.getLatitude();
   double longitude = location.getLongitude();

   appendText("현재 위치:" + latitude + "," + longitude);
   
   showMyLocation(latitude,longitude);
  }

  @Override
  public void onProviderDisabled(String provider) {

  }

  @Override
  public void onProviderEnabled(String provider) {

  }

  @Override
  public void onStatusChanged(String provider, int status, Bundle extras) {

  }

 }
 
 private void showMyLocation(double latitude,double longitude){
  int intlatitude = new Double(latitude).intValue();
  int intlongitude = new Double(longitude).intValue();
  
  // GeoPoint - 경도와 위도를 한점으로 표시하는 객체
  GeoPoint myPoint = new GeoPoint(intlatitude, intlongitude);
  
  // 맵뷰의 속성등을 컨트롤하는 클래스(맵뷰 어뎁터) 
  MapController controller = mapview.getController();
  
  // 애니메이션 효과가 나면서 점으로 이동
  controller.animateTo(myPoint);
  
  // 줌에는 단계가 있는데 정수값으로 표기한다
  controller.setZoom(17);
  
 }

 @Override
 protected boolean isRouteDisplayed() {
  // TODO Auto-generated method stub
  return false;
 }
}

[Android] GPS를 이용해 나의 위치 확인하기(기본)

1. 사전지식

1.1 위치기반서비스

- 모바일 네트워크를 통해 휴대 단말에서 접근할 수 있는 위치 정보 활용 시스템 입니다.
- LBS는 스마트폰 단말에서 자신의 위치를 찾을 수 있게 되면서 활성화 되었다.

1.2 위치기반서비스 활용 분야

- 엔터테인먼트, 위급상황, 의료, 산업, 개인 생활 등등

1.3 대표적인 사용 예

- 가장 가까운 은행, 식당, 주유소, 호텔, 골프장, 병원, 경찰서 찾기
- 출발지부터 목적지까지 가는 길 찾기
- 친구나 가족들의 위치 또는 행사 장소등을 알려주는 소셜 네트워킹 서비스, 친구찾기

1.4 위치를 찾는 대표적인 방법 두가지

- GPS 위성을 이용한 위치 찾기
- 기지국의 타워 ID를 이용한 위치 찾기

1.5 기지국을 이용한 위치 찾기 (cell Tower Triangulation)

- 가까이 위치하고 있는 기지국과의 상대적인 거리를 이용하는 방법
- 휴대폰과 기지국 간의 거리는 기지국으로 부터 휴대폰까지 신호를 보내고 받는 데 따른 지연 시간(lag time)으로 계산

2. 주요 객체 소개

2.1 LocationManager 객체

- 시스템의 위치기반 서비스 접근 지원 하는 객체
- 주기적으로 바뀌는 단말의 위치정보 수신

2.2 LocationListener 객체

-위치정보를 전달 받기 위한 리스너

2.3 Location 객체

-위치는 위도(latitude)와 경도(longitude)로 표시되며 시간은 UTCtimestamp 로 표시되고 그외에 선택적으로 고도(altitude),속도(speed)그리고 bearing정보 표시


3. 기능 구현 순서

3.1 위치관리자 객체 참조 하기

- 코드 37줄

3.2 위치 리스너 구현하기

- 코드 69-98줄

3.3 위치정보 업데이트 요청하기 (동시에 리스너 등록)

- 코드 53줄

3.4 매니페스트에 권한 추가하기
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>  // GPS
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>  //기지국

4.예제
import android.app.Activity;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MyLocationActivity extends Activity {

 TextView text01;
 LocationManager manager;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  text01 = (TextView) findViewById(R.id.text01);
  Button button01 = (Button) findViewById(R.id.button01);
  button01.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View v) {
    // LocationManager 객체 초기화 , LocationListener 리스너 설정
    getMyLocation();
   }
  });
 }

 // LocationManager 객체 초기화 , LocationListener 리스너 설정
 private void getMyLocation() {
  if (manager == null) {
   manager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
  }
  // provider 기지국||GPS 를 통해서 받을건지 알려주는 Stirng 변수
  // minTime 최소한 얼마만의 시간이 흐른후 위치정보를 받을건지 시간간격을 설정 설정하는 변수
  // minDistance 얼마만의 거리가 떨어지면 위치정보를 받을건지 설정하는 변수
  // manager.requestLocationUpdates(provider, minTime, minDistance, listener);

  // 10초
  long minTime = 10000;
  
  // 거리는 0으로 설정 
  // 그래서 시간과 거리 변수만 보면 움직이지않고 10초뒤에 다시 위치정보를 받는다
  float minDistance = 0;

  MyLocationListener listener = new MyLocationListener();

  manager.requestLocationUpdates(LocationManager.GPS_PROVIDER, minTime, minDistance, listener);

  appendText("내 위치를 요청 했습니다.");
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.my_location, menu);
  return true;
 }

 private void appendText(String msg) {
  text01.append(msg + "\n");
 }

 class MyLocationListener implements LocationListener {

  // 위치정보는 아래 메서드를 통해서 전달된다.
  @Override
  public void onLocationChanged(Location location) {
   appendText("onLocationChanged()가 호출되었습니다");

   double latitude = location.getLatitude();
   double longitude = location.getLongitude();

   appendText("현재 위치:" + latitude + "," + longitude);
  }

  @Override
  public void onProviderDisabled(String provider) {

  }

  @Override
  public void onProviderEnabled(String provider) {

  }

  @Override
  public void onStatusChanged(String provider, int status, Bundle extras) {

  }

 }
}

2013년 7월 16일 화요일

[Android] 기본적인 Paint 사용법


1.예제
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.view.View;

//뷰를 상속받아 새로운 뷰를 만든다
public class CustomViewStyles extends View {
 
 // paint객체 - 그래픽 그리기를 위해 필요한 색깔 , 폰트 등을 저장하는곳
 private Paint paint;

 public CustomViewStyles(Context context) {
  super(context);

  paint = new Paint();
 }

 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);

  // 첫번째 사각형
  paint.setStyle(Style.FILL);
  paint.setColor(Color.RED);
  canvas.drawRect(10, 10, 100, 100, paint);
   
  paint.setStyle(Style.STROKE);
  paint.setStrokeWidth(2.0F);
  paint.setColor(Color.GREEN);
  canvas.drawRect(10, 10, 100, 100, paint);

  // 두번째 사각형
  paint.setStyle(Style.FILL);
  paint.setARGB(128, 0, 0, 255);
  canvas.drawRect(120, 10, 210, 100, paint);
  
  DashPathEffect dashEffect = new DashPathEffect(new float[]{5,5}, 1);
  paint.setStyle(Style.STROKE);
  paint.setStrokeWidth(3.0F);
  paint.setPathEffect(dashEffect);
  paint.setColor(Color.GREEN);
  canvas.drawRect(120, 10, 210, 100, paint);
  
  paint = new Paint();
  
  // 첫번째 원
  paint.setColor(Color.MAGENTA);
  canvas.drawCircle(50, 160, 40, paint);
  
  // 두번째 원
  // paint.setAntiAlias(true); 좀더 부드럽게 보이게 해준다
  paint.setAntiAlias(true);
  canvas.drawCircle(160, 160, 40, paint);
  
  // 첫번째
  paint.setStyle(Style.STROKE);
  paint.setStrokeWidth(1);
  paint.setColor(Color.MAGENTA);
  paint.setTextSize(30);
  canvas.drawText("Text (Stroke)", 20, 260, paint);

  // 첫번째 텍스트
  paint.setStyle(Style.FILL);
  paint.setTextSize(30);
  canvas.drawText("Text (채우기)", 20, 320, paint);
  
 }
 
}

2.결과

[Android] Paint , Path , Drawable , LinearGradient 사용예제 와 뷰의 폭과 높이 확인 방법 과 색상 리소스 정의 방법

1.예제
android version = jelly bean
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Paint.Cap;
import android.graphics.Paint.Join;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RectShape;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;

public class CustomViewDrawables extends View {

 private ShapeDrawable upperDrawable;
 private ShapeDrawable lowerDrawable;

 public CustomViewDrawables(Context context) {
  super(context);

  // 윈도우 매니저를 이용해 뷰의 폭과 높이 확인
  // 뷰가 채워지는 화면의 크기를 알아오기 위해 시스템 서비스 객체인 WindowManager를 참조함
  WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
     Display display = manager.getDefaultDisplay();
     Point sizePoint = new Point();
     display.getSize(sizePoint);
     int width = sizePoint.x;
     int height = sizePoint.y;

  // 리소스에 정의된 색상값을 변수에 설정
  // 색상 정보는 xml 파일로 정의되며,[/res/values/]폴더 밑에 colors.xml이라는 이름으로 저장되어있다.
  // 안드로이드에서 색상을 만들어 사용하는 방법은 크게 자바 코드에서 사용하는 경우와 xml 리소스를 이용하는 경우로 나눌 수 있다.
  // 자바 코드에서는 Color 클래스에 정의된 상수 또는 Color.argb()메소드를 사용한다.
  Resources curRes = getResources();
  int blackColor = curRes.getColor(R.color.color01);
  int grayColor = curRes.getColor(R.color.color02);
  int darkGrayColor = curRes.getColor(R.color.color03);

  // upperDrawable 객체 생성
  upperDrawable = new ShapeDrawable();
  RectShape rectangle = new RectShape();
  rectangle.resize(width, height*2/3);
  upperDrawable.setShape(rectangle);
  upperDrawable.setBounds(0, 0, width, height*2/3);

  // 그라데이션 효과를 가지는 gradient객체 생성과 upperDrawable의 paint객체에 gradient객체를 shader로 설정
  LinearGradient gradient = new LinearGradient(0, 0, 0, height*2/3, grayColor, blackColor, TileMode.CLAMP);
  Paint paint = upperDrawable.getPaint();
  paint.setShader(gradient);

  // lowerDrawable 객체 생성
  lowerDrawable = new ShapeDrawable();
  RectShape rectangle2 = new RectShape();
  rectangle2.resize(width, height*1/3);
  lowerDrawable.setShape(rectangle2);
  lowerDrawable.setBounds(0, height*2/3, width, height);

  // 그라데이션 효과를 가지는 gradient 객체 생성과 lowerDrawable의 paint객체에 gradient객체를 shader로 설정
  LinearGradient gradient2 = new LinearGradient(0, 0, 0, height*1/3, blackColor, darkGrayColor, TileMode.CLAMP);
  Paint paint2 = lowerDrawable.getPaint();
  paint2.setShader(gradient2);

 }

 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);

  // 뷰 밑바탕이 되는 upperDrawable , upperDrawable 그리기
  upperDrawable.draw(canvas);
  upperDrawable.draw(canvas);

  // pathPaint 설정
  Paint pathPaint = new Paint();
  pathPaint.setAntiAlias(true);
  pathPaint.setColor(Color.YELLOW);
  pathPaint.setStyle(Style.STROKE);
  pathPaint.setStrokeWidth(16.0F);
  pathPaint.setStrokeCap(Cap.BUTT);
  pathPaint.setStrokeJoin(Join.MITER);

  // Path 설정
  Path path = new Path();
  path.moveTo(20, 20);
  path.lineTo(120, 20);
  path.lineTo(160, 90);
  path.lineTo(180, 80);
  path.lineTo(200, 120);

  // path 그리기
  canvas.drawPath(path, pathPaint);

  // pathPaint 설정
  pathPaint.setColor(Color.WHITE);
  pathPaint.setStrokeCap(Cap.ROUND);
  pathPaint.setStrokeJoin(Join.ROUND);

  // path 그리기
  path.offset(30, 120);
  canvas.drawPath(path, pathPaint);

  // pathPaint 설정
  pathPaint.setColor(Color.CYAN);
  pathPaint.setStrokeCap(Cap.SQUARE);
  pathPaint.setStrokeJoin(Join.BEVEL);

  // path 그리기
  path.offset(30, 120);
  canvas.drawPath(path, pathPaint);

 }

}

[Android] 뷰 위에 그래픽을 그리기

1. 뷰 위에 그래픽을 그리는 순서(정형화된 방법)

1.1 새로운 클래스를 만들고 뷰를 상속받는다.

1.2 페인트 객체를 초기화하고 필요한 속성을 설정한다.

1.3 뷰클래스에 정의된 onDraw() 오버라이딩해서 메서드 내에 원하는 그림을 그리는 메소드를 호출한다.

1.4 onTouch() 메서드 내에 터치 이벤트를 처리하는 코드를 넣는다.

1.5 새로 만든 뷰를 메인 액티비티에 추가한다.

2. 예제
android version = jelly bean
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

// 뷰를 상속받아 새로운 뷰를 만든다
public class CustomView extends View {

 // paint객체 - 그래픽 그리기를 위해 필요한 색깔 , 폰트 등을 저장하는곳
 Paint paint;
 float curX;
 float curY;

 public CustomView(Context context) {
  super(context);
  init();
 }

 public CustomView(Context context, AttributeSet attrs) {
  super(context, attrs);
  init();
 }

 // 뷰의 초기화 작업
 private void init() {

                // 페인트 객체 생성 및 색깔 설정
  paint = new Paint();
  paint.setColor(Color.RED);
 }

 // 뷰에 그림을 그릴때 자동으로 호출되는 메서드
 // 이뷰가 화면상에 보여지기 바로전에 호출된다.
 @Override
 protected void onDraw(Canvas canvas) {

  // 뷰에 사격형을 그립니다.
  // canvas - 뷰의 표면에 직접 그릴 수 있도록 만들어 주는 객체로 그래픽 그리기를 위한 메소드가 정의되어 있다.
  canvas.drawRect(curX, curY, curX + 100.0f, curY + 100.0f,paint);
  
  super.onDraw(canvas);
 }

 // 뷰안에서 터치 이벤트가 발생할때 자동으로 호출되는 메서드
 // return 값은 true 로 만들어줘야한다.
 @Override
 public boolean onTouchEvent(MotionEvent event) {
  int action = event.getAction();

  switch (action) {
  // 누른 상태
  case MotionEvent.ACTION_DOWN:
   break;
   
  // 누르고 욺직인 상태
  case MotionEvent.ACTION_MOVE:
   
   curX = event.getX();
   curY = event.getY();

   // 뷰의 그래픽을 다시 그리게 한다 .
   // OnDraw() 메서드를 호출하게 한다.
   invalidate();
   
   break;
   
  // 누르고 땔때 상태
  case MotionEvent.ACTION_UP:
   break;
  default:
  }

  return true;
 }

}

[Android] 사진찍기와 카메라 미리보기

*중요

*.1 Manifest에 주가해야되는 권한
- <uses-permission android:name="android.permission.CAMERA"/>  //카메라 사용
- <uses-permission android:name="android.permission.FLASHLIGHT"/>  //카메라 플레쉬 사용

1. 카메라 미리보기 주요과정

1.1 카메라 미리보는 SurfaceView를 사용함 따라서, SurfaceView 사용 패턴을 그대로 사용한다.(SurfaceHolder를 이용한 SurfaceView 컨트롤)

1.2 카메라에게 서피스뷰를 알려주는 메서드
camera.setPreviewDisplay(mHolder);
1.3 미리보기에 시작 메서드
camera.startPreview();
2. 카메라 캡처 주요과정

- 이부분은 주관적인 부분으로 정확하지않을수 있습니다.

2.1 카메라 셔터를 눌렀을때 일어나는 이벤트를 정의한 인터페이스를 재정의한다.
 Camera.ShutterCallback suttercallback = new Camera.ShutterCallback() {
  public void onShutter() {...}
 };
2.2 카메라 캡처후 사진데이터가 Raw 혹은 JPEG 형식으로 메모리에 적제되면 그것을 어떻게 처리할것인지 처리하는 인터페이스를 제정의한다.
 Camera.PictureCallback picturecallback = new Camera.PictureCallback() {
  public void onPictureTaken(byte[] data, Camera camera) {...}
 };
2.3 카메라 캡처 이벤트가 발생한곳(버튼이거나 뷰 등등)에 메서드를 넣어준다. 그리고 2.1 / 2.2 에서 생성한 객체들을 매개변수에 넣어준다
camera.takePicture(suttercallback , null , picturecallback);
3. SurfaceView 재정의 주요과정(전형적인 패턴)

-가끔 디테일한 설정이 필요할때는 SurfaceView를 재정의 해서 사용한다.

3.1 클래스 재정의 할때 SurfaceView 와 SurfaceView 의 상태컨트롤을 위한 SurfaceHolder.Callback를 상속받아서 정의한다
class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback
3.2 재정의된 SurfaceView를 컨트롤할 내부 변수 SurfaceHolder 객체를 선언하고 생성자나 다른 함수를 안에서 SurfaceHolder 객체를 생성한다.
private SurfaceHolder mHolder;
mHolder = getHolder();
3.3 카메라가 SurfaceView를 독점하기 위해선 SurfaceHolder의 타입은 항상SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS로 설정한다.
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
3.4 SurfaceView 의상태(메모리 유무 ,사이즈변화 등등)는 SurfaceHolder.Callback 인터페이스 에 정의된 메서드로 처리한다.(기존 다른 리스너 방식과 유사)
-mHolder.addCallback(this); //콜백 인터페이스 홀더에 설정
-public void surfaceCreated(SurfaceHolder holder)  // SurfaceView가 생성됬을때 호출된다
-public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)  //SurfaceView 크기가 변화될때 호출된다
-public void surfaceDestroyed(SurfaceHolder holder)  //SurfaceView 메모리 헤제됬을때 호출된다

4. 예제
android version = jelly bean
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.Camera;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.Menu;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.Toast;


// SurfaceView를 이용해 미리보기 화면을 만든 후 사진찍기를 하는 방법에 대해 알 수 있습니다.
public class MainActivity extends Activity {
 
 // 캡처한 사진파일 저장할 이름
 public static String IMAGE_FILE = "capture.jpg";

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  // FrameLayout에 재정의한 CameraSurfaceView 추가
  final CameraSurfaceView cameraView = new CameraSurfaceView(
    getApplicationContext());
  FrameLayout previewFrame = (FrameLayout) findViewById(R.id.previewFrame);
  previewFrame.addView(cameraView);

  // 버튼을 눌렀을때 캡처
  Button saveBtn = (Button) findViewById(R.id.saveBtn);
  saveBtn.setOnClickListener(new View.OnClickListener() {
   public void onClick(View v) {
    
    // cameraView에 있는 capture() 메서드 실행
    cameraView.capture(new Camera.PictureCallback() {
     
     // JPEG 사진파일 생성후 호출됨
     // 찍은 사진을 처리
     // PictureCallback 인터페이스 에 있는 onPictureTaken() 메서드
     // byte[] data - 사진 데이타
     public void onPictureTaken(byte[] data, Camera camera) {
      try {
       
       // 사진데이타를 비트맵 객체로 저장
       Bitmap bitmap = BitmapFactory.decodeByteArray(data,0, data.length);
       
       // bitmap 이미지를 이용해 앨범에 저장
       // 내용재공자를 통해서 앨범에 저장
       String outUriStr = MediaStore.Images.Media.insertImage(getContentResolver(), bitmap,"Captured Image","Captured Image using Camera.");

       if (outUriStr == null) {
        Log.d("SampleCapture", "Image insert failed.");
        return;
       } else {
        Uri outUri = Uri.parse(outUriStr);
        sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,outUri));
       }

       Toast.makeText(getApplicationContext(),"카메라로 찍은 사진을 앨범에 저장했습니다.",Toast.LENGTH_LONG).show();

       // 다시 미리보기 화면 보여줌
       camera.startPreview();
      } catch (Exception e) {
       Log.e("SampleCapture", "Failed to insert image.", e);
      }
     }
    });
   }
  });

 }

 // 카메라 미리보기를 위해 SurfaceView 클래스 재정의
 private class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
  
  // SurfaceView를 컨트롤할 SurfaceHolder 객체 선언
  private SurfaceHolder mHolder;

  // 미리보기를 위한 카메라 객체 선언
  private Camera camera = null;

  public CameraSurfaceView(Context context) {
   super(context);
   
   // SurfaceHolder 객체 생성 getHolder()는 SurfaceView 내부 함수
   mHolder = getHolder();

   // SurfaceHolder.Callback 인터페이스 장착
   mHolder.addCallback(this);

   // 카메라가 SurfaceView를  독점하기 위한 타입 설정
   // 버퍼를 사용하지않음
   mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  }

  // SurfaceView 가 메모리에 생성될때 호출된다.
  public void surfaceCreated(SurfaceHolder holder) {
   // 카메라를 사용할려고 한다는 설정
   camera = Camera.open();

   try {
    // 미리보기를 설정
    camera.setPreviewDisplay(mHolder);
   } catch (Exception e) {
    Log.e("CameraSurfaceView", "Failed to set camera preview.", e);
   }
  }
  
  // 보통 SurfaceView가 보여지기전 과 사이즈가 변화가있을때 호출된다.
  // 그래서 보여지기전인 surfaceCreated()가 호출된 다음 호출된다. 
  public void surfaceChanged(SurfaceHolder holder, int format, int width,
    int height) {

   // 카메라의 파라미터 값을 가져와서 미리보기 크기를 설정한다
   Camera.Parameters parameters= camera.getParameters();
   parameters.setPreviewSize(width, height);
   camera.setParameters(parameters);
   
   // 미리보기화면을 뿌려준다
   camera.startPreview();
  }

  // SurfaceView의 메모리가 해제되었을때 호출된다.
  // SurfaceView가 화면에 표시되지않을때(액티비티가 비활성화 될때) 호출된다.
  public void surfaceDestroyed(SurfaceHolder holder) {
   
   // 미리보기 중지
   camera.stopPreview();
   // 메모리 해제
   camera.release();
   camera = null;
  }

  
  // 사진을 찍을때 호출되는 함수 (스냅샷)
  public boolean capture(Camera.PictureCallback handler) {
   if (camera != null) {
    // 셔터후
    // Raw 이미지 생성후
    // JPE 이미지 생성후
    camera.takePicture(null, null, handler);
    return true;
   } else {
    return false;
   }
  }

 }

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

2013년 7월 15일 월요일

[Android] SQLiteOpenHelper를 이용한 Database 생성과 커리문 실행

1. DB 생성과 커리 실행 방법
- SQLiteOpenHelper 클래스는 DB를 (생성||열기||업데이트)위해 필요한 일들을 도와주는 역활을 한다.

1.1 데이터 베이스 생성 혹은 열기위해 필요한 객체를 생성
- public DataBaseHelper(Context context, String name, CursorFactory factory, int version)

1.2 처음에 DB가 생성될때 호출됨
- public void onCreate(SQLiteDatabase database)

1.3 DB가 존재할때 DB를 열때 호출됨
- public void onOpen(SQLiteDatabase database)

1.4 DB가 존재할때 DB버전이 바뀌면 호출됨
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)

2. 예제 
android version = jelly bean
import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MyDataBaseHelperActivity extends Activity {
 public static final String tableName = "CUSTOMER";
 Button button1;
 Button button2;
 Button button3;
 Button button4;
 TextView text1;
 DataBaseHelper helper;
 SQLiteDatabase database;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  button1 = (Button) findViewById(R.id.button1);
  button2 = (Button) findViewById(R.id.button2);
  //button3 = (Button) findViewById(R.id.button3);
  //button4 = (Button) findViewById(R.id.button4);
  text1 = (TextView) findViewById(R.id.text1);

  // 디비 생성
  button1.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View v) {
    createDatabase();
   }
  });
  
  // 커리 실행
  button2.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View v) {
    queryData();
   }
  });
 }

 private void createDatabase() {
  int version = 1;
  String name = "customer.db";
  // database = openOrCreateDatabase(name, MODE_WORLD_WRITEABLE, null);
  
  //헬퍼를 이용해 디비생성방법
  helper = new DataBaseHelper(getApplicationContext(), name, null, version);
  database = helper.getWritableDatabase();
 }

 private void queryData() {
  String sql = "select id,name,age from " + tableName + " where age >18";
  
  // 데이터를 받을땐 커서로 받는다
  Cursor cursor = database.rawQuery(sql, null);

  // cursor.getcount() 레코드 갯수
  // cursor.moveToNext() 다음 레코드를 조회
  // cursor.getString() 칼럼데이타 조회
  if (cursor != null) {
   int count = cursor.getCount();
   text1.append("데이터를 조회햇어요. 레코드 갯수" + count + "\n");

   for (int i = 0; i < count; i++) {
    cursor.moveToNext();
    String name = cursor.getString(1);
    text1.append("데이터 #" + i + ":" + name + "\n");
   }
  }
 }

 class DataBaseHelper extends SQLiteOpenHelper {

  // 데이터베이스를 생성할때 필요한 생성자
  // context = 불러올 액티비티
  // name = 데이터베이스 이름
  // factory = ??
  // version = 데이터베이스 버전
  public DataBaseHelper(Context context, String name,
    CursorFactory factory, int version) {
   super(context, name, factory, version);
  }

  // 데이터베이스를 처음 생성할때 불려지는 메서드 생성되있으면 호출되지않는다.
  @Override
  public void onCreate(SQLiteDatabase database) {
   createTable(database);
   insertData(database);
   text1.append("헬퍼를 이용해 데이터베이스를 생성 했어요.\n");
  }

  // 데이터베이스가 생성되거나 존재할때 데이터베이스를 여는 메서드
  @Override
  public void onOpen(SQLiteDatabase database) {
   text1.append("헬퍼를 이용해 데이터베이스를 오픈 했어요.\n");
  }

  // 데이터베이스가 업그레이드 될때 호출되는 메서든
  @Override
  public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
   text1.append("헬퍼를 이용해 데이터베이스를 업그레이드 했어요.\n");
  }

  private void createTable(SQLiteDatabase database) {
   String sql = "create table " + tableName + "(id text,name text,age integer)";
   try {
    // sql 실행하는 메서드
    database.execSQL(sql);
    text1.append("테이블을 만들었어요\n");
   } catch (Exception e) {
    text1.append("테이블 만들때 예외\n");
    e.printStackTrace();
   }
  }

  private void insertData(SQLiteDatabase database) {
   // 데이타베이스 트렌젝션 시작
   database.beginTransaction();
   try {
    String sql = "insert into " + tableName + "(id,name,age)" + " values('100','홍길동',21)";

    // sql 실행하는 메서드
    database.execSQL(sql);

    sql = "insert into " + tableName + "(id,name,age)" + " values('200','소녀시대',19)";
    
    // sql 실행하는 메서드
    database.execSQL(sql);
    
    // 데이타베이스 트렌젝션 성공
    database.setTransactionSuccessful();
   } catch (Exception e) {
    text1.append("데이터 추가할 때 예외" + e.getMessage() + "\n");
    e.printStackTrace();
   } finally {
    
    // 데이타베이스 트렌젝션 끝 이것은 꼭 해줘야한다.
    database.endTransaction();
   }

   text1.append("데이터를 넣었어요\n");
  }
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.my_data_base_helper, menu);
  return true;
 }
}

[Android] SurfaceView를 이용한 비디오 재생 과 녹화

1. SurfaceView 참조 혹은 추가

1.1 xml 파일에 SurfaceView 를 추가하는 방법
-생략

1.2 자바 코드에서 SurfaceView 를 추가하는 방법
        SurfaceView sur = new SurfaceView(getApplicationContext());
        LinearLayout surfaceViewLayout = (LinearLayout)findViewById(R.id.sufaceViewLayout);
        surfaceViewLayout.addView(sur);

2. 비디오 재생 주요순서

2.1 코드 138-158줄 참고

3. 비디오 재생중지 주요순서

3.1 코드 165-174줄 참고

4. 비디오 녹음 주요순서

4.1 코드 75-93줄 참고

5. 비디오 녹음중지 주요순서

5.1 코드 107-112줄 참고

6. 예제 
android version = jelly bean
import android.app.Activity;
import android.content.ContentValues;
import android.content.Intent;
import android.hardware.Camera;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.Menu;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.MediaController;
import android.widget.Toast;
import android.widget.VideoView;

public class MainActivity extends Activity {

 private static String EXTERNAL_STORAGE_PATH = "";
    private static String RECORDED_FILE = "video_recorded";
    private static int fileIndex = 0;
    private static String filename = "";

    MediaPlayer player;
    MediaRecorder recorder;

    // 카메라 상태를 저장하고 있는 객체
    private Camera camera = null;
    
    SurfaceView surfaceView;
    SurfaceHolder holder;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
  
        // 외장메모리가 있는지 확인한다.
        // Environment.getExternalStorageState() 를 통해서 현재 외장메모리를 상태를 알수있다.
        String state = Environment.getExternalStorageState();
        // Environment.MEDIA_MOUNTED 외장메모리가 마운트 flog
        if (!state.equals(Environment.MEDIA_MOUNTED)) {
         Toast.makeText(getApplicationContext(), "외장 메모리가 마운트 되지않았습니다.", Toast.LENGTH_LONG).show();
        } else {
         EXTERNAL_STORAGE_PATH = Environment.getExternalStorageDirectory().getAbsolutePath();
        }

        
        // SurfaceView 클래스 객체를 이용해서 카메라에 받은 녹화하고 재생하는데 쓰일것이다.
        surfaceView = (SurfaceView)findViewById(R.id.surface);
        // SurfaceView 클래스를 컨트롤하기위한 SurfaceHolder 생성
        holder = surfaceView.getHolder();
        // 버퍼없음
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        Button recordBtn = (Button) findViewById(R.id.recordBtn);
        Button recordStopBtn = (Button) findViewById(R.id.recordStopBtn);
        Button playBtn = (Button) findViewById(R.id.playBtn);
        Button playStopBtn = (Button) findViewById(R.id.playStopBtn);

        // 녹화 시작 버튼
        recordBtn.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                try {
                 // 녹화 시작을 위해  MediaRecorder 객체 recorder를 생성한다.
                 if (recorder == null) {
                  recorder = new MediaRecorder();
                    }
                 // 오디오와영상 입력 형식 설정
                 recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
                 recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
                 recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
                 
                 // 오디오와영상 인코더 설정
                 recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
                 recorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);

                 // 저장될 파일 지정
                 filename = createFilename();
                 recorder.setOutputFile(filename);

                 // 녹화도중에 녹화화면을 뷰에다가 출력하게 해주는 설정
                 recorder.setPreviewDisplay(holder.getSurface());
                 
                 // 녹화 준비,시작 
                 recorder.prepare();
                 recorder.start();

                } catch (Exception ex) {
                    ex.printStackTrace();
                    recorder.release();
                    recorder = null;
                }
            }
        });

        recordStopBtn.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                if (recorder == null)
                    return;
                // 녹화 중지
                recorder.stop();
                
                // 영상 재생에 필요한 메모리를 해제한다.
                recorder.release();
                recorder = null;

                ContentValues values = new ContentValues(10);

                values.put(MediaStore.MediaColumns.TITLE, "RecordedVideo");
                values.put(MediaStore.Audio.Media.ALBUM, "Video Album");
                values.put(MediaStore.Audio.Media.ARTIST, "Mike");
                values.put(MediaStore.Audio.Media.DISPLAY_NAME, "Recorded Video");
                values.put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis() / 1000);
                values.put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4");
                values.put(MediaStore.Audio.Media.DATA, filename);

                Uri videoUri = getContentResolver().insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values);
                if (videoUri == null) {
                    Log.d("SampleVideoRecorder", "Video insert failed.");
                    return;
                }

                sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, videoUri));

            }
        });

        playBtn.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
             
             // 영상 재생 방법
                if (player == null) {
                 // 영상 플레이를 위해 MediaPlayer 클래스 객체를 생성한다
                    player = new MediaPlayer();
                }

                try {
                 // 플레이할 파일 설정
                    player.setDataSource(filename);
                    
                    // 플레이할 뷰 설정
                    player.setDisplay(holder);
                 
                    // 플레이 준비,시작
                    player.prepare();
                    player.start();          
                          
                } catch (Exception e) {
                    Toast.makeText(getApplicationContext(), "영상이 재생 도중 예외가 발생했습니다.", Toast.LENGTH_LONG).show();
                }
            }
        });


        playStopBtn.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
             
             // 영상 중지 방법
                if (player == null)
                 return;
                // 영상 중지
                player.stop();
                
                // 메모리 해제
                player.release();
                player = null;
            }
        });
        
        
    }


    private String createFilename() {
     fileIndex++;

     String newFilename = "";
     if (EXTERNAL_STORAGE_PATH == null || EXTERNAL_STORAGE_PATH.equals("")) {
      // 내장 메모리를 사용합니다.
      newFilename = RECORDED_FILE + fileIndex + ".mp4";
     } else {
      // 외장 메모리를 사용합니다.
      newFilename = EXTERNAL_STORAGE_PATH + "/" + RECORDED_FILE + fileIndex + ".mp4";
     }

     return newFilename;
    }


    // 액티비티가 onPause 상태일때 녹화,재생에 필요한 모든 객체들의 메모리를 해제한다
    protected void onPause() {
        super.onPause();
     if (camera != null) {
      camera.release();
      camera = null;
        }

        if (recorder != null) {
         recorder.release();
         recorder = null;
        }

        if (player != null) {
            player.release();
            player = null;
        }
    }


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

[Android] VideoView를 이용한 비디오 재생

Tip!:웬만하면 VideoView는 그때 그때 자바 코드로 생성해서 추가 후 사용 하는게 좋다.이유는 화면 전환시 여러 UI가 있을때 화면에 제일 먼저 그려져서 보기에 좋지 않을 때가 있다. 

1. 비디오 재생 주요 순서

1.1 VideoView 클래스 객체를 참조
- VideoView videoView = (VideoView) findViewById(R.id.VideoView);

1.1 비디오 파일 위치 설정
- 예제에서 확인

1.2 비디오 재생 시작
- videoView.start();

2. 비디오 재생중지 주요 순서 

2.1 비디오 일시중지
- videoView.pause();

2.2 비디오 중지
- videoView.stopPlayback();

3. 예제 
android version = jelly bean
import android.app.Activity;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.MediaController;
import android.widget.Toast;
import android.widget.VideoView;

public class MyVideoPlayerActivity extends Activity {
 public final static String VIDEO_URL = "http://sites.google.com/site/ubiaccessmobile/sample_video.mp4";
 public final static int URL = 1;
 public final static int SDCARD = 2;
 VideoView videoView;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  // 영상을 출력하기 위한 비디오뷰
  // SurfaceView 를 상속받아 만든클래스이다
  // 웬만하면 VideoView는 그때 그때 생성해서 추가 후 사용
  // 화면 전환시 여러 UI가 있을때 화면에 제일 먼저 그려져서 보기에 좋지 않을 때가 있다.
  // 예제에서 xml 에 추가해서 해보았다.
  videoView = (VideoView) findViewById(R.id.VideoView);

  Button button1 = (Button) findViewById(R.id.button1);
  Button button2 = (Button) findViewById(R.id.button2);
  videoView = (VideoView) findViewById(R.id.VideoView);
  
  int type = URL;
  switch (type) {
  case URL:
   // 동영상의 경로가 웹에 있다면 아래와 같이 설정
   videoView.setVideoURI(Uri.parse(VIDEO_URL));
   break;

  case SDCARD:
   // 동영상의 경로가 SD Card 에 있다면 아래와 같이 설정
   String path = Environment.getExternalStorageDirectory()
     + "/TestVidio6.mp4";
   videoView.setVideoPath(path);
   break;

  }

  // 미디어컨트롤러 추가하는부분
  MediaController controller = new MediaController(this);
  videoView.setMediaController(controller);

  // 준비하는 과정을 미리함
  videoView.requestFocus();

  // 동영상이 재생준비가 완료되엇을떄를 알수있는 리스너 (실제 웹에서 영상을 다운받아 출력할때 많이 사용됨)
  videoView.setOnPreparedListener(new OnPreparedListener() {

   // 동영상 재생준비가 완료된후 호출되는 메서드
   @Override
   public void onPrepared(MediaPlayer mp) {
    // TODO Auto-generated method stub
    Toast.makeText(getApplicationContext(),
      "동영상이 준비되었습니다.\n'재생' 버튼을 누르세요.", Toast.LENGTH_LONG)
      .show();
   }
  });

  // 동영상 재생이 완료된걸 알수있는 리스너
  videoView.setOnCompletionListener(new OnCompletionListener() {

   // 동영상 재생이 완료된후 호출되는 메서드
   public void onCompletion(MediaPlayer player) {
    Toast.makeText(getApplicationContext(), "동영상 재생이 완료되었습니다.",
      Toast.LENGTH_LONG).show();
   }
  });

  button1.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View v) {
    // TODO Auto-generated method stub
    playVideo();
   }
  });

  button2.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View v) {
    // TODO Auto-generated method stub
    stopVideo();
   }
  });
 }

 private void playVideo() {
  // 비디오를 처음부터 재생할땐 0
  videoView.seekTo(0);
  // 비디오 재생 시작
  videoView.start();
 }

 private void stopVideo() {

  // 비디오 재생 잠시멈춤
  videoView.pause();

  // 비디오 재생 완전 멈춤
  videoView.stopPlayback();
  
  // 예제에선 videoView=null를 해서 단말기에 테스트시 한번밖에 동영상을 재생못합니다.
  //videoView = null;
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.my_video_player, menu);
  return true;
 }

}

[Android] Audio 재생 과 녹음

1. 오디오 재생 주요순서

1.1 MediaPlayer 객체 생성
- MediaPlayer player = new MediaPlayer ();

1.2 데이터 소스 (URL || 단말sd카드 || 프로젝트 파일에 포함(res,assets)) 지정
- player.setDataSource(filename);

1.3 준비
- player.prepare();

1.4 시작
- player.start();

2. 오디오 재생중지 주요순서

2.1 재생 중지
- player.stop();

2.2 재생에 사용됐던 메모리 해제
- player.release();
- player = null;

3. 오디오 녹음 주요순서

3.1 MediaRecorder 객체 생성
- MediaRecorder  recorder = new MediaRecorder();

3.2 오디오 입력 및 출력 형식 설정
- recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
- recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);

3.3 오디오 인코더와 파일 지정
- recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);

3.4 녹음준비,시작
- recorder.prepare();
- recorder.start();

3.5 메니페스트에 권한 설정
<uses-permission android:name="android.permission.RECORD_AUDIO" />

4. 오디오 녹음중지 주요순서

4.1 녹음 중지
- recorder.stop();

4.2 녹음에 사용됐던 메모리 해제
- recorder.release();
- recorder = null;

5. 예제
android version = jelly bean
import java.io.File;

import android.app.Activity;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity {
 // URL 오디오 파일 위치
 // 웹 상에 있는 오디오 파일을 재생할때는 permission.WRITE_EXTERNAL_STORAGE 를 추가해야한다.
 public static final String Audio_Url = "http://sites.google.com/site/ubiaccessmobile/dample_audio.amr";
 
 // 녹음된 오디오 저장할 위치
 // 내장 메모리를 사용하려면 permission.WRITE_EXTERNAL_STORAGE 를 추가해야한다.
 // Environment.getExternalStorageDirectory()로 각기 다른 핸드폰의 내장메모리의 디렉토리를 알수있다.
 final private static File RECORDED_FILE = Environment.getExternalStorageDirectory();
 
 String filename;
    // MediaPlayer 클래스에 재생에 관련된 메서드와 멤버변수가 저장어되있다.
    MediaPlayer player;
    // MediaRecorder 클래스에  녹음에 관련된 메서드와 멤버 변수가 저장되어있다.
    MediaRecorder recorder;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button recordBtn = (Button) findViewById(R.id.recordBtn);
        Button recordStopBtn = (Button) findViewById(R.id.recordStopBtn);
        Button playBtn = (Button) findViewById(R.id.playBtn);
        Button playStopBtn = (Button) findViewById(R.id.playStopBtn);
        
        // 저장할 파일 위치를 String 으로 처리했다.
        // RECORDED_FILE.getAbsolutePath() == /mnt/sdcard 뒤에 저장할 파일엔 '/' 가 필요하다.
        filename =RECORDED_FILE.getAbsolutePath()+"/test.mp4";;
        
        // 녹음 시작 버튼
        recordBtn.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                if (recorder != null) {
                 recorder.stop();
                    recorder.release();
                    recorder = null;
                }
                
                // 실험 결과 왠만하면 아래 recorder 객체의 속성을 지정하는 순서는 이대로 하는게 좋다 위치를 바꿨을때 에러가 났었음
                // 녹음 시작을 위해  MediaRecorder 객체  recorder를 생성한다.
                recorder = new MediaRecorder();
                
                // 오디오 입력 형식 설정
                recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
                
                // 음향을 저장할 방식을 설정
                recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
                
                // 오디오 인코더 설정
                recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
                
                // 저장될 파일 지정
                recorder.setOutputFile(filename);
                

                try {
                 Toast.makeText(getApplicationContext(), "녹음이 시작되었습니다.", Toast.LENGTH_LONG).show();
                 
                 // 녹음 준비,시작
                 recorder.prepare();
                 recorder.start();
                } catch (Exception ex) {
                    Log.e("SampleAudioRecorder", "Exception : ", ex);
                }
            }
        });

        // 녹음 중지 버튼
        recordStopBtn.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                if (recorder == null)
                    return;
                
                // 녹음을 중지
                recorder.stop();
                
                // 오디오 녹음에 필요한  메모리를 해제한다
                recorder.release();
                recorder = null;

                Toast.makeText(getApplicationContext(), "녹음이 중지되었습니다.", Toast.LENGTH_LONG).show();
            }
        });

        
        // 오디오 플레이 버튼
        playBtn.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                if (player != null) {
                 player.stop();
                    player.release();
                    player = null;
                }

                Toast.makeText(getApplicationContext(), "녹음된 파일을 재생합니다.", Toast.LENGTH_LONG).show();
                try {
                 
                 // 오디오를 플레이 하기위해 MediaPlayer 객체 player를 생성한다.
                 player = new MediaPlayer ();
                 
                    // 재생할 오디오 파일 저장위치를 설정
                    player.setDataSource(filename);
                    // 웹상에 있는 오디오 파일을 재생할때
                    // player.setDataSource(Audio_Url);
                    
                    // 오디오 재생준비,시작
                    player.prepare();
                    player.start();
                } catch (Exception e) {
                    Log.e("SampleAudioRecorder", "Audio play failed.", e);
                }
            }
        });


        // 오디오 재생 중지 버튼
        playStopBtn.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                if (player == null)
                 return;

                Toast.makeText(getApplicationContext(), "재생이 중지되었습니다.", Toast.LENGTH_LONG).show();

                
                // 오디오 재생 중지
                player.stop();
                
                // 오디오 재생에 필요한 메모리들을 해제한다
                player.release();
                player = null;
            }
        });
    }


    protected void onPause() {
        if (recorder != null) {
         recorder.release();
         recorder = null;
        }

        if (player != null) {
            player.release();
            player = null;
        }

        super.onPause();
    }

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

2013년 7월 14일 일요일

구글 블로그에서 코드 나오게 하는법

간단하게 구글 블로그에서 코드를 형식에 맞게 올리는 방법을 소개하겠습니다.
1. 자신의 블로그에 들어가셔서 왼쪽상단 디자인 클릭해 주세요.
2. 왼쪽 카데고리중 템블릿을 클릭 해주세요.
3. html 편집기를 클릭해주세요.
4. head 태크와 body 태크 사이에 아래 그림과 같이 스크립트를 입력해주세요.
<!-- SyntaxHighlight setting -->

<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js' type='text/javascript'>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJava.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCss.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCpp.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPhp.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushSql.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJava.js' type='text/javascript'/>
<link href='http://alexgorbatchev.com/pub/sh/current/styles/shCore.css' rel='stylesheet' type='text/css'/>
<link href='http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css' rel='stylesheet' type='text/css'/>

</script>
<script type='text/javascript'>
     SyntaxHighlighter.all()
</script>

<!-- SyntaxHighlight end -->


   필요한 언어에따라서 아래 링크를 따라가시면 언어맞는 브러쉬들을 제공합니다.
   http://alexgorbatchev.com/SyntaxHighlighter/manual/brushes/

5.여기까지로 설정이 완료 되었습니다. 앞으로 글쓰실때 html로 작성해주시면 되겠습니다.

6.코드를 추가하실때 html 편집으로 들어가셔서 <pre class = "brush:xxx"> 코드 <pre> 로 감싸서 해주시면 됩니다.

<pre class="brush:java">

package tutorial;
import com.opensymphony.xwork2.ActionSupport;
public class HelloWorld extends ActionSupport {
  private String name;
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String execute() {
    name = "Hello, " + name + "!"; 
    return SUCCESS;
  }
}
</pre>

7.결과
package tutorial;
import com.opensymphony.xwork2.ActionSupport;
public class HelloWorld extends ActionSupport {
  private String name;
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String execute() {
    name = "Hello, " + name + "!"; 
    return SUCCESS;
  }
}