2012년 3월 1일 목요일

수신 및 발신 전화번호 알아내기

오늘은 수신 및 발신 전화번호를 알아내 보도록 하겠습니다.

1. 수신 전화번호 알아내기
  • 두가지 방법이 있습니다. 두가지 방법다 Manifest.xml에 다음의 permission이 등록되어 있어야 합니다.
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>


A. TelephonyManager 및 PhoneStateListener 이용하기
  • Activity나 Service에서 간단한 코드로 이를 알아 낼 수 있습니다.
  • 우선, onCreate() 에서 TelephonyManager를 얻어냅니다.
TelephonyManager telephonyMgr = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
TelephonyManager  telephonyMgr.listen(new PhoneStateListener(){

            public void onCallStateChanged(int state, String incommingNumber){

                   switch(state) {
                   case TelephonyManager.CALL_STATE_RINGING:
                           Log.d(TAG, " CALL_STATE_RINGING.:" + incommingNumber);
                           break;
 
                    case TelephonyManager.CALL_STATE_IDLE:
                           Log.d(TAG,"CALL_STATE_IDLE ");
                           break;

                   case TelephonyManager.CALL_STATE_OFFHOOK:
                            Log.d(TAG,"CALL_STATE_OFFHOOK ");
                            break;
                   }
             }
}, PhoneStateListener.LISTEN_CALL_STATE);

  • PhoneStateListener는 Class 형태 이므로, onCallStateChanged()를 override하시면 됩니다.
  • incommingNumber안에 String형태로 넘어오기에 구현하기는 너무 간단합니다.

B. BroadcastReceiver 이용하기
  • Manifest.xml에 BroadcastReceiver를 등록합니다.
       <receiver android:name="my.test.CallStateListener">
            <intent-filter>
                <action android:name="android.intent.action.PHONE_STATE"/>            </intent-filter>
        </receiver>
  • 이제 CallStateListener를 구현합니다.
public class CallStateListener extends BroadcastReceiver {
      
       public String TAG = getClass().getSimpleName();

       @Override
       public void onReceive(Context context, Intent received) {

             String action = received.getAction();
             Bundle bundle = received.getExtras();

             if(action.equals("android.intent.action.PHONE_STATE")){

                    String state = bundle.getString(TelephonyManager.EXTRA_STATE);

                    if(state.equals(TelephonyManager.EXTRA_STATE_IDLE)){
 
                             Log.d(TAG, " EXTRA_STATE_IDLE ");
 
                    }else if(state.equals(TelephonyManager.EXTRA_STATE_RINGING)){
 
                             Log.d(TAG, " EXTRA_STATE_RINGING INCOMMING NUMBER : " + bundle.getString(TelephonyManager.EXTRA_INCOMING_NUMBER)); 
                    }else if(state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)){
 
                             Log.d(TAG, " EXTRA_STATE_OFFHOOK ");
                    }
             }
       }
}
  • 실제 폰을 가지고 위 코드를 실행해 보시면
  • RINGING -> OFFHOOK -> IDLE 순으로 status가 변하는 것을 볼 수 있으며, RINGING 에서만 number를 얻을 수 있습니다.
2. 발신 전화번호 알아내기
  • 발신번호는 TelephonyManager 및 PhoneStateListener를 이용해서는 얻을 수 없습니다.
  • 위의 B. 형태인 BroadcastReceiver를 이용해야 합니다.
  • Manifest.xml에 다음의 permission이 등록되어 있어야 합니다.
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>

  • 위에서 만들어 놓았던 BroadcastReceiver를 다시 이용합니다.
<receiver android:name="my.test.CallStateListener">
              <intent-filter>
                        <action android:name="android.intent.action.NEW_OUTGOING_CALL"/>                        
                        <action android:name="android.intent.action.PHONE_STATE"/>             
              </intent-filter>
</receiver>

  • 이제 CallStateListener에 구현합니다.
public class CallStateListener extends BroadcastReceiver {

      public String TAG = getClass().getSimpleName();

      @Override
       public void onReceive(Context context, Intent received) {

             String action = received.getAction();
             Bundle bundle = received.getExtras();

             if(action.equals("android.intent.action.PHONE_STATE")){

                      String state = bundle.getString(TelephonyManager.EXTRA_STATE);

                      if(state.equals(TelephonyManager.EXTRA_STATE_IDLE)){

                              Log.d(TAG, " EXTRA_STATE_IDLE ");

                       }else if(state.equals(TelephonyManager.EXTRA_STATE_RINGING)){

                              Log.d(TAG, " EXTRA_STATE_RINGING INCOMMING NUMBER : " + bundle.getString(TelephonyManager.EXTRA_INCOMING_NUMBER));
                        }else if(state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)){

                              Log.d(TAG, " EXTRA_STATE_OFFHOOK ");
                        }
                }else if(action.equals(Intent.ACTION_NEW_OUTGOING_CALL)){

                        Log.d(TAG, " OUTGOING CALL : " + bundle.getString(Intent.EXTRA_PHONE_NUMBER));
                }
         }
}

  • 빨간색으로 표시된 부분입니다.
  • 위 로그를 보자면  OUTGOING_CALL -> OFFHOOK -> IDLE 의 순서로 status가 바뀝니다.
  • 그리 어렵지는 않지요?

2012년 2월 26일 일요일

AppWidget Update 주기에 대하여

AppWidget의 update 주기에 대해 말씀드리겠습니다.

update 주기를 설정하는 방법은 여러가지가 있겠으나, 대략 다음중 하나를 선택하실 겁니다.

1. appwidget-provider XML 에서 updatePeriodMillis="0"
2. appwidget-provider XML 에서 updatePeriodMillis="원하는 시간만큼"
3. 아니면 프로그램 내에서 직접 AlarmManager를 통해

1. updatePeriodMillis="0"의 의미
- 이렇게 setting하면 3번과 같은 의미를 같습니다. onUpdate()는 프로그램에서 알아서 해야 하다는 말 입니다.
- 프로그램내에서 AppWidget 실행시 한번만 onUpdate()를 call 합니다.
- 이 후에 한번도 onUpdate()를 call하지 않으면, 상당한 시간이 흐른 후에 AppWidget에 setting해 놓은 기능들은, 특히 pending intent는 사라지게 되며 AppWidget은 기능을 제대로 작동되지 않습니다. 꼭 명심하세요.

2. updatePeriodMillis="원하는 시간만큼"
- 원하는 시간에 System에서 onUpdate() call 하게 되지만, 그 주기는 확신할 수는 없습니다.
- 최소시간은 30분입니다. 단위가 millisecond이니 30분 x 60초 x 1000=1800000 가 되겠습니다.
- 아무리 짧게 주어도 효과는 없습니다.

3. AlarmManager를 통해
- 2번 처럼 원하는 시간을 정할 수는 있을겁니다.
- 너무 짧은 시간을 주게 되면, 아마도 Failed Binder Transaction!!! 을 만나게 됩니다.
- AppWidget은 참 편하고 강력하며 iphone과 차별화된 기능이지만, 제가 보기에는 상당히 무겁습니다.
- 짧은 시간에 화면을 update하는 것은 금물입니다.

2012년 2월 19일 일요일

AppWidget 구현시 가장 중요한 것은?

AppWidget 구현 시 XXXConfigure, XXXProvider, Service 정말 많은 것을 구현해야 합니다.
그중에서도 Widget의 구성요소를 사용자로하여금 설정할 수 있게 해 주는 것이 XXXConfigure 인데요..

XXXConfigure를 만드는 순간 우리는 유령 Widget에 시달려야 합니다.

XXXConfigure는 Activity형태라는 것 다 아실테고..
User가 Activity를 빠져나가는 방법은 여러가지가 있을 수 있습니다.

1. home 버튼
2. back 버튼
3. 취소버튼 - 친절하게 XXXConfigure 화면에서 취소버튼을 만들은 경우
4. 그외 상상에 맞기겠습니다.

메뉴얼이나 developer site에 가서 보면

XXXConfigure내에서 Widget 만들기를 취소하는 것은 XXXConfigure에 setResult()에 RESULT_CANCELED를 setting하는 것으로 되어 있으나...아무리 이렇게 해봐도 유령은 계속 계속 생기게 됩니다.

현재 얼마나 많은 appWidget이 host에 등록 되어 있는지 대한 코드는 다음과 같습니다.

ComponentName compName = new ComponentName(this, XXXProvider.class);
int appWidgetIds[] = AppWidgetManager.getInstance(this).getAppWidgetIds(compName);
AppWidgetHost host = new AppWidgetHost(this, 0);

for(int i = 0; i < appWidgetIds.length; i++){
     Log.d(TAG, "[" + i + "] " + appWidgetIds[i]);
}

이코드를 XXXConfigure onCreate()에 넣어 보시면 현재 얼마나 많은 위젯들이 있는지 알 수 있겠죠.

유령은 XXXConfigure를 실행하고 setResult(RESULT_OK, intent); 가 호출되지 않은 상태인데요, 화면에 위젯이 표시되지 않고 host에 id로만 존재하는 놈을 말합니다.

그럼 어떻게 지울 수 있을까요....?

항상, onPause() 아니면 onDestroy()에서 (onPause()가 나을 것 같아요..) 유령을 찾아 지워야 합니다.

지우는 코드는 위에서 언급한 widgetId를 보는 코드와 동일합니다.

ComponentName compName = new ComponentName(this, XXXProvider.class);
int appWidgetIds[] =AppWidgetManager.getInstance(this).getAppWidgetIds(compName);
AppWidgetHost host = new AppWidgetHost(this, 0);

for(int i = 0; i < appWidgetIds.length; i++){
        Log.d(TAG, "[" + i + "] " + appWidgetIds[i]);
        if(appWidgetIds[i]가 유령입니까?){
              host.deleteAppWidgetId(appWidgetIds[i]);
        }else{
              // do nothing..
        }
}

빨간색으로 칠한 부분을 생각해 보겠습니다.

화면에 widget이 생성되어 있는지 아닌지 알아내는 방법을 못찾았습니다.(좀 알려주세요.)

그걸 안다면 이런짓을 하지는 않을 겁니다. 그러나 방법을 모르기에 제대로 생성된(즉, User가 XXXConfigure화면에서 OK버튼을 눌렀을때) widget과 아닌것을 구분하는 구분자 정도는 widget 생성시 만들어서 어디에 저장해 놓아야 합니다. 가장 편리하고 쉬운 것은 SharedPreferences를 이용하는 것입니다.

즉, 제대로된 생성된 appWidget의 경우, SharedPreferences 에 제대로 된놈인가를 표시하는 것이죠....

appWidgetIds[i] 가 유령인지 아닌지 판단시 SharedPreferences에 등록이 되어 있는지를 체크 하는 것입니다.

유령체크코드는 application마다 다르기에 여기서는 언급은 하지 않지만요...

조금은 지저분하고 googling을 해봐도 딱히 유령을 가장 깔끔하게 지우는 방법을 찾지는 못했습니다.

암튼 이만.... 댓글 달아 주시면 답변 드리겠습니다.



2012년 1월 11일 수요일

AppWidget에서 사용할 수 있는것은?

AppWidget에서 사용할 수 있는 Layout
FrameLayout,
LinearLayout
RelativeLayout.

AppWidget에서 사용할 수 있는 Widget들..
AnalogClock,
Button,
Chromometer,
ImageButton,
ImageView,
ProgressBar
TextView

너무 없죠.. 수수께끼 하는 것도 아니고..
그래도 만들어 볼만한게 AppWidget입니다.

그러나 3.x, 4.x로 넘어가면서 사용할 수 있는게 더 많아 졌다니...

실행중인 Task별 Activity 보기..

1. AndroidManifest.xml에 Permission 처리
    -  <uses-permission android:name="android.permission.GET_TASKS"/>

2. 다음과 같이 코딩을 하세요..
  
    // ActivityManager를 얻고..
   ActivityManager actMgr = (ActivityManager)AppPinScreenLockActivity.this.getSystemService(Activity.ACTIVITY_SERVICE);
   
   
    List<RunningTaskInfo> info = actMgr.getRunningTasks(7);
   
    for (Iterator<RunningTaskInfo> iterator = info.iterator(); iterator.hasNext();)  {
         RunningTaskInfo runningTaskInfo = (RunningTaskInfo) iterator.next();
         Log.d(TAG, "" + runningTaskInfo.topActivity.getClassName());
    }

2012년 1월 7일 토요일

Implementing Dynamic Tab Widget

1. layout xml file (main.xml) 만들기

<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/tabhost" 
    android:layout_height="fill_parent"
    android:layout_width="fill_parent">
     <LinearLayout
         android:layout_width="fill_parent"
         android:layout_height="fill_parent"
         android:orientation="vertical"
         android:padding="5dp">

         <TabWidget
             android:id="@android:id/tabs"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"/>
          <FrameLayout
             android:id="@android:id/tabcontent"             android:layout_height="wrap_content"
             android:layout_width="fill_parent"
             android:padding="5dp"/>
    </LinearLayout>
</TabHost>
- xml의 계층을 건들지 마시고 각 id의 name은 미리 android에 선언된 이름이므로 바꾸지 말아야 한다.

2. MainActivity 만들기
    - Tab을 만들기 위해서는 우선 TabActivity를 상속받은 Activity를 만들고,  TabHost.TabContentFactory 를 implement해야 한다.

public class TabTestActivity extends TabActivity implements TabHost.TabContentFactory {
          
             .......
       @Override
       public void onCreate(Bundle savedInstanceState) {

           super.onCreate(savedInstanceState);
           // 위에서 만든 main.xml           setContentView(R.layout.main);
           // main.xml 내에 있는 @android:id/tabhost 
           TabHost tabHost = getTabHost();    
       
           // 1. 새로운 tab생성. 물론 생성되는 모든 TabSpec들은 @android:id/tabs 내에 포함되게 됨
           TabHost.TabSpec tabSpec = tabHost.newTabSpec(getString(R.string.str_appranker_tab1));
           // 2. 이부분에서 단순히 String만을 주게 되면 Tab Widget에 String 만 표시된다.

           // 만약, 더 다양한 효과를 주고 싶으면 이부분에 View를 넘기면 된다.
           tabSpec.setIndicator(getString(R.string.str_appranker_tab1));
           // 3. 이부분이 상단 Tab을 눌렀을때 하단에 표시되는 내용부분이다.
           // 직접, View를 넘길수 없으며 Dynamic하게 생성되는 View들을 FrameLayout내에 넣어야 하기에 TabContentFactory를 이용하게 된다.
            tabSpec.setContent(this);
            // 4. TabHost에 생성한 Tab을 넣는다.
            // Tab을 더 생성하고 싶으면 1~4 다시 수행.            tabHost.addTab(tabSpec);
       }

       @Override
       public View createTabContent(String tag) {

           LayoutInflater inflater = getLayoutInflater();
           // Tab을 구별할 수 있는 tag 값에 따라 다른 View를 R.layout.content inflate해서 넣으면 되며, 가장 중요한 것은 @android:id/tabcontent의 하위 view로 rootview를 정의해야한다는것..
           // 그래야 나중에 framelayout에서 보이고 안보이고를 결정해 주죠......
           if(tag.equals(getString(R.string.str_tab1))){
                     return inflater.inflate(R.layout.content, getTabHost().getTabContentView()); 
           }
           return null;
       }
}


-- 근데요.. 하나의 activity내에서 FrameLayout에서 보여주게될 복잡한 view들을 control한다는것은 조금 힘들고 지저분해 보이네요...
-- tabSpec.setContent()에 Intent를 넣어 Activity가 실행되게하여 MVC모델에 충실하게 만드는 것은 어떨런지.....

2012년 1월 2일 월요일

intent-filter의 Grouping..?

안드로이드가 배우기 힘든것은 될것 같은데 안되는 것들이 있고, 이를 극복하기 위해서 참고할 만한 글을 찾기에 너무 힘들고.... 내가 직접 bug-around 해야하고...
안드로이드 개발자에게 직접 묻기도 뭐하고...

암튼, 오늘 찾아 낸 거...

intent-filter도 grouping이 필요하다는 것.. (나만 몰랐나?, 원래 해야하나? 누구든 알면 알려줘여..)

PACKAGE_ 관련 action과 BOOT_COMPLETED, USER_PRESENT는 다른 group으로 묶어야 제대로 동작을 합니다.

말하자면 아래와 같이.... 참고 하세요..

       <receiver android:name=".XXXBootLauncher">
            <intent-filter>
                <action android:name="android.intent.action.PACKAGE_ADDED"/>
                <action android:name="android.intent.action.PACKAGE_REMOVED"/>
                <data android:scheme="package" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
                <action android:name="android.intent.action.USER_PRESENT"/>
            </intent-filter>
        </receiver>

2012년 1월 1일 일요일

Package 삭제 추가에서 PackageName알아내기

등록된 BroadcastReceiver로 Package의 추가 삭제 intent가 전달되는 데요..
packagename은 Uri형태로 전달 됩니다.

즉, package:com.helloaxl.xxx 형태인데요...

이때 packageName을 정확히 얻어 올려면,

intent.getData().getSchemeSpecificPart() 를 호출해야 com.helloaxl.xxx를 얻어 올수 있답니다.

Package 추가 삭제 알아내기

 Manifest 파일에 다음과 같이 receiver를 등록합니다.

<receiver android:name=".XXXReceiver">
   <intent-filter>
     <action android:name="android.intent.action.PACKAGE_ADDED" />
     <action android:name="android.intent.action.PACKAGE_REMOVED" />
     <data android:scheme="package" />
  </intent-filter>
</receiver>

여기서 가장 중요한것은 <data android:scheme="package" />...
빼먹지 마시라는거...
 

2011년 12월 31일 토요일

logcat option 및 filter 제대로 셋팅하기

1. cmd 실행
2. chcp 65001 실행
3. adb logcat  option filter 실행

-s              Set default filter to silent.
Like specifying filterspec '*:s'
-f <filename>   Log to file. Default to stdout
-r [<kbytes>]   Rotate log every kbytes. (16 if unspecified). Requires -f
-n <count>      Sets max number of rotated logs to <count>, default 4
-v <format>     Sets the log print format, where <format> is one of:

brief process tag thread raw time threadtime long

-c              clear (flush) the entire log and exit
-d              dump the log and then exit (don't block)
-t <count>      print only the most recent <count> lines (implies -d)
-g              get the size of the log's ring buffer and exit
-b <buffer>     request alternate ring buffer
('main' (default), 'radio', 'events')
-B              output the log in binary
<Filter Spec.....>
filterspecs are a series of
<tag>[:priority]

where <tag> is a log component tag (or * for all) and priority is:
V    Verbose
D    Debug
I    Info
W    Warn
E    Error
F    Fatal
S    Silent (supress all output)

<tag>[:priority] 이부분에 대한 설명을 하자면...

public static final String TAG = "HelloAxlActivity"; <---- 이부분에서 선언한 태크
Log.d(TAG, "hello...."); <--- 이렇게 프로그램에서 사용하죠..

adb logcat HelloAxlActivity 가 되는 거죠...

그런데, 이상하죠.. 온동네 tag들이 다나옵니다. 이거 하라는 데로 했는데... 헐...
한가지가 더 있답니다.
마지막으로 젤 중요한것은요... 저도 정말 알고 싶어 했던거...

adb logcat HelloAxlActivity *:S

뒤에 *:S 로 HelloAxlActivity이후 한칸띈 후 마무리를 해주셔야 비로소 HelloAxlActivity Tag만을 가진 로그가 나옵니다. (이거 버근가?)

암튼, priority는 tag이후에 붙여 주시면 되겠습니다.

adb logcat HelloAxlActivity:I *:S  이렇게요...

이것과 똑같이 option을 이용해서 할 수도 있는데요...

adb logcat -s HelloAxlActivity:I

-s 는 silent로 만드는 option입니다.

위와 같이 하면 중간에
--------- beginning of /dev/log/system
.....
--------- beginning of /dev/log/main

이런식으로 두가지의 logfile의 내용을 한꺼번에 보여주는데요..

이는 옵션을 주어 버퍼를 선택할 수 있습니다.
adb logcat -b main -s HelloAxlActivity:I 이런식으로요..

이상이구요. 질문있으시면 알려주세요.

2011년 11월 20일 일요일

Failed Binder Transaction!!!

Activity간의 data 이동시 간혹

JavaBinder가 "Failed Binder Transaction!!!" 라는 신음을 내는데..

이는 안드로이드의 data 크기의 제약사항 때문에 발생하는데.. 그 크기가 약100Kb미만이랍니다.

데이터 사이즈를 어떻게든 줄여야 하는데.....

Intent에 extra data에 넣는 부분도 줄여야 하는데.. bitmap의 경우에는 당연히 external sdcard를 이용하여 URI로 넣어 주어 사이즈를 줄어야 한다.

제가 겪은 바로는 RemoveViews에도 이와 같은 현상이 일어 나는데...

이때도 마찬가지로 setImageViewBitmap() 대신 setImageViewUri()로 바꿔 넣어 주어야 한다.

그럼 어떻게 바꿀수 있냐고..... 다음에... 저도 해결좀 하구요..

2011년 11월 19일 토요일

Android Service 의 형태

Android에서 Background processing을 위해서는  Service를 사용해야 하는데,

service는 started service와 bind service로 나뉘며... 지금은 started service를 말하고자 한다.

onStartCommand()가 호출되고 나면 service의 형태가 어떤지를 integer값을 리턴하여 시스템에게 알려주어야 하는데 다음 3가지 정도면 원하고자 하는 서비스를 만들 수 있다.

서비스는 언제든 시스템에 의해 kill될 수 있으며, 상황이 나아지면 다시 시작된다.

1. START_STICKY
    - 서비스 종료시 시스템이 다시 서비스를 재시작 하게 되지만 종료시 넘어 왔던 intent 는 null로 초기화된다.

2. START_NOT_STICKY
   - 서비스 종료 후 자동으로 이 서비스를 시작하지는 않는다.

3. START_REDELIVER_INTENT
   - 서비스 종료 후 다시 재시작할 때 서비스 시작당시 넘어온 인텐트를 다시 넘겨 준다.

2011년 11월 17일 목요일

IMEI (International Mobile Equipment Identity) 란?

각각의 android store마다 불법복제 방지를 위해 license를 체크하는데,
삼성앱스에서는 단말기계마다 고유한 번호인 IMEI(International Mobile Equipment Identity, 코드14자 + 체크용1자=15자의 숫자)를 체크한다.

자기 android 폰의 IMEI를 체크하는 방식은 다음과 같다.

import android.telephony.TelephonyManager;
import android.content.Context;
 
{
TelephonyManager telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
  Log.d(TAG, " IMEI=" + telephonyManager.getDeviceId());
}
 
1. 우선 TelephonyManager를 얻고
2. getDeviceId()를 call하면 된다.
 
위의 code를 android 소스에 넣어 한번 찍어 보면 끝...

2011년 11월 16일 수요일

미얀마인들의 수호신이랍니다.

말레이시아 페낭의 미얀마 사원에 가면 지구본을 발로 밟고 있는 괴상하게 생긴 동물 2마리가 있다. 이것은 미얀마인들의 수호신으로 여러가지 형상의 동물모양을 하고 있어 이채롭다. 코는 코끼리코, 뿔은 용뿔, 발은 말발굽 그리고 몸통은 생선등으로 이루어져있다. 참고로 이 지구본은 기부함이다.

여자의 변신은 무죄?

 
화장의 달인, 180도 바뀌는 화장 성형 '세상에'

화장의 달인이 오직 메이크업만을 이용, 180도 달라진 얼굴로 '화장 성형'의 진수를 보여줬다.

5일 방송된 SBS '놀라운 대회-스타킹(이하 '스타킹')'에서는 종로의 여신 김보배 씨와 마포구의 여신 박수혜 씨가 등장해 놀라운 화장의 기술을 선보였다.

이들은 첫 등장부터 모두를 충격에 휩싸이게 만들었다. 사진 속의 예쁜 모습을 찾아볼 수 없는 초췌한 모습으로 스튜디오에 등장한 것.

그러나 짤막하게 주어진 시간 동안 화장을 통해 완벽한 변신을 시도했다. 달라진 모습을 보며 연예인 게스트들은 성형을 한 것이 아니냐며 의심을 금치 못했다. 또 성형 전문가 역시 "자신의 단점을 정확하게 알고 있는 것 같다. 특히 눈 화장을 잘 한 것 같다"며 칭찬을 아끼지 않았다.

한편 박수혜 씨는 남성들에게 "여자의 화장에 속지 말아라. 결혼 전 화장 전체를 지워보고 결혼해라"라는 충고를 남겨 웃음을 자아냈다.

[OSEN=김경주 인턴기자] trio88@osen.co.kr

새로운 사자성어

     1) 고진감래 - 고생을 진탕하고 나면 감기몸살 온다
     2) 새옹지마 - 새처럼 옹졸하게 지랄하지 마라
     3) 발본색원 - 발기는 본래 섹스의 근원이다
     4) 이심전심 - 이순자 마음이 전두환 마음
     5) 침소봉대 - 잠자리에서는 봉(?)이 대접을 받는다

     6) 사형선고 - 사정과 형편에따라 선택하고 고른다
     7) 전라남도 - 홀딱 벗은 남자의 그림
     8) 좌불안석 - 좌우지간에 불고기는 안심을 석쇠에 구워야 제맛
     9) 요조숙녀 - 요강에 조용히 앉아있는 여자
     10) 죽마고우 - 죽치고 마주앉아 고스톱치는 친구

     11) 삼고초려 - 쓰리고를 할때는 초단을 조심하라
     12) 희노애락 - 희희낙낙 노닐다가 애 떨어진다
     13) 개인지도 - 개가 사람을 가르친다.
     14) 포복절도 - 도둑질을 잘하려면 포복을 잘해야 한다
     15) 구사일생 - 구차하게 사는 한 평생

     16) 조족지혈 - 조기축구회서 족구하다 지랄하면 피본다
     17) 편집위원 - 편식과 집착은 위암의 원인 된다
     18) 임전무퇴 - 임산부 앞에서 침을 뱉으면 안된다
     19) 변화무쌍 - 변절한 화냥년은 무조건 쌍년이다
     20) 군계일학 - 군대에서는 계급이 학력보다 한수 위다

     21) 남녀평등 - 남자나 여자나 모두 등이 평평하다
     22) 눈치코치 - 눈을 치고 나서 코도 친다
     23) 유비무환 - 비가 오는 날은 환자가 없다
     24) 천고마비 - 하늘에 고약한 짓을 하면 온몸이 마비된다
     25) 만수무강 - 만수네 집에는 요강이 없다

재미있는 문자 오타시리즈

1. 피자먹는다는 얘기를 문자로
    - 나 지금 피지 먹어

2. 남자 친구와 헤어지고 펑펑 울고 있는데 남자 친구의 문자
    - 좋은 감자 만나

3. 봉사 활동 가던 도중 엄마한테 온 문자
    - 어디쯤 기고 있니

4. 할머니 오래 사세요라고 적어야 할것을
    - 할머니 오래 사네요

5. 엄마한테 학원 끝나고 데릴와를 잘못 써서
    - 임마 데릴러 와

6. 엄마한테 늦게 들어간다는 문자에 엄마 답장
    - 그럼 올 때 진화하고 와

7. 생일날 여자 친구한테 원하는거 없냐는 문자에.. 딱히 없어서
    - 딱히 원하는 건 ㅇ벗어

8. 소개팅녀에게 심심하냐고 물어보려는데
    - 너 싱싱해?

9. 친구한테 보낸다는 걸 잘못 택배아저씨한테..
    - 오늘 울 집 오면 야동 보여 줌 ㅋㅋ

10. 할머니가 중풍으로 쓰러지셔서 급히 엄마에게
    - 할머니 장풍으로 쓰러지셨어

11. 내 신발 사러가신 엄마가 사이즈를 물어보려
    - 너 시발 사이즈 몇이야?

12. 문자가 서투르신 아빠의 문자
    -아바닥 사간다 (통닭을 사오신 아버지)

13. 여자친구한테 생일을 물어봤는데..
    - 너 생ㅇ리 언제야?

14. 오늘 여자친구한테 선물을 사줬더니
    - 고마워 자기야. 사망해~ ♡

15. 우울해서 남친한테 위로 받으려 '나 오늘 또 울었다..' 문자를 보냈는데
    - 나 오늘 똥 루었다.

2011년 11월 12일 토요일

LEDFlash 2.0

LEDFlash 2.0

Easy to use, neat & seamless design.
Make your own blinking patterns with the pattern generator!
Make AppWidget in your home screen.