Android animation through XML


In the last days I was trying to do some animations with Android. I want to share some of the animation which can be build through defining them in your XML.

In total this tutorial will have 3 animations based on an ImageView: (1) shake, rotate, and fade.

It is actually quite easy. We will use the XML to define the behavior of the animation and some Java to create the reference and the initiation. Note that, I have created 3 buttons to start the animation. Continue reading

Android Tutorial: Prank app with SoundPool and MediaPlayer

In the last days I worked on a small prank app to try out how to set random events or actions in Android. I give it some thought to come up with a fun app to try out random events or actions in Android. I’m a fan of the Walking Dead TV show so why not develop a small Walking Dead app :)

In the app you are confronted with a close door, in which you need to pick the lock. After random clicks (or picks) the door opens and a zombie of the Walking Dead appears. Also the zombie which appears is based on a random selection. To make the app complete I added some special effects so to speak. A theme song to the app and a moaning zombie when you open the door plus the phone vibrates when you picked the lock successfully. Hopefully you get a bit scared with these special effects ;)

In this video you can see a small demo of the Walking Dead Prank App.

So lets start with the layout of our Walking Dead app. First we create 2 buttons in the layout. One Button that will function as a back button which will only be visible after you opened the door. The second button is the actual lock you need to pick. Later we will change this to a custom button as it needs to look like an actual lock.

<RelativeLayout 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:id="@+id/background"
    android:background="@drawable/backgrounddoor">

    <Button
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="132dp"
        android:background="@drawable/buttons" />

    <Button
        android:id="@+id/btnback"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_marginBottom="38dp"
        android:layout_marginLeft="16dp"
        android:text="Back" />

</RelativeLayout>

Its pretty straightforward, but maybe worthwhile to mention, is how to set the background (the door) via the XML. You can set this via the property: android:background=”@drawable/backgrounddoor” (make sure you have the background image accessible via your drawable folder).

The user will have to pick the lock by clicking multiple times on the lock. From a user perspective it should be clear to the user that the app is actually working. Therefore we make a lock which have a clear pressed and unpressed state which is visualized while pressing the lock. First, create 2 locks which are different in color setting or gradients. I have created two lock images: lock.png en lockpressed.png

Then make the reference via a separate XML file (e.g. buttons.xml). The buttons.xml should look like this:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item 
        android:state_pressed="true"
        android:drawable="@drawable/lockpressed" />
    <item 
       
        android:drawable="@drawable/lock" />
   
</selector>

Also make sure you make the reference from your activity_main.xml to this buttons.xml file. See the reference android:background=”@drawable/buttons” in the activity_main.xml

Now we are done with setting up the layout elements. If everything went well you have a layout with a lock and background. Note that the back button is visible in this view. We will later set this invisible in the first activity.

In total this app will have two java classes. One MainActivity and one separate class to manage the sound of the zombie. Right click on your project and add an additional java class and name it SoundManager.

In the first part you create the variables. You need the Android SoundPool class, a Hashmap to store the sound file after your application have load the mp3 file, the AudioManager of Android to handle your sound and finally a Context.

	
	private  SoundPool mSoundPool; 
	private  HashMap<Integer, Integer> mSoundPoolMap; 
	private  AudioManager  mAudioManager;
	private  Context mContext;

After you have declared your variables we will create a SoundManager method. The createSounds passes the context and create a new SoundPool and hashmap object. The first parameter in the SoundPool argument refers to the number of sounds which can play in parallel (in our case just 1).

	public void createSounds(Context theContext) { 
		 mContext = theContext;
	     mSoundPool = new SoundPool(1, AudioManager.STREAM_MUSIC, 0); 
	     mSoundPoolMap = new HashMap<Integer, Integer>(); 
	     mAudioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE); 	     
	} 

Third we create a method to add the sound. This way each sound file get indexed which is useful if we want to add additional sounds later in our app. For example when each zombie would have a different sound. In this tutorial we just keep it to one sound-file for all zombies.

	public void addSound(int Index,int SoundID)
	{
		mSoundPoolMap.put(1, mSoundPool.load(mContext, SoundID, 1));
	}
	

The next method is the actual play sound method. In this method we pass the index which we have created in the previous method. In this function we also use the sound settings (volume) as already been set by the device.

public void playSound(int index) { 
		
	     int streamVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); 
	     mSoundPool.play(mSoundPoolMap.get(index), streamVolume, streamVolume, 1, 0, 1f); 
	}
	
	public void playLoopedSound(int index) { 
		
	     int streamVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); 
	     mSoundPool.play(mSoundPoolMap.get(index), streamVolume, streamVolume, 1, -1, 1f); 
	}

See here the complete SoundManager Java class.

package com.christianpeeters.pranck;

import java.util.HashMap;

import android.content.Context;
import android.media.AudioManager;
import android.media.SoundPool;	

public class SoundManager {
	
	private  SoundPool mSoundPool; 
	private  HashMap<Integer, Integer> mSoundPoolMap; 
	private  AudioManager  mAudioManager;
	private  Context mContext;
	
		
	public void createSounds(Context theContext) { 
		 mContext = theContext;
	     mSoundPool = new SoundPool(1, AudioManager.STREAM_MUSIC, 0); 
	     mSoundPoolMap = new HashMap<Integer, Integer>(); 
	     mAudioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE); 	     
	} 
	
	public void addSound(int Index,int SoundID)
	{
		mSoundPoolMap.put(1, mSoundPool.load(mContext, SoundID, 1));
	}
	
	public void playSound(int index) { 
		
	     int streamVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); 
	     mSoundPool.play(mSoundPoolMap.get(index), streamVolume, streamVolume, 1, 0, 1f); 
	}
	
	public void playLoopedSound(int index) { 
		
	     int streamVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); 
	     mSoundPool.play(mSoundPoolMap.get(index), streamVolume, streamVolume, 1, -1, 1f); 
	}
	
}

Now that we have set the Java class we can start building the Main java class which operates the Walking Dead app.

First we need to set the variables we need:
- Create 2 buttons. One btnback for the back button and one button for the lock (btnlock).
- Create a SoundManager variable to initiate an object for the class we just created (SoundManager.java)
- Create a variable to generate a random number
- Create an Array which hold our zombie images (they should be in your drawable folder).
- Create a MediaPlayer variable.

	Button btnback, btnlock;
	private SoundManager mSoundManager;
	MediaPlayer player;
	private static final Random rgenerator = new Random();
	private static final Integer[] mImageIds = 
	    {R.drawable.suprisezombie0, R.drawable.suprisezombie1, R.drawable.suprisezombie2, 
		R.drawable.suprisezombie3, R.drawable.suprisezombie4};

As you probably have noticed I have used both the SoundPool as the MediaPlayer for Android. I wanted to configure a background sound in the app and noticed that this wasn’t possible with the SoundPool Manager of Android. Somehow, SoundPool only allows you to configure a sound after a certain event (e.g. button click) and doesn’t allow you to play a background sound. In case, you know how it is possible to use the SoundPool Manager to configure a background sound, please leave a comment on the end of this post.

So first we create the background sound of the app, I used the theme song for this of the Walking Dead. As you can see I have a raw folder with the Theme MP3 file. I have also set the looping on false. So the theme song is only played once. When the app is launched it will directly start the theme song.

Next, I created a new object of the SoundManager class, with index 1 referring to the raw folder with the zombiesound.

        player = MediaPlayer.create(this, R.raw.theme);
        player.setLooping(false); // Set looping
        player.setVolume(100,100);
        player.start();
        
        
        mSoundManager = new SoundManager();
        mSoundManager.createSounds(getBaseContext());
        mSoundManager.addSound(1, R.raw.zombiesound);
        

The next lines of codes are the references to the buttons, this should be straightforward. The btnback is set as invisible (Button.gone) as the back button should only appear after the user has picked the lock successfully.

        btnback = (Button)findViewById(R.id.btnback);
        btnback.setVisibility(Button.GONE);
        btnlock = (Button)findViewById(R.id.btn1);
        btnlock.setOnClickListener(this);
        }
   

The next step is to set the behavior of the lock when the user clicks on it. We want the user to have the feeling he has to pick a lock. Therefore, the user might have to click on the lock button several times before it opens the door. We do this by using the random number generator in the onClick method of the btnlock.
We create an if statement telling the button that the door should only open and perform the suprise() method after: the random number which is generated is equal to the number of clicks of the user on the btnlock. As a random number could be very large, and probably test the patience of the user to much we set a maximum and minimun on the number of clicks required or at least not more than 15 clicks.

	@Override
	public void onClick(View v) {
		
		// TODO Auto-generated method stub
		if (v.getId()==R.id.btn1) {
			int i = 15;
			int min = 3;
			int max = 8;

			
			if ((rgenerator.nextInt(max - min + 1) + min == 8) || (i<15)) {
			suprise();
			((Button) v).setOnClickListener(null);
			
			}
			
			}
	}	

The next step is to create the suprise effect of the app. When the user has successfully picked the lock the door opens and the follow things will happen:
- We stop the theme-song of the app (background sound)
- We create the soundeffect of a zombie screaming to the user :)
- We create the visual effect, that is one of the set of zombie images are displayed to the user
- And as cherry on the cake, we let the phone vibrate.

	private void suprise() {
	player.stop();
	soundeffect();
	visualeffect();
	vibrationeffect();
	}

In the soundeffect() method we play the sound of the SoundManager with Index 1
In the visualeffect() method we change the background image to one of the random images (method: changeImageResource()) and we make the back-button visible to the user. Plus we create an onClicklistener to tell the backbutton what to do (going back to the main screen).
In the vibratoreffect() we use the vibrator service of Android to create a new vibrator effect.

		private void soundeffect(){
			mSoundManager.playSound(1);
		}
	
		private void visualeffect() 	{
			
		changeImageResource();

		View b = findViewById(R.id.btn1);
		b.setVisibility(View.GONE);
		btnback.setVisibility(Button.VISIBLE);
		btnback.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View back) {
				
				Intent backevent = new Intent(getApplicationContext(), MainActivity.class);
				startActivity(backevent);

			}
		});
		}
		
		private void vibrationeffect() {
		Vibrator vib = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
		vib.vibrate(new long[]{ 0, 500, 0 }, -1);
		}
	

The changeImageResource method use the same random number generator which we used for the number of picks on the lock button. As we have in total five different zombie images we pass (5) in the integer which we create in this method. The next line just set the backgroundresource (or background image) based on the order of the Array we have created earlier.

		public void changeImageResource()
		{
		    int i = rgenerator.nextInt(5);
		    findViewById(R.id.background).setBackgroundResource(mImageIds[i]);
		    
		}
		

Finally, when the user clicks on the home button, we dont want the app to continue to play the theme-song. Therefore we call player.stop in the onPause().

Your complete MainActivity should now look like this:

package com.christianpeeters.pranck;

import java.util.Random;

import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Vibrator;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity implements OnClickListener{
	
	
	Button btnback, btnlock;
	private SoundManager mSoundManager;
	MediaPlayer player;
	private static final Random rgenerator = new Random();
	private static final Integer[] mImageIds = 
	    {R.drawable.suprisezombie0, R.drawable.suprisezombie1, R.drawable.suprisezombie2, 
		R.drawable.suprisezombie3, R.drawable.suprisezombie4};
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        
        player = MediaPlayer.create(this, R.raw.theme);
        player.setLooping(false); // Set looping
        player.setVolume(100,100);
        player.start();
        
        
        mSoundManager = new SoundManager();
        mSoundManager.createSounds(getBaseContext());
        mSoundManager.addSound(1, R.raw.zombiesound);
        
       
        btnback = (Button)findViewById(R.id.btnback);
        btnback.setVisibility(Button.GONE);
        btnlock = (Button)findViewById(R.id.btn1);
        btnlock.setOnClickListener(this);
        }
    
   
    	
	@Override
	public void onClick(View v) {
		
		// TODO Auto-generated method stub
		if (v.getId()==R.id.btn1) {
			int i = 15;
			int min = 3;
			int max = 8;

			
			if ((rgenerator.nextInt(max - min + 1) + min == 8) || (i<15)) {
			suprise();
			((Button) v).setOnClickListener(null);
			
			}
			
			}
	}	

	private void suprise() {
	player.stop();
	soundeffect();
	visualeffect();
	vibrationeffect();
	}

		private void soundeffect(){
			mSoundManager.playSound(1);
		}
	
		private void visualeffect() 	{
			
		changeImageResource();

		View b = findViewById(R.id.btn1);
		b.setVisibility(View.GONE);
		btnback.setVisibility(Button.VISIBLE);
		btnback.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View back) {
				
				Intent backevent = new Intent(getApplicationContext(), MainActivity.class);
				startActivity(backevent);

			}
		});
		}
		
		private void vibrationeffect() {
		Vibrator vib = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
		vib.vibrate(new long[]{ 0, 500, 0 }, -1);
		}
	
		
		public void changeImageResource()
		{
		    int i = rgenerator.nextInt(5);
		    findViewById(R.id.background).setBackgroundResource(mImageIds[i]);
		    
		}
		
		
		@Override
		protected void onPause		() {
		    super.onPause();
		    player.stop();
		}
		
		
}


Android Tutorial: Fragments


In this tutorial I will provide an example how you can implement fragments. Fragments are often used to create the tabs in the action bar which can be clicked or swiped through. We will create a small app which explains some of the sights of the town Maastricht, Netherlands. Of course you can adjust the code for you own purposes.  Continue reading

findViewById in Android fragments

A quick post on how to add and set android widget behavior in a fragment implementation. Fragments in android don’t extend Activity but Fragment. This implies that your standard way of referring to android widgets won’t work e.g. Button btn = (Button)findViewById(R.id.btn1); Continue reading

Android Tutorial: CameraView with layar

 

 

 

 

 

In this Android tutorial we will launch the Camera and display an image in the CameraView. We will use the following Android programming concepts:

  • SurfaceView and SurfaceHolder to set the CameraView as part of our MainActivity
  • Seperate overlay.xml to set the image which we wan to display in the CameraView.

First we create 2 layout files (1) the layout which holds the SurfaceView and (2) the layout which hold the image we want to display.

Open you Activity_Main.xml and set a SurfaceView as a child of your LinearLayout.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<SurfaceView
	android:id="@+id/cameraview"  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    />
</LinearLayout>

Secondly create a new layout in your resources folder and name it overlay.xml and simple add an ImageView in this layout. This ImageView will hold the image your want to display in your CameraView.

<?xml version="1.0" encoding="utf-8"?>
	<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	 android:orientation="vertical"
	 android:layout_width="fill_parent"
	 android:layout_height="fill_parent"
	 android:gravity="bottom">
	
	    <ImageView
	        android:id="@+id/imageView1"
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:layout_gravity="center_horizontal"
	        android:src="@drawable/ringimage" />
	
	</LinearLayout>

Now you have set your layout, you can open the MainActivity.java.

  • We set the MainActivity to our layout (Activity_Main.xml) and set the ScreenLayout to Horizontal.
  • Create a SurfaceView and set it to your cameraview which you created in your Activity_Main layout.
  • Implement the SurfaceHolder which holds this cameraviev

Next we need to inflate the Image we set in our overlay.xml.

  • Call the LayoutInflater
  • Set your LayoutInflater to your image (in my case overlay.xml which holds the ImageView)
  • Set some LayoutInflater parameters

Finally we need to set what we want the camera to do in the standard Android SDK methods of the SurfaceView (surfaceCreated, surfaceChanged, surfaceDestroyed).

package com.christianpeeters.ghost;

import java.io.IOException;

import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup.LayoutParams;

public class MainActivity extends Activity implements SurfaceHolder.Callback{

Camera camera;
SurfaceView surfaceView;
SurfaceHolder surfaceHolder;
boolean cameraview = false;
LayoutInflater inflater = null;

 /** Called when the activity is first created. */
	 @Override
	 public void onCreate(Bundle savedInstanceState) {
	     super.onCreate(savedInstanceState);
	     setContentView(R.layout.activity_main);
	     setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

	     getWindow().setFormat(PixelFormat.UNKNOWN);
	     surfaceView = (SurfaceView)findViewById(R.id.cameraview);
	     surfaceHolder = surfaceView.getHolder();
	     surfaceHolder.addCallback(this);
	     surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

	     inflater = LayoutInflater.from(getBaseContext());
	     View view = inflater.inflate(R.layout.overlay, null);
	     LayoutParams layoutParamsControl= new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
	     this.addContentView(view, layoutParamsControl);

	 	}

 	@Override
 	public void surfaceChanged(SurfaceHolder holder, int format, int width,
 	int height) {
 		// TODO Auto-generated method stub
		if(cameraview){
		camera.stopPreview();
		cameraview = false;
		}	

		if (camera != null){
		try {
		camera.setPreviewDisplay(surfaceHolder);
		camera.startPreview();
		cameraview = true;
		} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
				}
			}
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		// TODO Auto-generated method stub
		camera = Camera.open();
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
	// TODO Auto-generated method stub
	camera.stopPreview();
	camera.release();
	camera = null;
	cameraview = false;
	}
	}

Android Tutorial: Launch URL based on an OnClickListener

As a beginner in Android you spent often a long time on something very simple ;). Often because you miss some crucial knowledge, but don’t get frustrated, my experience is that you learn different concepts along the way and it becomes easier and easier to find solutions to problems you did’t solve before. In this short blog post I show you how you can launch an URL (website) based on OnClickListener event (for e.g. Button Click). Continue reading

Android Tutorial: Calculator App

With this blog post you can build an Android calculator app for calculating different absolute outcomes for different sets of discount percentages. It’s a simple app were the user can set e.g. the price of a retail item and calculate his/her savings and final price when the retail price gets discounted with a certain percentage (e.g. 25%).  Continue reading

Android Tutorial Part IV – Email Intent – UAT Tester App

This is the last part of the UAT tester app tutorial for Android. In case you have missed the previous Tutorial click on the links below.

Android Tutorial Part I – Setting the layout
Android Tutorial Part II – Setting the reference variables
Android Tutorial Part III – Pick Gallery Image

In this last tutorial will we set the email intent, meaning that the user can pass the information of the UAT tester app to an installed email-client and send the information to for example the Test Manager.  Continue reading