android.os.Build.MODEL 을 확인해 보면 "sdk"라고 나올 경우는 에뮬레이터 환경

기타 제조사등의 정보도 android.os.Build를 확인하면 가능함.

SystemProperty를 통해서 알수 있는 방법도 확인이 필요함.
(SystemProperties는 private 영역으로 접근 불가함.)
Posted by 피의복수

자 이제 MapView를 통해 구글이 제공하는 지도를 볼 수 있다는 것을 알았고, 그 위에 마커를 올려줄 수 있다는 것을 확인했다.
근데 Map 예제를 보면서 왜 지도가 세계지도로 나올까? 난 이게 참 궁금했다.
확인해보니 Map과 관련된 Control을 관리해 주어야 하는 구만.
그럼 지금부터는 진짜 지도를 보자.

MapView를 사용하기 위해서는 manifest.xml에
<uses-library android:name="com.google.android.maps" /> 과
<uses-permission android:name="android.permission.INTERNET" /> 를 추가해 주어야 한다는 것을 이미 배웠다.

이런 식으로 GPS를 확인하기 위해 다음과 같은 permission이 추가되어야 한다.
 
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>   
 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

하나씩 설명하기 어려우니 작성한 소스를 올린다.

package com.bloodlee;

/**
 * MapView를 위한 Sample을 작성합니다.<br>
 * 1. 현재 GPS 정보를 조회하여 Map을 그립니다.<br>
 * 2. GPS 정보가 변경되면 해당 위치를 다시 그립니다.<br>
 * 3. 혠 wjdqh
 * @author bloodlee
 */

import java.io.IOException;
import java.util.List;
import java.util.Locale;

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

import android.content.Context;
import android.location.Address;
import android.location.Criteria;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

public class MapviewSample extends MapActivity implements LocationListener{

 MapController mc;
 
 /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        // MapView 생성
        MapView mapView = (MapView) findViewById(R.id.mapview);
        // MapView 하단에 Zoom 생성
        mapView.setBuiltInZoomControls(true);

        // LocationManager를 구한다.
        LocationManager locManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        // 현재 시스템의 LocationManager에서 활성화된 Provider를 조회한다.
        List<String> providers = locManager.getProviders(true);
        for(int i=0; i < providers.size();i++)
         Log.i("Providers in LocationManager",providers.get(i));

        // Provider의 조건으로 최적의 Provider를 조회한다.
        Criteria criteria = new Criteria();
        criteria.setAccuracy(Criteria.ACCURACY_FINE);
        criteria.setAltitudeRequired(false);
        criteria.setBearingRequired(false);
        criteria.setCostAllowed(true);
        criteria.setPowerRequirement(Criteria.POWER_LOW);
        String provider = locManager.getBestProvider(criteria, true);
     Log.i("BestProvider",provider);

        // Provider에 저장된 최종 위치 정보를 조회한다.
     Location loc = locManager.getLastKnownLocation(provider);
        GeoPoint p = null;
        // Provider를 통해 현재 위치를 조회한다.
        if(loc != null){
         int lat = (int)(loc.getLatitude()* 1E6);
         int lng = (int)(loc.getLongitude() * 1E6);
         p = new GeoPoint(lat, lng);
         Log.i("GPS Information","[" + lat + "],[" + lng + "]");
        }
        else{ // 현재 위치를 조회할 수 없는 경우 기본값(명동)을 설정한다.
         Log.i("GeoPoint","Location is null");
         p = new GeoPoint(37559978,126985806);
        }
        Log.i("Address",getAddress(p));
       
        mc = mapView.getController();
        mc.animateTo(p);
        // Zoom Level을 설정한다. 1 ~ 21까지. 21이면 최대 확대
        mc.setZoom(15);
       
        // GPS 정보가 변경을 조회한다. GPS가 변경되면 onLocationChanged 호출
     locManager.requestLocationUpdates(provider, 1000L, 500.0f, this);
     
    }
   
    /**
     * LocationListener를 통해 GPS 정보가 변경되는 경우 호출
     */
 public void onLocationChanged(Location loc) {
  if (loc != null) {
         int lat = (int)(loc.getLatitude()* 1E6);
         int lng = (int)(loc.getLongitude() * 1E6);

   GeoPoint p = new GeoPoint(lat, lng);
   mc.animateTo(p);
         Log.d("onLocationChanged","[" + lat + "],[" + lng + "]");
            Log.i("Address",getAddress(p));
  }
 }

 public void onProviderDisabled(String provider) {
  // required for interface, not used
 }
 
 public void onProviderEnabled(String provider) {
  // required for interface, not used
 }
 
 public void onStatusChanged(String provider, int status, Bundle extras) {
  // required for interface, not used
 }
 
    @Override
    protected boolean isRouteDisplayed() {
        return false;
    }
   
    /**
     * 취치 정보로 해당 주소 정보를 조회한다.
     */
    private String getAddress(GeoPoint p){
        // 주소 정보를 조회합니다.
     // 한국 주소가 잘 안나오는 것 같다.
        Geocoder geocoder = new Geocoder(this, Locale.getDefault());
     StringBuilder sb = new StringBuilder();
        try{
         List<Address> addrList = geocoder.getFromLocation((double)(p.getLatitudeE6() / 1E6),
                       (double)(p.getLongitudeE6() / 1E6),
                                                         10);
            if (addrList.size() > 0) {
             Address addr = addrList.get(0);

             /* 잘 안나옴.
             for (int i = 0; i < addr.getMaxAddressLineIndex(); i++)
              sb.append(addr.getAddressLine(i)).append(", ");
             Log.i("addr.getAddressLine(i))", sb.toString());

             sb.append(addr.getAdminArea()).append(", ");
             if(addr.getAdminArea() != null)
             Log.i("addr.getAdminArea()", addr.getAdminArea());
             sb.append(addr.getSubAdminArea()).append(", ");
             if(addr.getSubAdminArea() != null)
             Log.i("addr.getSubAdminArea()", addr.getSubAdminArea());
             sb.append(addr.getPremises()).append(", ");
             if(addr.getPremises() != null)
             Log.i("addr.getPremises()", addr.getPremises());
             */
             sb.append(addr.getFeatureName()).append(", "); // 번지
             sb.append(addr.getLocality()).append(", "); // 시, 군
             sb.append(addr.getPostalCode()).append(", ");
             sb.append(addr.getCountryName());

             Log.i("Address", sb.toString());
             Toast.makeText(MapviewSample.this, sb.toString(), Toast.LENGTH_LONG).show();
            }

        }catch(IOException ioe){
         Log.e("Exception on getting Geocoder", ioe.getLocalizedMessage());
        }
     return sb.toString();
    }
}


 

Posted by 피의복수

1. aapt(Android Asset Packaging Tool)
  - 안드로이드 패키징 Tool
  - eclipse의 ADT를 사용하고 있다면 굳이 볼 필요는 없음.

2. adb(Android Debug Bridge)
  - emulator instance나 device의 상태를 관리하는 Tool
  - Clietn / Server로 구성(Server는 emulator나 Device의 daemon과 client와의 Communication을 관리한다.
  - Client를 실행하면 Server의 활성화를 확인하며, 활성화되지 않은 경우 Server를 시작한다.
  - Server는 local TCP port 5037에 bind한다.
  - Server는 emulator와 Device에서 사용하는 5555에서 5585까지의 port를 스캔한다.
  - emulator와 Device은 한쌍의 순차적 port를 사용하는데, emulator가 5554를 사용하면 adb는 5555를 사용한다.

  1) emulator/Device Instance조회
    > adb devices
[serialNumber] [state] -- state: offlline or device

List
of devices attached
emulator
-5554  device
emulator
-5556  device
emulator
-5558  device 
 
  2) 특정 emulator/Device에 Command 실행
    > adb -s <serialNumber> <command>
adb -s emulator-5556 install helloWorld.apk

  3) Application 설치
    > adb install <path_to_apk>

  4) Forwarding Port
    > adb forward tcp:<port> tcp:<port>

  5) copy file to or from emulator/device instance
    > adb pull <remote> <local>

    > adb push <local> <remote>

  6) 기타 Command는 http://developer.android.com/guide/developing/tools/adb.html#commandsummary 참조



 
Posted by 피의복수

Home Screen을 사용하는 Widget을 만드는 방법을 정리해 보자
Widget을 만들려면 다음과 같은 3가지가 필요하다.
1. AppWidgetProviderInfo
  Widget의 metadata를 정의한다. AppWidgetProvider class, Widget layout 그리고 업데이트 주기등을 XML에 정의한다.
/res/xml 에 해당 xml로 정의하면 된다.

2. AppWidgetProvider
  실제 Widget Application.
업데이트 등 처리

3. View Layout 
  초기 layout을 정의하며, 이는 optional

또한 Widget을 설정하기 위한 Widget Configuraion을 정이할 수 있다. (반드시 있어야 하는 것은 아님)

본격적으로 Widget을 만들어 볼까? 간단하게 Home에 시간을 나타내는 Widget을 만들어 본다.
(나중에 안 사실이지만 Time같이 초단위로 화면이 업데이트 되어야 하는 것들은 Widget으로 만들면 안된다. 업데이트 주기의 minimum값이 있는 것 같다.더 확인해봐야 겠지만 거의 30분정도...^^ 또 삽질했다)
1. Mainfest에 Widget Application 선언   
<application android:icon="@drawable/icon" android:label="@string/app_name">
        <receiver android:name=".TimeWidget" android:label="Timer Widget">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>
            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/time_widget_provider" />
        </receiver>
    </application>
    <uses-sdk android:minSdkVersion="5" />
  TimerWidget이라는 Class를 만들로 providerInfo는 /xml/time_widget_provider.xml을 사용하기로 정의한다.
그리고 WidgetProvider는 receiver의 기능을 하기 때문에 activity가 아닌 receiver로 정의하고, 안드로이드 예제처럼 별도의 receiver를 만들지 않고 WidgetProvider에서 receiver의 onReceive() method를 override하여 구현한다.

2. AppWidgetProviderInfo Metadata 추가하기
<appwidget-provider
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="146dp"
    android:initialLayout="@layout/main"
    android:updatePeriodMillis="1810000"
    android:minHeight="144dp"/>
초기 화면의 layout은 /layout/main.xml을 사용한다. 그리고 사이즈를 정의한다. 업데이트 주기는 30분 이상으로 설정한다.

3. Widget layout
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/LinearLayout01"
    android:layout_height="146dp"
    android:layout_width="144dp"
    android:orientation="horizontal">
    <TextView
        android:id="@+id/widget_timeview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:gravity="center_vertical|center_horizontal"
        android:textColor="@android:color/black"
        android:textSize="12pt"
    />
</LinearLayout>

  Time을 화면에 그리기 위한 TextView를 정의한다.

4. AppWidgetProvider를 상속한 class 생성

public class TimeWidget extends AppWidgetProvider {

    java.text.DateFormat timeformat = SimpleDateFormat.getTimeInstance( SimpleDateFormat.MEDIUM, Locale.getDefault() );

 @Override
    public void onUpdate( Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds )
    {
        updateTime( context, appWidgetManager);
    }
   
 @Override
    public void onReceive(Context context, Intent intent) {
        updateTime( context, AppWidgetManager.getInstance(context););
    }

    public void updateTime( Context context, AppWidgetManager appWidgetManager)
    {
        RemoteViews remoteViews1;
        ComponentName watchWidget;
       
        remoteViews1 = new RemoteViews( context.getPackageName(), R.layout.main );
        watchWidget = new ComponentName( context, WatchWidget.class );
        remoteViews1.setTextViewText( R.id.widget_timeview, timeformat.format( new Date()));
        appWidgetManager.updateAppWidget( watchWidget, remoteViews1 );
    }
   
}

 emulator에서 확인해 보니 실제 WIdget이 화면에 설정되면 onReceive() method가 호출되고 업데이트 주기가 되면 onUpdate() method가 호출됨을 확인하였다.

5. Widget 설정하기
  이렇게 만들어진 Widget을 어떻게 단말에 설정할까? emulator의 menu > add > widget을 선택하면 설정할 수 있는 widget list가 나온다 그리고 선택하면 된다.
근데 지울때는? 이거땜에 구글링을 했다.  Widget을 한 2초 정도 누르고 있으면 하단에 휴지통이 생긴다. 그럼 선택한 widget을 휴지통에 드래그하면 삭제된다.

주의) 삽질하고 알아낸 건데 업데이트 주기는 30분 이상으로 설정되어야 하는 것 같다.

Posted by 피의복수

1. emulator
  eclipse를 통해 구동하다보면 가끔씩 오류가 발생한다.
이럴 때는 당황하지 말고 SDK가 설치된 directory로 이동하여 emulator를 직접 구동해 보자

tools >emulator -avd avd_name 으로 emulator를 실행한 후에 실행 option에서 실행한 avd_name을 선택하면 오류가 없다.
참고로 자세한 사용법은 tools > emulator -help를 확인해 보셈^^
기존에 설치된 것을 초기화하기 위해서는 -wipe-data option을 추가해서 실행하면 되겠다.
Widget을 삭제하려면 드래그해서 휴지통에 넣으라는데....에뮬에서는 휴지통을 못 찾겠네.
==> 위젯을 좀 오래 클릭해보면 하단에 휴지통이 나타난다. 이 후 드래그해서 넣으면 끝^^

2. Log
  Java의 log4j처럼 유사한 Log를 제공한다.
Log.i(Information), Log.d(Debug)등을 활용하면 된다. 물론 System.out.println도 가능하다.
이렇게 남겨진 로그는 DDM을 이용해 확인해 보면 된다.
DDM은 어디 있을까?

tools > ddms  참 쉽죠~~잉

3. SDK Update
  eclipse에서 SDK Update하는 경우에는 발생하지 않는데, SDK의 "SDK Setup.exe"를 통해 Update를 할 경우 https://xxxxx/repository.xml에 대한 접근 오류가 나는 경우가 있다. (이것 땜에 또 삽질)
Window 사용자라면 사용자 계정 directory로 가봐라. ./android라는 directory가 보일 것이다.
그 밑에 보면 androidtool.cfg 가 있는데 여기에 sdkman.force.http=true 추가하면 그 뒤로는 접속이 될 것이다.
게속 삽질중...^^

Posted by 피의복수

단말 번호를 가져오려면 아래와 같이 해본다.
우선 manifest 파일에 권한을 부여해야 한다.
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

TelephonyManager telephony = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
telephony.getLine1Number(); // 단말 번호 가져오기
Log.i("Phone Number",telephony.getLine1Number());
단말 번호가 MSISDN이라고 하던데...국내에 들어오면 달라질 수 있을래나?

위의 TelephonyManager를 활용하면 다양한 단말의 정보를 가져올 수 있다.
MCC, MNC 및 기타 단말의 통신사 정보, Network 정보등을 조회할 수 있다.
단 Wi-Fi, Mobile을 사용하고 있는지에 대해서는 별도의 ConnectivityManager를 활용하면 될 것 같다.
Posted by 피의복수

Screen Size를 조회하기 위해서는 아래와 같이 해본다.

Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
Log.i("Screen",String.valueOf(width) + "*" + String.valueOf(height));

Posted by 피의복수

  안드로이드 graphics는 custom 2D library와 고성능 3D를 위한 OpenGL ES1.0을 제공한다.

Consider your option
  2D graphics를 그릴 때 다음 두 가지 중 하나를 사용하게 될 것이다.
1) Layout에서 View object로 graphic이나 animation을 그리는 경우.
  - 동적인 변화가 필요없는 graphic, 그리고 성능에 민감한 게임이 아닌 경우에 적합하다.
  - static graphic이나 미리정의된 animation을 출력할 경우에 사용할 수 있다.
2) Canvas에 직접 graphic을 그리는 경우
  - 규칙적으로 re-draw가 필요한 경우에 적합
  - UI Activity로서 동일한 Thread에서 layout에 custom View object를 생성 시 invalidate()를 호출하고 onDraw callback을 다루면 된다.
  - 다른 Thread에서는 SurfaceView를 관리하고 thread의 성능 맞추어 빠르게 Canvas에 그린다.

Simple Graphics Inside a View
  단순한 graphic(images, shapes, colors, pre-defined animation)을 그리는경우는 View 의 background에 그리거나 layout의 ImageView의 Content에 그린다.

Draw with a Canvas
 
특화된 drawing이나 graphic의 animation을 제어하는 application을 개발하려면, Canvas를 통해 drawing을 해야 한다.











Posted by 피의복수

  모든 application은 root directory에 AndroidManifest.xml filed을 가지고 있다 이 파일은 application에 대한 주요한 정보와 System이 applicaiton의 코드를 실생할 수 있기 전에 시스템이 가지고 있어야 할 정보를 안드로이드 system에 제출한다.

  1) Application의 Java package
  2) Application의 Component를 기술한다.
  3) 어떤 process가 applicaiton component를 다룰 것인지 결정한다.
  4) application이 API의 protected parr를 접속하기 위한, 그리고 다른 Application과 연동하기 위한 permission을 선언한다.
  5) Applicaiton의 Component롸 연동하기 위해 필요한 permission을 선언한다.
  6) Application이 필요한 Android API의 minimum level 선언
  7) link 해야할 library 리스트
  8) 테스트를 위해 필요한 instrumentation class(?????) - 이건 잘 모르겠는데?

Structure of the Manifest File
<?xml version="1.0" encoding="utf-8"?>
<manifest>
    <uses-permission />
    <permission />
    <permission-tree />
    <permission-group />
    <instrumentation />
    <uses-sdk />
    <uses-configuration /> 
    <uses-feature /> 
    <supports-screens /> 
    <application>
        <activity>
            <intent-filter>
                <action />
                <category />
                <data />
            </intent-filter>
            <meta-data />
        </activity>
        <activity-alias>
            <intent-filter> . . . </intent-filter>
            <meta-data />
        </activity-alias>
        <service>
            <intent-filter> . . . </intent-filter>
            <meta-data/>
        </service>
        <receiver>
            <intent-filter> . . . </intent-filter>
            <meta-data />
        </receiver>
        <provider>
            <grant-uri-permission />
            <path-permission />
            <meta-data />
        </provider>
        <uses-library />
    </application>
</manifest>

Element, Attribute 등에 대한 상세 내역은 가이드 문서를 참조하세요.

Sample
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.example"
      android:versionCode="2"
      android:versionName="1.1">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".HelloMapView"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
 
  <uses-library android:name="com.google.android.maps" /> ==> 외부 Library 사용
    </application>
    <uses-sdk android:minSdkVersion="3" />
 <uses-permission android:name="android.permission.INTERNET" /> ==> Network 사용을 위한 Permission
</manifest>

Posted by 피의복수

  안드로이드는 multi-process system으로 각 applicaiton은 자신의 process에서 실행한다. 대부분 Application과 System간의 security는 표준 Linux 기능 - Applicaiton에 할당되는 user and group ID - 을 통해 process level에서 수행된다. 부가적인 security 기능은 process가 수행하는 특정 업무에 대한 제한, data 접속에 대한 per-URI를 수행하는 "permission" mechanizm을 통해 제공된다.

Security Architecture
  안드로이드 security architecture의 주요 point는 application이 다른 applicatoin, OS 또는 user에 영향ㅇ르 미치는 어떠한 작업도 허용하지 않는 것이다.
Application의 process는 secure sandbox 이며, 다른 application을 중단 시킬수 없다. 다만 기존 sandbox에 제공되지 않는 부가적인 기능에 필요한 permission을 명백히 선언하는 경우는 제외이다. 이러한 permission은 다양한 방법으로 operating에의해 다루어 지는데, 인증을 기반으로 자동으로 허용/불허용하는 경우 또는 사용자에게 상기시키는 방법이 있다.
Application에 필요한 permission은 해당 Application에서 정적으로 선언되고, install전에 알려지며 그 후 변경되지 않는다.

Application Signing
  모든 안드로이드 Application(.apk file)은 private key를 가진 인증서로 sing되어야 한다. 이 인증서는 Application의 저작자를 식별해 준다. 인증서가 반드시 인증서 기관에서 sign될 필요는 없으며, 안드로이드 Application이 self-sing 인증서를 사용하는 것도 허용된다. 인증서는 단지 application 간의 신뢰있는 관계를 주기위해 사용되며, application이 설치될 수 있는지를 판단하기 위해 사용되는 것은 아니다.

User IDs and File Access
  Device에 설치되는 각각의 안드로이드 package(.apk file)은 자신의 unique Linix user ID를 가지며, 그것을 위한 sanbox를 생성하고, 가른 Applicaiton의 접근으로 부터 보호한다. user ID은 Device에 Applicaiton이 설치되는 경우에 할당을 받으며, Application의 생명주기 동안 존재하게 된다.

security에 대한 수행이 process level에서 이루어지므로 두개의 package의 코드가 동일한 procedd에서 실행될 수 없다.
하지만 동일한 user ID을 할당받기 위해 manifest file에 sharedUserId attribute를 사용할 수 있다. 이렇게 하면 두개의 package는 동일한 applicaiton으로 위급되어 동일한 user ID와 permission을 갖게된다. 동일한 서명으로 sign된 두개의 application만이 동일한 user ID를 사용할 수 있다.

  파일을 생성할때 MODE_WORLD_READABLE, MODE_WORLD_WRITABLE flag를 설정하면 다른 package가 같은 파일을 사용할 수 있게 된다.

Using Permission
  기본적으로 안드로이드 application은 permission이 없다.
Device의 protedted 기능을 사용하기 위해서는 manifest file에 하나 또는 그 이상의 <user-permission> tag를 사용하여 필요한 permission을 선언해 주어야 한다.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.app.myapp" >

    <uses-permission android:name="android.permission.RECEIVE_SMS" />

</manifest>

  Application 설치 시 application에서 필요로하는 permission은 package installer에 의해 권한이 부여된다. -  package installer는 permission을 선언한 application의 서명을 확인하거나 사용자의 입력을 통해 확인한다.


Posted by 피의복수

BLOG main image
일에 필요한 자료 by 피의복수

카테고리

분류 전체보기 (40)
프로그램이야기 (38)
outlook (1)
Twitter (0)
Mobile (0)
메일 (0)
시스템관리 (0)
프로그램환경설정 (0)
안드로이드 (32)
Augmented Reality (1)
iPhone (2)
모바일 SNS (0)
위치관련 (0)
MAC 사용하기 (1)
Postgres Plus® Advanced Ser.. (0)
Hadoop (0)
Hive (0)
Shell Script (0)
AngulaJs (0)
Spring Boot (0)
Database (0)
끄적끄적 (1)
취미 (0)
서비스이야기 (1)
빅데이터 (0)

최근에 올라온 글