Smartphones

Android summer fun: Write a screen crack prank

Android developer William J. Francis combines techniques he has shown in several previous tutorials to make a functional screen crack prank.

Since I began developing for Android three years ago, it's become a tradition around my house to engage my son in some kind of just-for-fun programming venture each summer (usually about the time he's become bored hanging around the house all day but not yet willing to admit he is ready for school to start back up). Last summer we created our own sound board, and to my surprise, it was a big hit with readers and generated a number emails and some cool follow-up articles.

This year I thought I'd try to turn it up a notch. In this tutorial we'll combine principles from the aforementioned sound board post, plus the capture the flag post, and last week's post on Android's vibrator service. The result is the infamous screen crack prank--an innocent-looking program that entices the user to press a button as fast as humanly possible, only to cause the phone to suddenly vibrate, make a sound like glass breaking, and draw a realistic crack on the display. I know, it's childish, but hey, that's what makes it fun! You can either follow along with the tutorial below, or download and import the project.

1. Create a new project in Eclipse targeted at Android 1.6 or above. Be sure to change the startup activity to Main.java.

2. Let's begin by editing our AndroidManifest.xml file. We'll not only be adding the vibrate permission, but we'll be adding orientation and config change overrides to the activity so the screen doesn't reset when the phone is turned. This is a property used almost exclusively for games and needs to be used with care since in most cases having an activity restart and reload resources is the desired behavior.

AndroidManifest.XML
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.authorwjf.tapper"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="4" />
<uses-permission android:name="android.permission.VIBRATE" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".Main"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:configChanges="keyboardHidden|orientation" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

3. We need to add a couple resources. I've created a /res/raw folder for my sound bit, glass.ogg, and a /res/drawable folder for my image, cracked_screen.png.

4. In the /res/layout folder, we need to define our main.xml layout. A linear layout hosting two text views and a button are just what we need.

main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:id="@+id/background">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Tapper!"
android:textStyle="bold"
android:textColor="#00ff00"
android:textSize="20sp"
android:layout_margin="20dip"
android:gravity="center"
android:id="@+id/title"/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#ffffff"
android:layout_margin="20dip"
android:text="INSTRUCTIONS:\n\nTry to tap the button 100 times in under 30 seconds.\n\nGood Luck!"
android:id="@+id/blurb"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dip"
android:padding="25dip"
android:text="100"
android:layout_gravity="center"
android:id="@+id/button"/>
</LinearLayout>

5. Now that all of our resources are in place and the manifest is prepared, it's time to write code. In our main.java file, we will start by overriding on create where we will wire up our button and pre-load the sound file.

Main.java
package com.authorwjf.tapper;
import java.util.HashMap;
import java.util.Random;
import android.app.Activity;
import android.content.Context;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Bundle;
import android.os.Vibrator;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class Main extends Activity implements OnClickListener{
private SoundPool  sp;
AudioManager am;
private HashMap<Integer, Integer> map;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
preloadSoundMap();
((Button) findViewById(R.id.button)).setOnClickListener(this);
}
private void preloadSoundMap() {
sp = new SoundPool(1, AudioManager.STREAM_MUSIC, 0);
am = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
map = new HashMap<Integer, Integer>();
map.put(1, sp.load(this, R.raw.glass, 1));
}
}

6. Next comes our on click handler where we use a random number generator to see if it's time to spring our prank. Let's go ahead and stub out our crack function too.

@Override
public void onClick(View v) {
if (v.getId()==R.id.button) {
int i = Integer.parseInt(((Button) v).getText().toString());
((Button) v).setText(Integer.toString(--i));
Random gen = new Random();
if ((gen.nextInt(10 - 1 + 1) + 1 == 10) || (i<50)) {
crack();
((Button) v).setOnClickListener(null);
}
}
}
private void crack() {
audibleFX();
visualFX();
touchFX();
}

7. Now we can fire off our effect functions in order. First the sound effect, then the visual effect, and finally the vibration.

private void audibleFX() {
float streamVolume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
sp.play(map.get(1), streamVolume, streamVolume, 1, 0, 1f);
}
private void visualFX() {
findViewById(R.id.background).setBackgroundResource(R.drawable.cracked_screen);
((TextView)findViewById(R.id.title)).setTextColor(0x6400ff00);
((TextView)findViewById(R.id.blurb)).setTextColor(0x64ffffff);
((Button)findViewById(R.id.button)).setBackgroundColor(0x64cdc9c9);
}
private void touchFX() {
Vibrator mv = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
mv.vibrate(new long[]{ 0, 500, 0 }, -1);
}
We're finished, and that means we are ready to have some fun. Time to load the app to your device and...(wait for it)...get cracking (Figure A). Figure A

If you have any questions or comments that aren't about the terrible pun, post them in the discussion thread.

About

William J Francis began programming computers at age eleven. Specializing in embedded and mobile platforms, he has more than 20 years of professional software engineering under his belt, including a four year stint in the US Army's Military Intellige...

1 comments
authorwjf
authorwjf

Sorry I'm not sure why you'd be getting an error on the orientation attribute. Did you download the entire source package or just cut and paste from the website?