2011. 2. 16. 09:39

안드로이드에서의 dp, dpi, px





dp를 평소에 즐겨사용했지만, 확실히 무슨 개념인지를 몰라 조사하던중에 

잘 정리되어있는 블로그를 발견 !


수정(101130)

단순히 px을 dp로 변환하고자 한다면 dp = px * 0.66625로 계산한다.(해상도480*800 기준)

480*800 px => 320*533 dp이다.




출처 : http://blog.naver.com/dythmall?Redirect=Log&logNo=30096162077


dp (dip, density independent pixel) 은 안드로이드에서 여러 화면 크기를 서포트 해주기 위해서 만든 유닛이다.

만약 많은 화면에서 내가 만든 레이아웃이 제대로 보이길 원한다면 dp를 써서 화면을 만드는 것이 좋다.

우선 주의할 것은 안드로이드는 160dpi를 기본으로 생각한다.
이것은 (320 x 480) 스크린의 density를 나다내는 것이다.

그러므로 480 x 800  (240dpi)의 스크린을 dp로 나타낸다면 320 x 533 (480 / 1.5, 800 / 1.5) 이 된다.
dp를 이용해서 레이아웃을 잡을때 이 수치를 꼭 기억하고 잡자!
dp로 레이아웃을 잡을때 버튼을 4개 만들고 LinearLayout (horizontal)에 넣은뒤 
width를 80dp (80*4 = 320)로 잡으면 4개가 같은 넓이의 버튼이 된다.
하지만 480을 생각하고 120dp 라고 넓이를 잡으면 오른쪽 1개 버튼은 화면을 지나서 보이는걸 볼것 이다.

그렇다면 코드상에서 dp를 pixel로 바꾸려면 어떻게 해야할까?
식은 pixel = dp * (density / 160)

dp는 원하는 값이고 density 는 
DisplayMetrics outMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(outMetrics);
outMetrics.densityDpi 
로 가지고 올 수 있다.

여기서 outMetrics.density 라는 변수가 있는데 이것은 (density / 160) 의 결과 값이 들어 있다.
그러므로 식은 
pixel = dp * outMetrics.density 
가 된다.

여기서 코드상에 dp를 pixel로 변한하는 식이 필요한 이유는,
안드로이드 레이아웃을 코드상에서 고치면 dp를 쓸 수 없기 때문이다.
모든 setWidth나 setHeight 등등은 인자를 pixel로 받는다.
2011. 1. 5. 14:59

안드로이드 수신/발신 정보 가져오기 android call log





폰 사용량을 알기 위해 안드로이드 수신/발신 정보를 가져오려고 한다.

 

안드로이드 수신/발신 정보 가져오기 CallLog 이용

  1. private void getHistory() {
  2. String[] projection = { CallLog.Calls.CONTENT_TYPE, CallLog.Calls.NUMBER, CallLog.Calls.DURATION, CallLog.Calls.DATE };
               
    Cursor cur = managedQuery(CallLog.Calls.CONTENT_URI, null, CallLog.Calls.TYPE + "= ?",
                    new String[]{ String.valueOf(CallLog.Calls.OUTGOING_TYPE) },                CallLog.Calls.DEFAULT_SORT_ORDER);
           
    Log.d("db count=", String.valueOf(cur.getCount()));
    Log.d("db count=", CallLog.Calls.CONTENT_ITEM_TYPE);
    Log.d("db count=", CallLog.Calls.CONTENT_TYPE);

    if(cur.moveToFirst() && cur.getCount() > 0) {
       while(cur.isAfterLast() == false) {
          StringBuffer sb = new StringBuffer();

          sb.append("call type=").append(cur.getString(cur.getColumnIndex(CallLog.Calls.TYPE)));
          sb.append(", cashed name=").append(cur.getString(cur.getColumnIndex(CallLog.Calls.CACHED_NAME)));
          sb.append(", content number=").append(cur.getString(cur.getColumnIndex(CallLog.Calls.NUMBER)));
          sb.append(", duration=").append(cur.getString(cur.getColumnIndex(CallLog.Calls.DURATION)));
          sb.append(", new=").append(cur.getString(cur.getColumnIndex(CallLog.Calls.NEW)));
          sb.append(", date=").append(timeToString(cur.getLong(cur.getColumnIndex(CallLog.Calls.DATE)))).append("]");
          cur.moveToNext();
          Log.d("call history[", sb.toString());
         
          }
       }
  3. }
  4. androidManifest.xml에 추가
  5. <uses-permission android:name="android.permission.READ_CONTACTS" />

 

아주 편리하게도 api가 있다. CallLog를 이용해서 DB 에 저장된 내용을 가져올 수 있다.

주석 없이도 볼 수 있을 거란 생각에 주석은 생략한다.

 

CallLog의 경우 사용자가 전화통화내역 삭제를 누를 경우 볼 수 없다.

그리하야 별도로 call log 를 쌓으려고 한다.

방법은 직접 action을 감지하고, 통화 내역을 계산하여 별도의 DB에 쌓는 것이다.

안드로이드 수신/발신 정보 모니터링 하기

  1.     private String LOG_TAG = "CheckCall";
        private static int pState = TelephonyManager.CALL_STATE_IDLE;
  2.  
  3. public void onReceive(Context context, final Intent intent) {
            TelephonyManager telManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);

            telManager.listen(new PhoneStateListener(){
                public void onCallStateChanged(int state, String incomingNumber){
                        if(state != pState){
                            if(state == TelephonyManager.CALL_STATE_IDLE){
                               Toast.makeText(mContext, "IDLE" + String.valueOf(System.currentTimeMillis()), Toast.LENGTH_SHORT).show();
                            }
                            else if(state == TelephonyManager.CALL_STATE_RINGING){
                                Toast.makeText(mContext, "RINGING" + String.valueOf(System.currentTimeMillis() +incomingNumber), Toast.LENGTH_SHORT).show();
                            }
                            else if(state == TelephonyManager.CALL_STATE_OFFHOOK){
                               Toast.makeText(mContext, "OFFHOOK" + String.valueOf(System.currentTimeMillis()), Toast.LENGTH_SHORT).show();
                            }
                            pState = state;
                        }
                }
            }, PhoneStateListener.LISTEN_CALL_STATE);
           
            if(Intent.ACTION_NEW_OUTGOING_CALL.equals(intent.getAction())){
                Log.i(LOG_TAG, "out=" + intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER));
            }
        }
  4.  
  5. AndroidManifest.xml

  6. <receiver android:name=class name>
            <intent-filter>
                  <action android:name="android.intent.action.PHONE_STATE" />
                  <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
            </intent-filter>
    </receiver>

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

  8.  
  9. 참고자료

 

이정도 코드 역시 주석이 없이도 쉬이 할 수 있을 것 같아서 그냥 붙여 넣었다. 매니페스트에 권한과 인텐트 필터 넣는 것을 몰라 한참을 리서치 했다.

 

  1. state

  2. 발신시
  3. Intent.ACTION_NEW_OUTGOING_CALL -> offhook -> idle

  4. 수신시
  5. Ring -> offhook -> idle

 

 원문 :http://whdnfl21.springnote.com/pages/6833219

2011. 1. 3. 11:47

다이얼로그 생성시 BadTokenException 이슈





요즘 어플리케이션 개발에 한창입니다. 점점 안드로이드 플랫폼에 익숙해져 가는것 같습니다. 그러나 때로는 명확해 보이는 코드가 오류를 던져 대면 당혹스러워 지는군요. 이번 경우가 그렀습니다.

오류 발생 코드

  1. public void onCreate( Bundle $bundle ) {   
  2.         super.onCreate( $bundle ) ;   
  3.         setContentView( R.layout.ui_setting ) ;   
  4.            
  5.         Button dialogShowBtn = (Button) findViewById( R.id.dialogShowBtn ) ;   
  6.         dialogShowBtn.setOnClickListener( this ) ;   
  7.     }   
  8.   
  9.     public void onClick(View v) {   
  10.         // TODO Auto-generated method stub   
  11.         switch( v.getId() ) {   
  12.         case R.id.dialogShowBtn :   
  13.             CustomDialog customDialog = new CustomDialog( getApplicationContext() ) ;   
  14.             customDialog.show() ;   
  15.             break ;   
  16.         }   
  17.     }  

오류 메세지

Uncaught handler: thread main exiting due to uncaught exception android.view.WindowManager$BadTokenException: Unable to add window — token null is not for an application

해결책

  1. public void onCreate( Bundle $bundle ) {   
  2.         super.onCreate( $bundle ) ;   
  3.         setContentView( R.layout.ui_setting ) ;   
  4.            
  5.         Button dialogShowBtn = (Button) findViewById( R.id.dialogShowBtn ) ;   
  6.         dialogShowBtn.setOnClickListener( this ) ;   
  7.     }   
  8.   
  9.     public void onClick(View v) {   
  10.         // TODO Auto-generated method stub   
  11.         switch( v.getId() ) {   
  12.         case R.id.dialogShowBtn :   
  13.             CustomDialog customDialog = new CustomDialog( this ) ;   
  14.             customDialog.show() ;   
  15.             break ;   
  16.         }   
  17.     }  

토의

일단 다이얼로그의 생성자에 인자로 보내는 Context를 getApplicationContext()로 얻어서 넘기는 대신에, Activity 자신을 직접 넘김으로써 오류를 잡는데는 성공했지만 아직까지는 명확하게 왜 이렇게 해야 하는지 알아가는 중입니다. 다만, 레퍼런스를 읽어보면 다이얼로그는 Owner Activity에 종속적으로 실행이 된다고 하는데 위에 오류 발생하는 코드를 보면 Activity를 알 길이 없습니다.

하지만 그렇다고 아래와 같은 코드도 BadTokenException 오류를 발생하기는 마찬가지였습니다.

  1. public void onCreate( Bundle $bundle ) {   
  2.         super.onCreate( $bundle ) ;   
  3.         setContentView( R.layout.ui_setting ) ;   
  4.            
  5.         Button dialogShowBtn = (Button) findViewById( R.id.dialogShowBtn ) ;   
  6.         dialogShowBtn.setOnClickListener( this ) ;   
  7.     }   
  8.   
  9.     public void onClick(View v) {   
  10.         // TODO Auto-generated method stub   
  11.         switch( v.getId() ) {   
  12.         case R.id.dialogShowBtn :   
  13.             CustomDialog customDialog = new CustomDialog( getApplicationContext() ) ;   
  14.             customDialog.setOwnerActivity( this ) ;   
  15.             customDialog.show() ;   
  16.             break ;   
  17.         }   
  18.     }  

관련예제