You are on page 1of 5

animated LiveWallpaper API that allows developers to create

interactive wallpaper that users may choose to run as part of their home page

handlers, part of the Android thread system that enhances


interactivity

Live Wallpaper
2.1 (API Level 7)
is a wallpaper (a
background set on the home screen) that may be animated and enabled for interaction
LiveWallpaperService

example
live wallpaper that is touch-enabled and utilizes
the Internet (via the Yamba Manager) in order to place some text at the point of
touch
Manifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.marakana.android.yamba">
<application>
<service
android:label="@string/app_name"
android:icon="@drawable/ic_launcher"
android:name=".YambaWallpaper"
android:permission="android.permission.BIND_WALLPAPER">
<intent-filter>
<action
android:name="android.service.wallpaper.WallpaperService" />
</intent-filter>
<meta-data android:name="android.service.wallpaper"
android:resource="@xml/wallpaper" />
LiveWallpaper Service Resource XMLres/xml
//To achieve a simple animation effect, we’ll be drawing on a canvas. The wallpaper
will
// display recent Yamba status updates, and we’ll interact with the user by letting
her choose where on the screen the updates should appear
//drawing and animation in general are beyond the scope
//primary class, extending the base class WallpaperService

public class YambaWallpaper extends WallpaperService {


@Override
public Engine onCreateEngine() {// called at creation time and returns a
WallpaperService.Engine object.
//That responsible for handling the wallpaper’s life cycle as well as the
graphical and interactive aspects of the wallpaper
return new YambaWallpaperEngine(((YambaApplication)
getApplication()).getYambaClient());}
//create the YambaWallpa perEngine private class and create it via the
onCreateEngine()
//YambaWallpaperEngine itself contains the other two classes. TextPoint is a data
struc‐
ture containing a string (the text) and two coordinates (x and y) that represent
screen
locations
private class YambaWallpaperEngine extends Engine implements Runnable {
private Handler handler = new Handler();
//special thread that loops continuously. At regular intervals
it invokes the getContent() method, which attempts to get YambaClient.Status ob‐
jects via the getTimeline() method in the YambaClient. These objects contain text
statuses that have been sent to the Yamba API Web Service. If content comes back,
we
store the text of these statuses and then wait a minute before checking for content
again.
If there is no content during this call, we wait two seconds and see again whether
we
can get content
private ContentThread contentThread = new ContentThread();
private YambaClient yambaclient;
private Paint paint;
private String[] content = new String[20];
private TextPoint[] textPoints = new TextPoint[20];
private int current = -1;
private boolean running = true;
private float offset = 0;
public YambaWallpaperEngine(YambaClient client) {
yambaclient = client;
paint = new Paint();
paint.setColor(0xffffffff);
paint.setAntiAlias(true);
paint.setStrokeWidth(1);
paint.setStrokeCap(Paint.Cap.SQUARE);
paint.setStyle(Paint.Style.FILL);
paint.setTextSize(40);}
//As a
class that extends android.service.wallpaper.WallpaperService.Engine, it is the
piece of code that handles the life cycle and drawing that occurs in the wallpaper.
When
the engine is created, the runtime calls its onCreate() method, where we start the
ContentThread. After the engine is created
@Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
running = true;
contentThread.start();
// enable touch events
setTouchEventsEnabled(true);}
@Override
public void onDestroy() {
super.onDestroy();
handler.removeCallbacks(this);
running = false;
synchronized(contentThread) {
contentThread.interrupt();}
}
//making the wallpaper
visible
@Override
public void onVisibilityChanged(boolean visible) {
if (visible) {
drawFrame();
} else {
handler.removeCallbacks(this);}}
@Override
public void onSurfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
super.onSurfaceChanged(holder, format, width, height);
drawFrame();}
@Override
public void onSurfaceCreated(SurfaceHolder holder)
{super.onSurfaceCreated(holder);}
@Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
super.onSurfaceDestroyed(holder);
handler.removeCallbacks(this);}
@Override
public void onOffsetsChanged(float xOffset, float yOffset,
float xStep, float yStep, int xPixels, int yPixels) {
offset = xPixels;
drawFrame();}
@Override
public void onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
current++;
if(current >= textPoints.length) {
current = 0;
}
String text = content[current];
if(text != null) {
textPoints[current] = new TextPoint(text, event.getX() -
offset, event.getY());
}
}
super.onTouchEvent(event);
}
@Override
public void run() {
drawFrame();
}
private void drawFrame() {
final SurfaceHolder holder = getSurfaceHolder();
Canvas c = null;
try {
c = holder.lockCanvas();
if (c != null) {
// draw text
drawText(c);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (c != null) {
holder.unlockCanvasAndPost(c);
}
}
// Reschedule the next redraw
handler.removeCallbacks(this);
if (isVisible()) {
handler.postDelayed(this, 40); // 40 ms = 25 frames per second
}
}
private boolean getContent() {
List<YambaClient.Status> timeline = null;
try {
timeline = yambaclient.getTimeline(20);
int i = -1;
content = new String[20];
if(timeline != null) {
for(YambaClient.Status status: timeline) {
i++;
content[i] = status.getMessage();
}
}
} catch (Exception e) {}
return timeline != null && !timeline.isEmpty();
}
private void drawText(Canvas c) {
c.drawColor(Color.BLACK);
for(TextPoint textpoint: textPoints) {
if(textpoint != null) {
c.drawText(textpoint.text,
textpoint.x + offset,
textpoint.y, paint);
}
}
}
private class TextPoint {
public String text;
public float x;
public float y;
public TextPoint(String t, float xp, float yp) {
text = t;
x = xp;
y = yp;
}
}
private class ContentThread extends Thread {
public void run() {
while(running) {
try {
boolean hascontent = getContent();
if(hascontent) {
Thread.sleep(60000); // 1 min
} else {
Thread.sleep(2000); // 2 s
}
} catch (InterruptedException ie) {
return;
} catch (Exception e) {}
}
}
}
}
}

You might also like