`

Creating Android live wallpaper[转]

阅读更多
As you all know live wallpaper is introduced in Android from version 2.1 onwards. Live wallpapers are animated backgrounds for your home screen. You can set your live wallpaper by long pressing the home screen and selecting Wallpapers->Live Wallpaper menu item. A list of live wallpapers installed in the system will be shown and you can select one of them to make it active. Live Wallpaper is like a normal application Android and can use any feature that normal application uses like MapView, Accelerometer, GPS, etc.

Live Wallpaper is like a normal service application in Android. It has two components, WallpaperService and WallpaperService.Engine. The service component is like normal service application but with extra method onCreateEngine(). The purpose of this method is to return a instance of Wallpaper.Engine class which actually do all the tasks including drawing wallpaper and managing the lifetime. The WallpaperService will call the onCreateEngine() method when a wallpaper is active. A wallpaper can provide a settings screen if needed. Settings screen can be used to configure the wallpaper (in our sample application we provide this settings screen to select the pattern to draw on the wallpaper screen, see the sample application section).

To create our own wallpaper we create the WallpaperService and override the onCreateEngine method. Then specify the wallpaper in AndroidManifest.xml file. Following is sample manifest entry:

<application android:label="@string/app_name" android:icon="@drawable/icon">
<service android:label="@string/wallpaper_pattern" android:permission="android.permission.BIND_WALLPAPER" android:name="com.varma.samples.patternwallpaper.PatternWallpaper">
        <intent-filter>
                <action android:name="android.service.wallpaper.WallpaperService" />
</intent-filter>
            <meta-data android:name="android.service.wallpaper" android:resource="@xml/patternwallpaper" />
        </service>

<activity android:label="@string/wallpaper_settings" android:name="com.varma.samples.patternwallpaper.PatternWallpaperSettings" android:exported="true"/>

</application>The <service> specifies our wallpaper service. The <intnet-filter> should be android.service.wallpaper.WallpaperService. We should create an XML resource that specify our wallpaper service and give it in <meta-data> tag to describe the wallpaper. Finally we have to specify the settings activity if there is any. In addition to this, we have to specify the <users-sdk> and <uses-feature> tags, the <users-sdk> tag should specify 7 or above since the feature is only available 7 or above. A sample entry is:

<uses-sdk android:minSdkVersion="7" />
<uses-feature android:name="android.software.live_wallpaper" />Once we specify these entries we create a service and extend from WallpaperService class and override the onCreateEngine method. From this method we return our own instance of WallpaperService.Engine implementation. The system will provide a SurfaceView class for drawing purpose. The WallpaperService.Engine has following important method which we have to override to implement the wallpaper engine:

public void onCreate(SurfaceHolder surfaceHolder) Called while creating the Wallpaper.Engine object. Note that the system provides a SurfaceHolder implementation
public void onDestroy() Called while destroying the object
public void onOffsetsChanged(

float xOffset,

float yOffset,

float xOffsetStep,

float yOffsetStep,

int xPixelOffset,

int yPixelOffset)
Called when offsets changed.
public void onSurfaceChanged(

SurfaceHolder holder,

int format,

int width,

int height)
Called when the SurfaceHolder’s surface is changed.
public void onSurfaceCreated(SurfaceHolder holder) Called when the SurfaceHolder’s surface is created.
public void onSurfaceDestroyed(SurfaceHolder holder) Called when the SurfaceHolder is destroyed.
public void onVisibilityChanged(boolean visible) Called when the visibility of the wallpaper changed. The parameter visible is true when visible otherwise false. Here we have to start and stop drawing depending on the visibility.
public void onTouchEvent (MotionEvent event) Called when touch events occurred. There are different events, some of them are:

android.wallpaper.tap

when the user taps the home screen.

android.home.drop

when the user drops an icon on home screen.

Our sample application does not use onTouchEvent but a live wallpaper can use this to implement different effects.


Normally while creating wallpaper we override these method and start ad stop the drawing in onVisibilityChanged. For drawing the wallpaper we create separate thread or a runnable routine. The following code snippet creates a runnable routine:

private final Runnable drawrunnable = new Runnable() {
public void run() {
draw();
}
};


The draw method actually draws the wallpaper. In this method we post the drawrunnable routine every 5 seconds using a Handler class. The draw method implementation is (from sample application):

private void draw(){
final SurfaceHolder holder = getSurfaceHolder();
Canvas canvas = null;

handler.removeCallbacks(drawrunnable);

try
{
canvas = holder.lockCanvas();

drawPattern(canvas);
}
finally
{
if (canvas != null)
holder.unlockCanvasAndPost(canvas);
}

if(isVisible)
{
handler.postDelayed(drawrunnable,DRAW_DELAY);
}
}Sample Application

The sample application of this article is a simple live wallpaper that draws three different pattern; spirograph, circle pattern and sierpinski triangle. Use can choose the pattern to draw. The pattern is drawn with random values in every 5 seconds.


原文http://www.androiddevblog.net/android/creating-android-live-wallpaper
分享到:
评论
8 楼 csj2017 2011-09-15  
   
7 楼 w11h22j33 2011-01-21  
http://developer.android.com/resources/samples/CubeLiveWallpaper/index.html
6 楼 w11h22j33 2011-01-21  
http://code.google.com/p/andenginelivewallpaperextensionexample/
5 楼 w11h22j33 2011-01-20  
package com.sysu.zrp;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Handler;
import android.service.wallpaper.WallpaperService;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;

public class christmas_snow extends WallpaperService
{
        private final Handler mHandler = new Handler();
        public static int diswidth;
        public static int disheight;
       
        class snow_engine extends Engine
        {
                private Paint mpaint;
                private snowset_control mcontrol;
                private boolean mVisible;
                private Bitmap bmptmp;
                private startset set;
                private startsetthread thread;
               
                private final Runnable docontrol=new Runnable()
                {
                        public void run()
                        {
                                mcontrol.move_del_snow();
                                mcontrol.create_snow();
                                ondraw();
                        }
                };
               
                snow_engine()
                {
                        ini();
                }
               
                private void ondraw()
                {
                        final SurfaceHolder holder=getSurfaceHolder();
                        Canvas canvastmp=null;
                        canvastmp=holder.lockCanvas();
                        canvastmp.drawBitmap(bmptmp, 0, 0, null);
                        mcontrol.draw_snow(canvastmp, mpaint);
                        set.dodraw(canvastmp);
                        holder.unlockCanvasAndPost(canvastmp);
                        mHandler.removeCallbacks(docontrol);
                        if (mVisible)
            {
                mHandler.postDelayed(docontrol, 40);
            }
                }
               
                private void ini()
                {
                        DisplayMetrics dm = getResources().getDisplayMetrics();
                        diswidth=dm.widthPixels;
                        disheight=dm.heightPixels;
                        thread=new startsetthread();
                        set=thread.setthread;
                        mpaint=new Paint();
                        mpaint.setColor(0xffffffff);
                        mpaint.setAntiAlias(true);
                        mpaint.setStrokeWidth(2);
                        mpaint.setStrokeCap(Paint.Cap.ROUND);
                        mpaint.setStyle(Paint.Style.FILL);
                        mcontrol=new snowset_control();
                        mVisible=false;
                        int id;
                        if(diswidth>320)
                        {
                                id=R.drawable.tree480;
                        }
                        else
                        {
                                id=R.drawable.tree320;
                        }
                        bmptmp=BitmapFactory.decodeResource(getResources(), id);
                }
       
                public void onCreate(SurfaceHolder surfaceHolder)
        {
            setTouchEventsEnabled(true);
            super.onCreate(surfaceHolder);
        }       
               
                public void onSurfaceCreate(SurfaceHolder holder)
                {
                        super.onSurfaceCreated(holder);
                }
               
                public void onDestroy()
        {
            mHandler.removeCallbacks(docontrol);
            super.onDestroy();
        }
                public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height)
        {
                        DisplayMetrics dm = getResources().getDisplayMetrics();
                        diswidth=dm.widthPixels;
                        disheight=dm.heightPixels;
                        int id;
                        if(diswidth>320)
                        {
                                id=R.drawable.tree480;
                        }
                        else
                        {
                                id=R.drawable.tree320;
                        }
                        bmptmp=BitmapFactory.decodeResource(getResources(), id);
            docontrol.run();
            if(!thread.isAlive())
            {
                    thread.start();
            }
            super.onSurfaceChanged(holder, format, width, height);
        }
                public void onSurfaceDestroyed(SurfaceHolder holder)
        {
                        thread.flag=false;
                        thread.stop();
                        mVisible=false;
            mHandler.removeCallbacks(docontrol);
            super.onSurfaceDestroyed(holder);
        }
                public void onVisibilityChanged(boolean visible)
        {
            mVisible = visible;
            if (visible)
            {
                docontrol.run();
            }
            else
            {
                mHandler.removeCallbacks(docontrol);
            }
            super.onVisibilityChanged(visible);
        }
                public void onTouchEvent(MotionEvent event)
                {
                        if(event.getAction()==MotionEvent.ACTION_DOWN)
                        {
                                double xtouch=event.getX();
                                double ytouch=event.getY();
                                 mcontrol.blip(xtouch, ytouch);
                        }
                }
    }

        public Engine onCreateEngine()
        {
                return new snow_engine();
        }

}
3 楼 w11h22j33 2011-01-20  
不要使用Thread
应直接使用Handler与Runnable接口对象组合运行。

使用Thread会产生一些莫名其妙的问题,比如:壁纸预览时报错;壁纸设置时报错;壁纸设置后闪一下即消失变为默认静态壁纸;壁纸设置后停止运行但切换到待机状态再切回还是能运行的。

当壁纸设置后消失时,在DDMS中看到产生的异常信息类似:



01-13 03:04:53.734: INFO/DEBUG(1856): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
01-13 03:04:53.734: INFO/DEBUG(1856): Build fingerprint: 'hkcsl_cht/htc_bravo/bravo/bravo:2.2/FRF91/236241:user/release-keys'
01-13 03:04:53.734: INFO/DEBUG(1856): pid: 2830, tid: 2867  >>> com.skyd.mantrawheel <<<
01-13 03:04:53.734: INFO/DEBUG(1856): signal 11 (SIGSEGV), fault addr deadbaad
01-13 03:04:53.734: INFO/DEBUG(1856):  r0 00000000  r1 afd14699  r2 00000027  r3 00000074
01-13 03:04:53.734: INFO/DEBUG(1856):  r4 afd42328  r5 00000000  r6 00000000  r7 0000a000
01-13 03:04:53.734: INFO/DEBUG(1856):  r8 00000000  r9 48533900  10 485338d8  fp 000001e0
01-13 03:04:53.734: INFO/DEBUG(1856):  ip 00001730  sp 48533590  lr deadbaad  pc afd11cf0  cpsr 60000030
01-13 03:04:53.734: INFO/DEBUG(1856):  d0  643a64696f72646e  d1  6472656767756265
01-13 03:04:53.734: INFO/DEBUG(1856):  d2  062b818b0627c18a  d3  0633418d062f818c
01-13 03:04:53.734: INFO/DEBUG(1856):  d4  0000018f0000018f  d5  0000018f0000018f
01-13 03:04:53.734: INFO/DEBUG(1856):  d6  be6659913f797051  d7  0000000043c24000
01-13 03:04:53.734: INFO/DEBUG(1856):  d8  000001e000000000  d9  40790000000000a0
01-13 03:04:53.734: INFO/DEBUG(1856):  d10 3fd34413509f79fe  d11 bfe3441350ad386e
01-13 03:04:53.734: INFO/DEBUG(1856):  d12 3ddb7cdfd9d7bdbb  d13 0000000000000000
01-13 03:04:53.734: INFO/DEBUG(1856):  d14 0000000000000000  d15 0000000000000000
01-13 03:04:53.734: INFO/DEBUG(1856):  d16 018e41d4018e7b6a  d17 018dcea8018e083e
01-13 03:04:53.734: INFO/DEBUG(1856):  d18 018ed1b2018dd842  d19 0190c492018fcb22
01-13 03:04:53.734: INFO/DEBUG(1856):  d20 0000000000000000  d21 0000000000000000
01-13 03:04:53.734: INFO/DEBUG(1856):  d22 0000018f0000018f  d23 0000018f0000018f
01-13 03:04:53.744: INFO/DEBUG(1856):  d24 0000018f0000018f  d25 0000018f0000018f
01-13 03:04:53.744: INFO/DEBUG(1856):  d26 ffff19a8ffff19a8  d27 ffff19a8ffff19a8
01-13 03:04:53.744: INFO/DEBUG(1856):  d28 0003e5c00003e5c0  d29 0003e5c00003e5c0
01-13 03:04:53.744: INFO/DEBUG(1856):  d30 0001000000010000  d31 0001000000010000
01-13 03:04:53.744: INFO/DEBUG(1856):  scr 60000012
01-13 03:04:53.814: INFO/DEBUG(1856):          #00  pc 00011cf0  /system/lib/libc.so
01-13 03:04:53.814: INFO/DEBUG(1856):          #01  pc 0000be62  /system/lib/libc.so
01-13 03:04:53.814: INFO/DEBUG(1856):          #02  pc 0000cdc2  /system/lib/libc.so
01-13 03:04:53.814: INFO/DEBUG(1856):          #03  pc 000008d8  /system/lib/libstdc++.so
01-13 03:04:53.814: INFO/DEBUG(1856):          #04  pc 0004d3f8  /system/lib/libskia.so
01-13 03:04:53.814: INFO/DEBUG(1856):          #05  pc 0006ad50  /system/lib/libskia.so
01-13 03:04:53.814: INFO/DEBUG(1856):          #06  pc 0006d5b0  /system/lib/libskia.so
01-13 03:04:53.814: INFO/DEBUG(1856): code around pc:
01-13 03:04:53.814: INFO/DEBUG(1856): afd11cd0 2d00682d e029d1fb b12b68db c05cf8df
01-13 03:04:53.814: INFO/DEBUG(1856): afd11ce0 f8442001 4798000c e054f8df 26002227
01-13 03:04:53.814: INFO/DEBUG(1856): afd11cf0 2000f88e eee4f7fb f7fd2106 f04fe802
01-13 03:04:53.814: INFO/DEBUG(1856): afd11d00 91035180 460aa901 96012006 f7fc9602
01-13 03:04:53.814: INFO/DEBUG(1856): afd11d10 a905eb88 20024632 eb92f7fc eed0f7fb
01-13 03:04:53.814: INFO/DEBUG(1856): code around lr:
01-13 03:04:53.814: INFO/DEBUG(1856): deadba8c ffffffff ffffffff ffffffff ffffffff
01-13 03:04:53.814: INFO/DEBUG(1856): deadba9c ffffffff ffffffff ffffffff ffffffff
01-13 03:04:53.814: INFO/DEBUG(1856): deadbaac ffffffff ffffffff ffffffff ffffffff
01-13 03:04:53.814: INFO/DEBUG(1856): deadbabc ffffffff ffffffff ffffffff ffffffff
01-13 03:04:53.814: INFO/DEBUG(1856): deadbacc ffffffff ffffffff ffffffff ffffffff
01-13 03:04:53.814: INFO/DEBUG(1856): stack:
01-13 03:04:53.814: INFO/DEBUG(1856):     48533550  00000015 
01-13 03:04:53.814: INFO/DEBUG(1856):     48533554  afd146c9  /system/lib/libc.so
01-13 03:04:53.814: INFO/DEBUG(1856):     48533558  afd425a0  /system/lib/libc.so
01-13 03:04:53.814: INFO/DEBUG(1856):     4853355c  afd4254c  /system/lib/libc.so
01-13 03:04:53.814: INFO/DEBUG(1856):     48533560  00000000 
01-13 03:04:53.814: INFO/DEBUG(1856):     48533564  afd156e3  /system/lib/libc.so
01-13 03:04:53.814: INFO/DEBUG(1856):     48533568  afd14699  /system/lib/libc.so
01-13 03:04:53.814: INFO/DEBUG(1856):     4853356c  afd14699  /system/lib/libc.so
01-13 03:04:53.814: INFO/DEBUG(1856):     48533570  00000074 
01-13 03:04:53.814: INFO/DEBUG(1856):     48533574  afd42328  /system/lib/libc.so
01-13 03:04:53.814: INFO/DEBUG(1856):     48533578  00000000 
01-13 03:04:53.814: INFO/DEBUG(1856):     4853357c  485335a4 
01-13 03:04:53.814: INFO/DEBUG(1856):     48533580  0000a000  [heap]
01-13 03:04:53.814: INFO/DEBUG(1856):     48533584  afd1493b  /system/lib/libc.so
01-13 03:04:53.814: INFO/DEBUG(1856):     48533588  df002777 
01-13 03:04:53.814: INFO/DEBUG(1856):     4853358c  e3a070ad 
01-13 03:04:53.814: INFO/DEBUG(1856): #00 48533590  afd438e4  /system/lib/libc.so
01-13 03:04:53.814: INFO/DEBUG(1856):     48533594  afd1040c  /system/lib/libc.so
01-13 03:04:53.814: INFO/DEBUG(1856):     48533598  afd42328  /system/lib/libc.so
01-13 03:04:53.814: INFO/DEBUG(1856):     4853359c  48e40628 
01-13 03:04:53.814: INFO/DEBUG(1856):     485335a0  48e40628 
01-13 03:04:53.814: INFO/DEBUG(1856):     485335a4  fffffbdf 
01-13 03:04:53.814: INFO/DEBUG(1856):     485335a8  afd42328  /system/lib/libc.so
01-13 03:04:53.814: INFO/DEBUG(1856):     485335ac  afd4372c  /system/lib/libc.so
01-13 03:04:53.814: INFO/DEBUG(1856):     485335b0  48e40628 
01-13 03:04:53.814: INFO/DEBUG(1856):     485335b4  afd0be67  /system/lib/libc.so
01-13 03:04:53.814: INFO/DEBUG(1856): #01 485335b8  48e40660 
01-13 03:04:53.814: INFO/DEBUG(1856):     485335bc  00142180  [heap]
01-13 03:04:53.814: INFO/DEBUG(1856):     485335c0  00001404 
01-13 03:04:53.814: INFO/DEBUG(1856):     485335c4  485338b0 
01-13 03:04:53.814: INFO/DEBUG(1856):     485335c8  00000000 
01-13 03:04:53.814: INFO/DEBUG(1856):     485335cc  48e40628 
01-13 03:04:53.814: INFO/DEBUG(1856):     485335d0  48e40628 
01-13 03:04:53.814: INFO/DEBUG(1856):     485335d4  00000000 
01-13 03:04:53.814: INFO/DEBUG(1856):     485335d8  485338b0 
01-13 03:04:53.814: INFO/DEBUG(1856):     485335dc  afd0cdc5  /system/lib/libc.so





目前经过多次尝试仍未探知具体出错的地方。



可以指定一个Activity为动态壁纸设置界面
需在壁纸设置文件中这样指定:

<?xml  version="1.0"  encoding="utf-8"?>
<wallpaper  xmlns:android="http://schemas.android.com/apk/res/android"
android:author="@+string/author"
android:description="@string/description"
android:thumbnail="@drawable/mani1"
android:settingsActivity="com.skyd.mantrawheel.Main"
/>

并且该Activity必须在AndroidManifest.xml中这样注册:

<activity android:name=".Main" android:label="@string/app_name" android:exported="true"></activity>



最好指定uses-feature标记
在AndroidManifest.xml中指定如下代码会使程序在市场中对不支持动态壁纸功能的用户隐藏:

<uses-feature android:name="android.software.live_wallpaper" />



必须在onCreate(SurfaceHolder surfaceHolder)中指定setTouchEventsEnabled(true);
如果你放在onSurfaceCreated(SurfaceHolder holder)中指定,你会很郁闷地发现动态壁纸在2.1版本的系统中可以运行,2.2版本却报错。
2 楼 w11h22j33 2011-01-20  
参考资料
http://www.androiddevblog.net/android/creating-android-live-wallpaper#

http://code.google.com/p/krvarma-android-samples/source/browse/trunk/patternwallpaper/?r=80
1 楼 w11h22j33 2011-01-20  
一:定义一个壁纸类继承WallpaperService

关键的继承方法为

@Override
public Engine onCreateEngine() {

  return new MyWallEngine(this.getBaseContext());
}

具体的实现就像如何实现一个Engine类

android.service.wallpaper.WallpaperService.Engine

该类的关键因素包括如下:

@Override
  public void onCreate(SurfaceHolder surfaceHolder) {
   super.onCreate(surfaceHolder);

   // By default we don't get touch events, so enable them.
   setTouchEventsEnabled(true);
  }



@Override
  public void onDestroy() {
   super.onDestroy();

   //do destory
  }

@Override
  public void onTouchEvent(MotionEvent event) {

}

@Override
  public void onVisibilityChanged(boolean visible) {

}



@Override
  public void onSurfaceChanged(SurfaceHolder holder, int format,
    int width, int height) {
   super.onSurfaceChanged(holder, format, width, height);

}

@Override
  public void onSurfaceCreated(SurfaceHolder holder) {
   super.onSurfaceCreated(holder);
  }

  @Override
  public void onSurfaceDestroyed(SurfaceHolder holder) {
   super.onSurfaceDestroyed(holder);

}



@Override
  public void onOffsetsChanged(float xOffset, float yOffset, float xStep,
    float yStep, int xPixels, int yPixels) {

}

二:由于Engine不是继承于Activity,在涉及到Context来绘制图形时,需要从外部传入Context

比如:

@Override
public Engine onCreateEngine() {

  return new MyEngine(this.getBaseContext());
}

this.getBaseContext()可以获取一个Context,可以根据该Context获取响应的信息



三:绘制图片时,通过Canvas.drawBitmap(bmp,left,top,Paint)

如果设置left,top为0,0,则绘制的图片将只在第4象限显示;

即屏幕默认的左上角坐标为(-240,-320)

Bitmap bmp = BitmapFactory.decodeResource(this.ctx.getResources(),
     R.drawable.love);
   Paint cPaint = new Paint();   c.clipRect(-240, -320, 240, 320);//显示从(-240, -320)到(240, 320)的区域(单位:象素)
   c.drawBitmap(bmp, -240, -320, cPaint);

相关推荐

Global site tag (gtag.js) - Google Analytics