Oct 29, 2012

Insert ImageView dynamically using Java code

Here demonstrate how to create and add ImageView in LinearLayout (inside HorizontalScrollView/ScrollView) dynamically using Java code.

Insert ImageView dynamically using Java code


package com.example.androidinsertimages;

import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;

public class MainActivity extends Activity {
 
 Button addinHorizontalScrollView, addinScrollView;
 LinearLayout inHorizontalScrollView, inScrollView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        inHorizontalScrollView = (LinearLayout)findViewById(R.id.inhorizontalscrollview);
        inScrollView = (LinearLayout)findViewById(R.id.inscrollview);
        
        addinHorizontalScrollView = (Button)findViewById(R.id.addinhorizontalscrollview);
        addinHorizontalScrollView.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View arg0) {
    addImageView(inHorizontalScrollView);
   }});
        
        addinScrollView = (Button)findViewById(R.id.addinscrollview);
        addinScrollView.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View arg0) {
    addImageView(inScrollView);
   }});
        
    }
    
    private void addImageView(LinearLayout layout){
     ImageView imageView = new ImageView(this);
     imageView.setImageResource(R.drawable.ic_launcher);
     layout.addView(imageView);
    }

}


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" 
    android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world"
        tools:context=".MainActivity" />
    
    <Button
        android:id="@+id/addinhorizontalscrollview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Add in HorizontalScrollView"/>
    <HorizontalScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <LinearLayout
            android:id="@+id/inhorizontalscrollview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
        </LinearLayout>
    </HorizontalScrollView>
    
    <Button
        android:id="@+id/addinscrollview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Add in ScrollView"/>
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <LinearLayout
            android:id="@+id/inscrollview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical">
        </LinearLayout>
    </ScrollView>

</LinearLayout>


We can also remove the ImageViews using Java code, refer to next post, "Remove View dynamically using Java code".


Oct 16, 2012

Get video width and height of MediaPlayer and update SurfaceView LayoutParams accordingly

Last article demonstrate how to Play Youtube 3gp video with MediaPlayer in SurfaceView. It can be noticed that the video is fill in parent view, because "fill_parent" are defined in layout.

To adjust the video fit the Youtube video width and height, we can implement our custom OnVideoSizeChangedListener(), and call myMediaPlayer.getVideoWidth() and myMediaPlayer.getVideoHeight() to get the video width and height. After then, update SurfaceView LayoutParams with correct size accordingly.

MediaPlay with true size

Modify the Java code:
package com.example.androidyoutubeplayer;

import java.io.IOException;

import android.graphics.PixelFormat;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnVideoSizeChangedListener;
import android.os.Bundle;
import android.app.Activity;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;

public class MainActivity extends Activity implements SurfaceHolder.Callback{
 
 MediaPlayer myMediaPlayer;
 SurfaceView mySurfaceView;
 SurfaceHolder mySurfaceHolder;
 
 Button btnPlay, btnStop;
 TextView textVideoSize;
 String path3gp = "rtsp://v8.cache6.c.youtube.com/CjYLENy73wIaLQkP0kiLmutogRMYDSANFEIJbXYtZ29vZ2xlSARSBXdhdGNoYKjR78WV1ZH5Tgw=/0/0/0/video.3gp";
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        getWindow().setFormat(PixelFormat.UNKNOWN);
        mySurfaceView = (SurfaceView)findViewById(R.id.mediasurface);        
        mySurfaceHolder = mySurfaceView.getHolder();
        mySurfaceHolder.addCallback(this);
        myMediaPlayer = new MediaPlayer();
        
        btnPlay = (Button)findViewById(R.id.play);
        btnStop = (Button)findViewById(R.id.stop);
        
        btnPlay.setOnClickListener(playOnClickListener);
        btnStop.setOnClickListener(stopOnClickListener);
        
        textVideoSize = (TextView)findViewById(R.id.size);

    }
    
    OnClickListener playOnClickListener
    = new OnClickListener(){

  @Override
  public void onClick(View v) {
   myMediaPlayer.reset();
   
   myMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
   myMediaPlayer.setDisplay(mySurfaceHolder);
   
   try {
    
    myMediaPlayer.setOnVideoSizeChangedListener(videoSizeChangedListener);
    
    myMediaPlayer.setDataSource(path3gp);
    myMediaPlayer.prepare();
    
    /*
     * if you get Video Width and Height after prepare() here, it always return 0, 0!
     */
    int videoWidth = myMediaPlayer.getVideoWidth();
    int videoHeight = myMediaPlayer.getVideoHeight();
    textVideoSize.setText(String.valueOf(videoWidth) + " x " + String.valueOf(videoHeight));
    
    myMediaPlayer.start();
   } catch (IllegalArgumentException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } catch (SecurityException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } catch (IllegalStateException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   
  }};
    
    OnClickListener stopOnClickListener
    = new OnClickListener(){

  @Override
  public void onClick(View v) {
   if(myMediaPlayer.isPlaying()){
    myMediaPlayer.stop(); 
   }
   
  }};

 @Override
 public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
  // TODO Auto-generated method stub
  
 }

 @Override
 public void surfaceCreated(SurfaceHolder holder) {
  // TODO Auto-generated method stub
  
 }

 @Override
 public void surfaceDestroyed(SurfaceHolder holder) {
  // TODO Auto-generated method stub
  
 }
 
 /*
  * Get Video Width and Height in OnVideoSizeChangedListener,
  * and update SurfaceView LayoutParams accordingly.
  */
 OnVideoSizeChangedListener videoSizeChangedListener
 = new OnVideoSizeChangedListener(){

  @Override
  public void onVideoSizeChanged(MediaPlayer arg0, int arg1, int arg2) {
   int videoWidth = myMediaPlayer.getVideoWidth();
   int videoHeight = myMediaPlayer.getVideoHeight();
   
   textVideoSize.setText(String.valueOf(videoWidth) + " x " + String.valueOf(videoHeight));
   
   mySurfaceView.setLayoutParams(
     new LinearLayout.LayoutParams(videoWidth, videoHeight));
  }};
}


Modify the layout file to add TextView to show the detected size.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    
    <Button
        android:id="@+id/play"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="PLAY"/>
    <Button
        android:id="@+id/stop"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="STOP"/>
    <TextView
        android:id="@+id/size"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"/>
    <SurfaceView
        android:id="@+id/mediasurface"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"/>

</LinearLayout>


Modify AndroidManifest.xml to add permission of "android.permission.INTERNET".

Oct 12, 2012

Play Youtube 3gp video with MediaPlayer in SurfaceView

This example show how to play YouTube's 3gp video using MediaPlayer, in a SurfaceView.

Play Youtube 3gp video with MediaPlayer in SurfaceView


Modify layout file, /res/layout/activity_main.xml, to add two control buttons (play and stop), and a SurfaceView to hold the media window.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    
    <Button
        android:id="@+id/play"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="PLAY"/>
    <Button
        android:id="@+id/stop"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="STOP"/>
    <SurfaceView
        android:id="@+id/mediasurface"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"/>


</LinearLayout>


Modify MainActivity, extends Activity and implements SurfaceHolder.Callback. In the code, path3gp is the path to the Youtube's 3gp video.
package com.example.androidyoutubeplayer;

import java.io.IOException;

import android.graphics.PixelFormat;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.app.Activity;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity implements SurfaceHolder.Callback{
 
 MediaPlayer myMediaPlayer;
 SurfaceView mySurfaceView;
 SurfaceHolder mySurfaceHolder;
 
 Button btnPlay, btnStop;
 
 String path3gp = "rtsp://v8.cache6.c.youtube.com/CjYLENy73wIaLQkP0kiLmutogRMYDSANFEIJbXYtZ29vZ2xlSARSBXdhdGNoYKjR78WV1ZH5Tgw=/0/0/0/video.3gp";
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        getWindow().setFormat(PixelFormat.UNKNOWN);
        mySurfaceView = (SurfaceView)findViewById(R.id.mediasurface);        
        mySurfaceHolder = mySurfaceView.getHolder();
        mySurfaceHolder.addCallback(this);
        myMediaPlayer = new MediaPlayer();
        
        btnPlay = (Button)findViewById(R.id.play);
        btnStop = (Button)findViewById(R.id.stop);
        
        btnPlay.setOnClickListener(playOnClickListener);
        btnStop.setOnClickListener(stopOnClickListener);

    }
    
    OnClickListener playOnClickListener
    = new OnClickListener(){

  @Override
  public void onClick(View v) {
   myMediaPlayer.reset();
   
   myMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
   myMediaPlayer.setDisplay(mySurfaceHolder);
   
   try {
    myMediaPlayer.setDataSource(path3gp);
    myMediaPlayer.prepare();
    
    myMediaPlayer.start();
   } catch (IllegalArgumentException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } catch (SecurityException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } catch (IllegalStateException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   
  }};
    
    OnClickListener stopOnClickListener
    = new OnClickListener(){

  @Override
  public void onClick(View v) {
   if(myMediaPlayer.isPlaying()){
    myMediaPlayer.stop(); 
   }
   
  }};

 @Override
 public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
  // TODO Auto-generated method stub
  
 }

 @Override
 public void surfaceCreated(SurfaceHolder holder) {
  // TODO Auto-generated method stub
  
 }

 @Override
 public void surfaceDestroyed(SurfaceHolder holder) {
  // TODO Auto-generated method stub
  
 }
}


Modify AndroidManifest.xml to add permission of "android.permission.INTERNET".


Related article: Get video width and height of MediaPlayer and update SurfaceView LayoutParams accordingly.

Oct 7, 2012

My traffic drop on Oct !!!

My web site traffic suddenly dropped in Oct, what's wrong!?

My traffic drop on Oct !!!



Play RTTTL (Ring Tone Text Transfer Language) with MediaPlayer

Android platform support various media formats, include mRTTTL (Ring Tone Text Transfer Language).

Ring Tone Text Transfer Language (RTTTL) was developed by Nokia to be used to transfer ringtones to cellphone by Nokia. (source: Wikipedia - Ring Tone Transfer Language).

We are going to play the RTTTL ringtone of "Haunted House" listed in the Wikipedia article as an example.

Play RTTTL (Ring Tone Text Transfer Language) with MediaPlayer

Create /res/raw/hauntedhouse.rtttl file to define ring tone of "Haunted House".
HauntedHouse: d=4,o=5,b=108: 2a4, 2e, 2d#, 2b4, 2a4, 2c, 2d, 2a#4, 2e., e, 1f4, 1a4, 1d#, 2e., d, 2c., b4, 1a4, 1p, 2a4, 2e, 2d#, 2b4, 2a4, 2c, 2d, 2a#4, 2e., e, 1f4, 1a4, 1d#, 2e., d, 2c., b4, 1a4


Modify layout to have buttons to start and stop the ring tone.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world"
        tools:context=".MainActivity" />
    <Button 
        android:id="@+id/start"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start" />
    <Button 
        android:id="@+id/stop"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Stop" />

</LinearLayout>


The Java code of the activity.
package com.example.androidrtttl;

import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity {
 
 Button buttonStart, buttonStop;
 MediaPlayer mediaPlayer;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        buttonStart = (Button)findViewById(R.id.start);
        buttonStart.setOnClickListener(buttonStartOnClickListener);
        buttonStop = (Button)findViewById(R.id.stop);
        buttonStop.setOnClickListener(buttonStopOnClickListener);

    }

    OnClickListener buttonStartOnClickListener
    = new OnClickListener(){

  @Override
  public void onClick(View v) {
   if (mediaPlayer != null){
    mediaPlayer.release();
   }
   
   mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.hauntedhouse);
   mediaPlayer.setOnCompletionListener(mediaplayerCompletionListener);
   mediaPlayer.start();
  }
     
    };
    
    OnClickListener buttonStopOnClickListener
    = new OnClickListener(){

  @Override
  public void onClick(View v) {
   if (mediaPlayer != null){
    mediaPlayer.stop();
    mediaPlayer.release();
   }
   
  }};
  
 OnCompletionListener mediaplayerCompletionListener
 = new OnCompletionListener(){

  @Override
  public void onCompletion(MediaPlayer arg0) {

   mediaPlayer.release();
   
   Toast.makeText(getApplicationContext(), 
     "onCompletion", 
     Toast.LENGTH_LONG).show();
  }};

}


Oct 5, 2012

Save and Restore Instance State

The methods onSaveInstanceState(Bundle outState) and onRestoreInstanceState(Bundle savedInstanceState) are the good place to Save and Restore Instance State.
  • onSaveInstanceState (Bundle outState)

    Called to retrieve per-instance state from an activity before being killed so that the state can be restored in onCreate(Bundle) or onRestoreInstanceState(Bundle) (the Bundle populated by this method will be passed to both).

    This method is called before an activity may be killed so that when it comes back some time in the future it can restore its state. For example, if activity B is launched in front of activity A, and at some point activity A is killed to reclaim resources, activity A will have a chance to save the current state of its user interface via this method so that when the user returns to activity A, the state of the user interface can be restored via onCreate(Bundle) or onRestoreInstanceState(Bundle).

    Do not confuse this method with activity lifecycle callbacks such as onPause(), which is always called when an activity is being placed in the background or on its way to destruction, or onStop() which is called before destruction. One example of when onPause() and onStop() is called and not this method is when a user navigates back from activity B to activity A: there is no need to call onSaveInstanceState(Bundle) on B because that particular instance will never be restored, so the system avoids calling it. An example when onPause() is called and not onSaveInstanceState(Bundle) is when activity B is launched in front of activity A: the system may avoid calling onSaveInstanceState(Bundle) on activity A if it isn't killed during the lifetime of B since the state of the user interface of A will stay intact.

    The default implementation takes care of most of the UI per-instance state for you by calling onSaveInstanceState() on each view in the hierarchy that has an id, and by saving the id of the currently focused view (all of which is restored by the default implementation of onRestoreInstanceState(Bundle)). If you override this method to save additional information not captured by each individual view, you will likely want to call through to the default implementation, otherwise be prepared to save all of the state of each view yourself.

    If called, this method will occur before onStop(). There are no guarantees about whether it will occur before or after onPause().

  • onRestoreInstanceState (Bundle savedInstanceState)

    This method is called after onStart() when the activity is being re-initialized from a previously saved state, given here in savedInstanceState. Most implementations will simply use onCreate(Bundle) to restore their state, but it is sometimes convenient to do it here after all of the initialization has been done or to allow subclasses to decide whether to use your default implementation. The default implementation of this method performs a restore of any view state that had previously been frozen by onSaveInstanceState(Bundle).

    This method is called between onStart() and onPostCreate(Bundle).

Example:
package com.example.androidsavestate;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {
 
 TextView textviewSavedState;
 EditText edittextEditState;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        textviewSavedState = (TextView)findViewById(R.id.savedstate);
     edittextEditState = (EditText)findViewById(R.id.editstate);
    }

 @Override
 protected void onRestoreInstanceState(Bundle savedInstanceState) {
  // TODO Auto-generated method stub
  super.onRestoreInstanceState(savedInstanceState);
  
  String stateSaved = savedInstanceState.getString("saved_state");
  
  if(stateSaved == null){
   Toast.makeText(MainActivity.this, 
     "onRestoreInstanceState:\n" +
     "NO state saved!", 
     Toast.LENGTH_LONG).show();
  }else{
   Toast.makeText(MainActivity.this, 
     "onRestoreInstanceState:\n" +
     "saved state = " + stateSaved, 
     Toast.LENGTH_LONG).show();
   textviewSavedState.setText(stateSaved);
   edittextEditState.setText(stateSaved);
  }

 }

 @Override
 protected void onSaveInstanceState(Bundle outState) {
  // TODO Auto-generated method stub
  super.onSaveInstanceState(outState);
  
  String stateToSave = edittextEditState.getText().toString();
  outState.putString("saved_state", stateToSave);
  
  Toast.makeText(MainActivity.this, 
    "onSaveInstanceState:\n" +
    "saved_state = " + stateToSave, 
    Toast.LENGTH_LONG).show();
 }

}


Save and Restore Instance State

Oct 4, 2012

Create scaled bitmap using Bitmap.createScaledBitmap() method

To create a scaled bitmap from a source bitmap, we can call the static method Bitmap.createScaledBitmap().
  • public static Bitmap createScaledBitmap (Bitmap src, int dstWidth, int dstHeight, boolean filter)
    Creates a new bitmap, scaled from an existing bitmap, when possible. If the specified width and height are the same as the current width and height of the source btimap, the source bitmap is returned and now new bitmap is created.

    src: The source bitmap.
    dstWidth: The new bitmap's desired width.
    dstHeight: The new bitmap's desired height.
    filter: true if the source should be filtered.

    Returns: The new scaled bitmap or the source bitmap if no scaling is required.

Example to create scaled bitmap with 1/2 width and height:
   Bitmap scaledBitmap =  Bitmap.createScaledBitmap(
     srcBitmap, 
     srcBitmap.getWidth()/2, 
     srcBitmap.getHeight()/2, 
     false);


Infolinks In Text Ads