화요일, 7월 13, 2010

[Android] My Tip

My Android Tip
 - Use at your own risk! lol, ㅋㅋㅋ


내가 작업한 것 중에서 유용한 Tip 들을 정리 해본다.

// ---------------------------------------------
// :: AndroidManifest.xml
// ---------------------------------------------
* android:sharedUserId="..."
* for Froyo (Android 2.2 API Level 8 ~)
android:installLocation = {
"internalOnly",
"preferExternal",
"auto"
};
android:installLocation="auto"

* android:launchMode="singleTask"

* Prevent to restart Activity Life-Cycle when slide-out QWERTY keypad
* Landscape/Portrait mode event
android:screenOrientation="portrait"
android:configChanges="keyboardHidden|orientation"

* android:theme="@android:style/Theme.Translucent"
// ---------------------------------------------


// ---------------------------------------------
// :: Slide Strings
// ---------------------------------------------
    // NOTE: Slide Strings
android:ellipsize = {
"marquee" -> slide
"end" -> "..."
}
android:singleLine="true"
android:ellipsize="marquee"
android:focusable="true"
android:focusableInTouchMode="true"

    // main.xml
    // ----------------------------------------------
    
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12.00sp"
android:gravity="left|center_vertical"
android:height="20.0dp"
android:width="300.0dp"
android:singleLine="true"
android:ellipsize="end"
android:focusable="true"
android:focusableInTouchMode="true"
android:text="">
  


    // TextView Click Event
    // ----------------------------------------------
    // TextViewStr1
    View.OnClickListener TextViewStr1Listener = new View.OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub

Log.d( "LOG", "TextViewStr1Listener: focus = false" );
//m_TextViewStr_xxx.clearFocus();

m_TextViewStr1.setEllipsize( TruncateAt.MARQUEE );
m_TextViewStr1.setFocusable( true );
};
    };
    m_TextViewStr1.setOnClickListener( TextViewStr1Listener );
  
    // Focus
    View.OnFocusChangeListener focusTextViewStr1Listener = new View.OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
// TODO Auto-generated method stub

if( hasFocus ) {
Log.d( "LOG", "[FOCUS] TextViewStr1Listener: focus = true" );
//m_TextViewStr_xxx.clearFocus();

m_TextViewStr1.setEllipsize( TruncateAt.MARQUEE );
m_TextViewStr1.setFocusable( true );
}
else {
Log.d( "LOG", "[FOCUS] TextViewStr1Listener: focus = false" );
m_TextViewStr1.setEllipsize( TruncateAt.END );
}
}
};
m_TextViewStr1.setOnFocusChangeListener( focusTextViewStr1Listener );
// ---------------------------------------------


// ---------------------------------------------
// :: ViewControl Visibility
// ---------------------------------------------
// VISIBLE: 0x00000000, INVISBLE: 0x00000004, GONE: 0x00000008
ImageView.setVisibility( 0 );
ImageView.invalidate();
// ---------------------------------------------    


// ---------------------------------------------
// :: Events
// ---------------------------------------------
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        // TODO Auto-generated method stub
        super.onConfigurationChanged(newConfig);
      
        Log.d( "FUNC", "onConfigurationChanged" );


        if( m_isFullScreen ) {
         Log.d( "LOG", "Full Screen -> restore" );
         m_isFullScreen = false;
         //getWindow().setFlags( WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR, WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR );
         //setRequestedOrientation( ActivityInfo.SCREEN_ORIENTATION_PORTRAIT );
         getWindow().clearFlags( WindowManager.LayoutParams.FLAG_FULLSCREEN );
        }
        else {
         Log.d( "LOG", "Full Screen" );
         m_isFullScreen = true;
         getWindow().setFlags( WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN );
        }

    }

    /*
     * Activity Status(Activity Lifecycle)
run1: app
onStart -> onResume

run2-1: app -> no work -> home
onSaveInstanceState -> onStop
run2-2: app
onStop -> onRestart -> onStart -> onResume

run3-1: work -> home
onSaveInstanceState -> onStop
run3-2: app
onRestart -> onStart -> onResume
    */

Figure Source: http://developer.android.com/guide/topics/fundamentals.html


  
















// NOTE: Activity LifeCycle method 들의 한글 주석은 출처가 없다.

    // onCreate가 호출이 된 후 GUI 상태 복구를 위해서 사용을 하는 함수
    public void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        // savedInstaceState로부터 GUI 상태를 복구를 한다.
        // 인수로 받는 Bundle은 onCreate에도 전달된다.
      
        Log.d( "FUNC", "onRestoreInstanceState" );


        if( !m_isPauseBySystem ) {
         Log.d( "PLAY", "keep state: pauseBySystem == false" );
         return;
        }
        if( m_MediaPlayer == null ) {
         Log.d( "LOG", "m_MediaPlayer == null" );
         return;
        }
        else {
         Log.d( "LOG", "now restart..." );
         m_MediaPlayer.start();
          }

    }
  
    /// visible lifetime으로 가기 전 activity 처리를 위해서 호출이 된다.
    public void onRestart(){
        super.onRestart();
        // activity가 이미 화면에 보이고
        // 여기서 변경된 것들만 읽어들인다.
      
        Log.d( "FUNC", "onRestart" );
    }

    /// visible lifetime start시에 호출된다.
    public void onStart(){
        super.onStart();
        // 여기서는 activity가 화면에 보이므로
        // 필요한 GUI 변경 사항을 적용한다.
      
        Log.d( "FUNC", "onStart" );
    }

    /// active lifetime시에 호출이 된다.
    public void onResume(){
        super.onResume();
        /// 일시 중지된 모든 GUI update나 thread
        /// activity에 의해서 필요하지만 activity가 비활성화
        /// 되면서 일시 중단된 것들을 처리를 다시 시작을 할 때
      
        Log.d( "FUNC", "onResume" );
      

     Intent intt = new Intent( "com.android.music.musicservicecommand" );
     intt.putExtra( "command", "pause" );
     sendBroadcast( intt );

        if( !m_isPauseBySystem ) {
         Log.d( "PLAY", "keep state: pauseBySystem == false" );
         return;
        }
        if( m_MediaPlayer == null ) {
         Log.d( "LOG", "m_MediaPlayer == null" );
         return;
        }
        else {
         Log.d( "LOG", "now restart..." );
         m_MediaPlayer.start();
        }


        // for Some Interrupt
// ...
    }

    /// GUI 상태를 저장을 하기 위해서 호출이된다.
    public void onSaveInstanceState(Bundle savedInstanceState){
        /// GUI state를 savedInstanceState에 저장한다.
        /// 프로세스가 중료되거나 재시작될 경우
        /// 이 번들이 onCreate에 전달이 되서
        /// 그 시점부터 다시 시작이 될 것이다.
        super.onSaveInstanceState(savedInstanceState);
      
        Log.d( "FUNC", "onSaveInstanceState" );


        if( m_MediaPlayer == null ) {
         Log.d( "LOG", "m_MediaPlayer == null" );
         return;
        }
        else {
         Log.d( "LOG", "now pause... by System" );
         m_isPauseBySystem = true;
         m_MediaPlayer.pause();
         // save m_MediaPlayer.getCurrentPosition()...
        }

      
        // for Some Interrupt
// ...
    }

    /// active lefetime 끝에서 호출된다.
    public void onPuase() {
        super.onPause();
        /// activity가 포그라운드 상태가 아닐 경우
        /// 다시 update 되거나 필요가 없는 GUI및 Thread
        /// 프로세서 점유율이 높이는 처리는 일시 중지한다
      
        Log.d( "FUNC", "onPuase" );


        if( m_MediaPlayer == null ) {
         Log.d( "LOG", "m_MediaPlayer == null" );
         return;
}
        else {
         m_isPauseBySystem = true;
         m_MediaPlayer.pause();
         // save m_MediaPlayer.getCurrentPosition()...
        }


      
        // Try adding android:configChanges="keyboardHidden|orientation"
        // to your AndroidManifest.xml. This tells the system what configuration changes
        // you are going to handle yourself
        // android:configChanges="keyboardHidden|orientation
          
        // for Some Interrupt
// ...
    }

    /// visible lifetime 끝에서 호출
    public void onStop() {
        super.onStop();
        /// 남아있는 GUI 업데이트나 쓰레드
        /// activity가 화면에 보이지 않을 때 필요치 않은 처리를 일시 중단을 한다.
        /// 이 메서드가 호출이 되고 난 뒤에는 프로세스가 종료될 가능성이 있으므로
        /// 바뀐 모든 내용과 상태 변화를 지속시킨다.
      
        Log.d( "FUNC", "onStop" );
    }
// ---------------------------------------------


// ---------------------------------------------
// :: Surface and Media Player
// ---------------------------------------------

public class TESTAPP extends Activity implements
OnPreparedListener,
SurfaceHolder.Callback {
...
}
...

    // SurfaceHolder
    public void surfaceChanged(SurfaceHolder surfaceholder, int format, int width, int height) {
     Log.d( "FUNC", "surfaceChanged()" );
    }
    public void surfaceDestroyed(SurfaceHolder surfaceholder) {
     Log.d( "FUNC", "surfaceDestroyed()" );


     if( m_MediaPlayer == null )
     return;
     else
     m_MediaPlayer.pause();

    }
    public void surfaceCreated(SurfaceHolder holder) {
     Log.d( "FUNC", "surfaceCreated()" );
    
// mediaPlayer not null ?
// then start to play or pause

    // NOTE: update surface
    //m_MediaPlayer.setDisplay( holder );

/*
     if( m_MediaPlayer == null ) {
     Log.d( "LOG", "m_MediaPlayer == null" );
return;
     }
     else {
     Log.d( "LOG", "now Playing..." );
m_MediaPlayer.setDisplay( holder );
//m_MediaPlayer.pause();
//m_MediaPlayer.start();
*/


     if( m_MediaPlayer == null ) {
     Log.d( "LOG", "null; playing..." );
return;
     }
     else {
     Log.d( "LOG", "playing..." );
/*
     if( m_MediaPlayer.getCurrentPosition() == 0 )
m_MediaPlayer.start();
     }
     else {
     Log.d( "LOG", "use the holder" );
     m_MediaPlayer.setDisplay( holder );
    
m_MediaPlayer.start();
*/
    m_SurfaceHolder = holder;
    // re-create MediaPlayer, reset SurfaceView, seekTo(...), ...
    // PlayVideo(); // see below code Video Player with SurfaceView
     }

}

    }
  
    public void onPrepared(MediaPlayer mediaplayer) {
        Log.d( "FUNC", "MediaPlayer: onPrepared()" );

// mediaPlayer not null ?
// then start to play

        if( m_MediaPlayer != null )
         m_MediaPlayer.start();
else
Log.d( "LOG", "m_MediaPlayer == null" );

    }
// ---------------------------------------------


// ---------------------------------------------
// :: Handler
// ---------------------------------------------
    private Handler m_Handler = null;

{
m_Handler = new Handler();
m_Handler = new Handler() {
public void handleMessage(android.os.Message msg) {
// update something
// or
// skip
};
};
}

// another

if( m_Handler != null ) {
Log.d( "LOG", "m_Handler != null" );
m_Handler.removeCallbacksAndMessages( null );
m_Handler = null;
}

m_Handler = new Handler();
m_Handler.postDelayed( new Runnable() {
public void run() {
Log.d( "RUNNABLE", "start" );
// Something...
Log.d( "THREAD", "finish" );
}
}, 5000
);

or

m_Handler = new Handler() {
public void handleMessage(android.os.Message msg) {
Log.d( "FUNC", "HANDLER: handleMessage()" );

switch( msg.what ) {
case 0:
// Something
break;
}
};
};
// ---------------------------------------------


// ---------------------------------------------
// :: Thread Start and Stop
// ---------------------------------------------
    private void threadStop() {
     Log.d( "FUNC", "threadStop()" );

     m_ThreadRunFlag = false;
m_Thread = null;
    }
    private void threadStart() {
Log.d( "FUNC", "threadStart()" );
  
if( m_Thread != null ) {
     Log.d( "THREAD", "m_Thread != NULL" );
     return;
     }

     m_ThreadRunFlag = true;
m_Thread = new Thread() {
public void run() {
try {
// checks MediaPlayer Status
//

while( m_ThreadIsRunning == true ) {
Thread.sleep( 1000 );

// checks MediaPlayer Status
//

m_Handler.sendMessage( m_Handler.obtainMessage() );
}

m_ThreadRunFlag = false;
}
catch( Throwable t ) {
m_ThreadRunFlag = false;
}
}

if( m_Thread != null )
m_Thread.start();
else
Log.d( "THREAD", "m_Thread == NULL" );
    };
// ---------------------------------------------


// ---------------------------------------------
// :: MessageBox
// ---------------------------------------------
    private void dlgFail() {
final Builder winAlert;
Dialog winDialog;
     LayoutInflater li = LayoutInflater.from( this );
     View viewDlgFail = li.inflate( R.layout.dlgFail, null );

     DialogInterface.OnClickListener okListener = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub

// Button 1
if( which == -1 ) {
Log.d( "Button", "Selected Button 1" );
//Toast.makeText( __MyActivity__.this, "Selected Button 1", Toast.LENGTH_LONG ).show();
}
// Button 2
else if( which == -3 ) {
Log.d( "Button", "Selected Button 2" );
//Toast.makeText( __MyActivity__.this, "Selected Button 2", Toast.LENGTH_LONG ).show();
}
// Button 3
else if( which == -2 ) {
Log.d( "Button", "Selected Button 3" );
//Toast.makeText( __MyActivity__.this, "Selected Button 3", Toast.LENGTH_LONG ).show();
}

dialog.cancel();

// Quit
// System.exit( 1 );
return;
}
};

winAlert = new AlertDialog.Builder( this )
.setIcon( R.drawable.icon )
.setTitle( getResources().getString(R.string."__FAIL_MESSAGE_TITLE__") )
.setMessage( testGMP.this.m_strResMsg )
.setPositiveButton( getResources().getString(R.string."__FAIL_MESSAGE_BUTTON_OK__"), okListener )
.setView( viewDlgFail );
winDialog = winAlert.create();
winDialog.show();
    }
// ---------------------------------------------


// ---------------------------------------------
// :: Resource to Export
// ---------------------------------------------
// Get current mounted SD card path
String strFilePathExt = Environment.getExternalStorageDirectory().getPath();
String strFilePath = strFilePathExt + "/";
String strFilename = "_export_filename_";

// Get SD card State
Environment.getExternalStorageState()


// Checks Internal Storage Free Space
{
File path = Environment.getDataDirectory();
StatFs stat = new StatFs( path.getPath() );
long blockSize = stat.getBlockSize();
long availableBlocks = stat.getAvailableBlocks();
{
AssetFileDescriptor afd = getResources().openRawResourceFd( R.raw.__RAW_MEDIA_FILE__ );
if( (availableBlocks * blockSize) < afd.getLength() ) {
Toast.makeText( this, getResources().getString(Out of Internal Storage), Toast.LENGTH_LONG ).show();
afd.close();
return;
}

afd.close();
}
}

// Checks Mount State and External Storage Free Space
if( android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED) ) {
File path = Environment.getExternalStorageDirectory();
StatFs stat = new StatFs( path.getPath() );
long blockSize = stat.getBlockSize();
long availableBlocks = stat.getAvailableBlocks();
{
AssetFileDescriptor afd = getResources().openRawResourceFd( R.raw.__RAW_MEDIA_FILE__ );
if( (availableBlocks * blockSize) < afd.getLength() ) {
Toast.makeText( this, getResources().getString("Out of External Storage"), Toast.LENGTH_LONG ).show();
afd.close();
return;
}

afd.close();
}
}

// Resource file to Export to SD card
{
     AssetFileDescriptor afd = this.getResources().openRawResourceFd( R.raw.__RAW_MEDIA_FILE__ );
   
if( (new File(strFilePath + strFilename).exists()) == true ) {
Log.d( "EXPORT", "Exist = " + strFilePath + strFilename + ", " + "Internal Resource File Size = " + afd.getLength() + ", External(Exported) Resource File Size = " + (new File(strFilePath + strFilename).length()) );
if( (new File(strFilePath + strFilename).length()) == afd.getLength()) {
Toast.makeText( this, getResources().getString("File existed already"), Toast.LENGTH_LONG ).show();
afd.close();
return;
}
}

byte[] buf_readBytes = new byte[1024];
int readBytes = 0;
int offset = 0;
int count = 1024;

OutputStream oStream = new FileOutputStream( strFilePath + strFilename );

FileInputStream fis = afd.createInputStream();
while( true ) {
int bytes = fis.read( buf_readBytes );
if( bytes <= 0 ) break;
oStream.write( buf_readBytes, 0, bytes );
}

oStream.flush();
oStream.close();
fis.close();
afd.close();
}
// ---------------------------------------------


// ---------------------------------------------
// :: Use Cache Directory and File
// ---------------------------------------------
    private File m_TmpFile = null;

    ...

    @Override
    protected void onDestroy() {
     super.onDestroy();

     try {
if( m_TmpFile != null )
m_TmpFile.delete();
}
     catch( Exception e ) {
     Log.e( "FUNC", "onDestroy(): error: " + e.getMessage(), e );
     }
    }
{
try {
AssetFileDescriptor afd = getResources().openRawResourceFd( R.raw.__RAW_MEDIA_FILE__ );
FileInputStream fis = afd.createInputStream();
String strTmpFilename = "";

if( m_TmpFile != null )
m_TmpFile.delete();

Log.d( "CacheFile", "Full Resource Size = " + Long.toString(fis.getChannel().size()) );
Log.d( "CacheFile", "Current Resource Position = " + Long.toString(fis.getChannel().position()) );
Log.d( "CacheFile", "Current Resource Size = " + Long.toString(afd.getLength()) );

{
byte[] buf_readBytesFile = new byte[1024];
File cacheDir = getCacheDir();
String strFilename = "__CACHE_TMP_FILENAME__";
m_TmpFile = File.createTempFile( strFilename, ".tmp", cacheDir );
OutputStream oStream = new FileOutputStream( m_TmpFile );

Log.d( "CacheFile", "CacheTmpFilename = " + m_TmpFile.getPath() );

while( true ) {
int bytes = fis.read( buf_readBytesFile );
if( bytes <= 0 ) break;
oStream.write( buf_readBytesFile, 0, bytes );
}

oStream.flush();
strTmpFilename = m_TmpFile.getAbsolutePath();
oStream.close();
}

Log.d( "CacheFile", "CacheTmpFilename = " + strTmpFilename );

afd.close();
fis.close();
}
catch( Exception e ) {
// ...
}
}
// ---------------------------------------------


// ---------------------------------------------
// :: Play Video
// ---------------------------------------------
// See above code SurfaceView method
public class TESTAPP extends Activity implements
OnPreparedListener,
SurfaceHolder.Callback {
...


     Intent intt = new Intent( "com.android.music.musicservicecommand" );
     intt.putExtra( "command", "pause" );
     sendBroadcast( intt );

}
...

private MediaPlayer m_MediaPlayer = null;
private SurfaceView m_SurfaceView = null;
private SurfaceHolder m_SurfaceHolder = null;
// VideoView
m_VideoView = (VideoView)findViewById( R.id.VideoView01 );
// SurfaceView
m_SurfaceView = (SurfaceView)findViewById( R.id.SurfaceView01 );
m_SurfaceHolder = m_SurfaceView.getHolder();
m_SurfaceHolder.addCallback( this );
m_SurfaceHolder.setType( SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS );
m_SurfaceView.setClickable( false );

// Visibility
// VideoView
//m_VideoView.setVisibility( 0 );
//m_VideoView.invalidate();
// SurfaceView
m_SurfaceView.setVisibility( 0 );
m_SurfaceView.invalidate();

// Button: Play
Button btnPlay = (Button)findViewById( R.id.Button01 );
View.OnClickListener btnPlayListener = new View.OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub

if( m_MediaPlayer == null ) {
Log.d( "PLAY", "OK, First time" );
PlayVideo();
}
else {
PlayVideo();
}
}
};
btnPlay.setOnClickListener( btnPlayListener );

public void PlayVideo() {
if( m_MediaPlayer != null )
m_MediaPlayer.release();
m_MediaPlayer = null;
m_MediaPlayer = new MediaPlayer();
AssetFileDescriptor afd = getResources().openRawResourceFd( R.raw.__RAW_MEDIA_FILE__ );

if( m_MediaPlayer == null ) {
Log.d( "MediaPlayer", "m_MediaPlayer == NULL" );
return;
}

// Use ViewoView
/*
if( m_VideoView == null ) {
Log.d( "VideoView", "m_VideoView == NULL" );
return;
}
*/

// Use SurfaceView
if( m_SurfaceView == null ) {
Log.d( "SurfaceView", "m_SurfaceView == NULL" );
return;
}

m_MediaPlayer.setAudioStreamType( AudioManager.STREAM_MUSIC );
 m_MediaPlayer.setScreenOnWhilePlaying( true );
   try {
m_MediaPlayer.setDataSource( afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength() );

// Use VideoView
//m_VideoView.getHolder().addCallback( this );
//m_MediaPlayer.setDisplay( m_VideoView.getHolder() );

// Use Surface
m_MediaPlayer.setDisplay( m_SurfaceHolder );
m_MediaPlayer.prepare();  
   }
     catch( IllegalStateException e ) {
     // ...
     }
     catch( IOException e ) {
     // ...
     }

  if( m_CurrentPosition > 0 )
      m_MediaPlayer.seekTo( m_CurrentPosition );
  if( !isPause )
m_MediaPlayer.start();
}
}

if( m_MediaPlayer != null ) {
m_MediaPlayer.release();
m_MediaPlayer = null;
}
// ---------------------------------------------

// ---------------------------------------------
// :: Play Video (VideoView)
// ---------------------------------------------
// VideoView

int m_CurrentPosition = 0;

... onSaveInstanceState( ... ) {
m_VideoView.pause();
m_CurrentPosition = m_VideoView.getCurrentPosition();
}

... onRestoreInstanceState( ... ) {
m_VideoView.seekTo( m_CurrentPosition );
m_VideoView.start();
}

if( m_MediaController == null )
m_MediaController = new MediaController( this );
Uri uriVideo = Uri.parse( "android.resource://com.test.TESTAPP/" + R.raw.xxx );
m_VideoView.setVideoURI( uriVideo );
m_MediaController.setSaveEnabled( true );
m_VideoView.setMediaController( m_MediaController );
m_MediaController.show();
m_VideoView.requestFocus();
m_VIdeoView.start();
// ---------------------------------------------

// ---------------------------------------------
// :: Media Scan (SD card)
// ---------------------------------------------
sendBroadcast( new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory())) );
// ---------------------------------------------


// ---------------------------------------------
// :: Restrict characters length (Korean/Japanese)
// - EditText 에서 한글/일본어 입력 시 byte 수 제한하기.
// - 간단한 테스트는 Emulator 에서 일본어 입력기로 해보면 된다.
// ---------------------------------------------
        m_Editbox = (EditText)findViewById( R.id.EditText01 );
        m_Editbox.addTextChangedListener( new TextWatcher() {
public void onTextChanged(CharSequence s, int start, int before, int count) {
// TODO Auto-generated method stub

//Log.d("LOG", s.toString() );
}
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
//Log.d("LOG", s.toString() );
}

    // byte to int, bytes to hex 는 internet 에서 그냥 찾아서 썼다.
// NOT my code (^^) --------------------
public int getInt(byte[] bytes) {
      int newValue = 0;
      newValue |= (((int) bytes[0]) << 24) & 0xFF000000;
      newValue |= (((int) bytes[1]) << 16) & 0xFF0000;
      newValue |= (((int) bytes[2]) << 8) & 0xFF00;
      newValue |= (((int) bytes[3])) & 0xFF;
      return newValue;
}
public String byteArrayToHex(byte[] ba) {
   if (ba == null || ba.length == 0) {
       return null;
   }

   StringBuffer sb = new StringBuffer(ba.length * 2);
   String hexNumber;
   for (int x = 0; x < ba.length; x++) {
       hexNumber = "0" + Integer.toHexString(0xff & ba[x]);

       sb.append(hexNumber.substring(hexNumber.length() - 2));
   }
   return sb.toString();
}
// NOT my code (^^) --------------------


public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub

//Toast.makeText( myTest1App.this, m_Editbox.getText().toString(), Toast.LENGTH_LONG ).show();
     // 여기에선 8 bytes 를 제한한다.
     // 주의할 점은 한글/일본어는 2 bytes 가 아닌 3 bytes 로 된다.
     // 아래 log 에서 해당 문자와 hex code 를 보면 안다.
int max_len = 8; // restrict 8 bytes. (Korean/Japanese may has 3 bytes. NOT 2 bytes.)
if( s.length() > 0 ) {
int c = s.charAt( s.length()-1 );
String str = Character.toString( s.charAt(s.length()-1) );
int cLen = str.length();

Log.d( "LOG", "s len = " + s.toString().getBytes().length + ", s str = " + s.toString() + ", s hex = " + byteArrayToHex(s.toString().getBytes()) );
//Log.d( "LOG", "byte = " + s.toString().getBytes() + ", len = " + cLen + ", ascii = " + s.charAt(0) + ", dec = " + c + ", hex = " + byteArrayToHex(s.toString().getBytes()) );
Log.d( "LOG", "s.charAt(" + (s.length()-1) + ") -> " + ", = " + str + ", len = " + cLen + ", dec = " + c + ", bytes = " + str.getBytes() + ", len = " + str.getBytes().length + ", hex = " + byteArrayToHex(str.getBytes()) );

if( s.toString().getBytes().length > max_len ) {
s.delete( s.length()-1, s.length() );
m_TextView.setText( s.toString() );
}
}
}
}
);
// ---------------------------------------------


// ---------------------------------------------
// :: Indicator: Notification
// ---------------------------------------------
// http://developer.android.com/guide/topics/ui/notifiers/notifications.html
// http://osdir.com/ml/Android-Beginners/2010-07/msg00649.html

// Path: /android-sdk-windows/platforms/android-4/samples/ApiDemos/src/com/example/android/apis/app
// Source: RemoteService.java
// - AndroidManifest.xml
// - < activity ... android:launchMode="singleTask">
//
// Show a notification while this service is running.
private NotificationManager mNM = null;
private void showNotification() {
        // Indicator: Notification
if( mNM != null ) {
    mNM.cancel( R.string.app_name );

        // Use custom view
//mNM.cancel( R.layout.local_service_controller );

  }

mNM = (NotificationManager)getSystemService( NOTIFICATION_SERVICE );

        // In this sample, we'll use the same text for the ticker and the expanded notification
        CharSequence text = getText( R.string.remote_service_started );

        // Set the icon, scrolling text and timestamp
        //Notification notification = new Notification(R.drawable.stat_sample, text, System.currentTimeMillis() );
        Notification notification = new Notification( -1, text, System.currentTimeMillis() );

        Intent intent = new Intent( this,  testMyActivity.class );
        intent.setFlags( Intent.FLAG_ACTIVITY_SINGLE_TOP );

        // The PendingIntent to launch our activity if the user selects this notification
        PendingIntent contentIntent = PendingIntent.getActivity( this, 0, intent, 0 );

        // Set the info for the views that show in the notification panel.
        //notification.setLatestEventInfo(this, getText(R.string.local_service_label),
        notification.setLatestEventInfo( this, getText(R.string.Info), text, contentIntent );

/*

        // Set custom view
        * DELETE notification.setLatestEventInfo(...)
        RemoteViews contentView = new RemoteViews( getPackageName(), R.layout.local_service_controller );
        ////contentView.setImageViewResource( R.id.image, R.drawable.notification_image );
        ////contentView.setTextViewText( R.id.text, "Hello, this message is in a custom expanded view" );
        //contentView.setImageViewResource( R.id.image, R.drawable.imagefile );
        contentView.setTextViewText( R.id.TextViewIndicator, getText(R.string.app_name) );
        notification.contentView = contentView;

        // Use custom view
        notification.contentIntent = contentIntent;

*/
        // Send the notification.
        // We use a string id because it is a unique number.  We use it later to cancel.
        mNM.notify( R.string.remote_service_started, notification );

        // Use custom view
        //mNM.notify( R.layout.local_service_controller, notification );

}

// Use custom view (ImageView, TextView)
// local_service_controller.xml
// Change (, ) to <, >
(LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:padding="4dip"
android:id="@+id/LinearLayoutIndicator"
    android:layout_width="fill_parent" android:layout_height="fill_parent")
(RelativeLayout android:orientation="horizontal"
android:layout_width="fill_parent" android:layout_height="fill_parent")
    (TextView
     android:id="@+id/TextViewIndicator"
        android:layout_width="fill_parent" android:layout_height="wrap_content"
        android:layout_weight="0"
        android:paddingBottom="4dip"
        android:text="local_service_controller")
    (/TextView)
    (Button android:id="@+id/start"
     android:layout_below="@+id/TextViewIndicator"
        android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:text="start_service")
    (/Button)
    (Button android:id="@+id/stop"
     android:layout_below="@+id/TextViewIndicator"
     android:layout_toRightOf="@+id/start"
        android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:text="stop_service")
    (/Button)
(/RelativeLayout)
(/LinearLayout)
// ---------------------------------------------



-----
Cheers,
June

댓글 없음:

댓글 쓰기