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 →
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.
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:
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.
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.
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.
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.
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.
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();
}
}
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 →
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 →
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.
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;
}
}
In this post a small android app is build which makes use of the gridview layout. The app consist of a gridview with images from the Android Play Market, when clicking on each of the items a dialog pop-up will appear with a small text with either a cancel of download button. Continue reading →
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 →
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 →
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 →
You probably know your able to test drive your apps via the emulator which is part of the Android SDK. The emulator has advantage to set e.g. different screen-layouts etc, but personally I like to test drive my apps on an actual device. In this post I explain how you can very easily test your apps with a real Android device. Continue reading →