WallPePer_Canvas.java

package pe.berabue.livewallpaper;

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

public class WallPaPer_Canvas extends WallpaperService {
    	
	private final Handler mHandler = new Handler();
	
	@Override
	public void onCreate() {
		super.onCreate();
	}
	
	@Override
	public void onDestroy() {
		super.onDestroy();
	}

	@Override
	public Engine onCreateEngine() {
		return new CanvasEngine();
	}

	private class CanvasEngine extends Engine {  

		private Bitmap imgIcon;
		
		private final Runnable mRunnable = new Runnable() {
			public void run() {
				drawFrame();
			}
		};
		private boolean isVisible;
	        
		public CanvasEngine() {
			imgIcon = BitmapFactory.decodeResource(getApplicationContext().getResources(), R.drawable.icon);
		}
		
		@Override
		public void onCreate(SurfaceHolder surfaceHolder) {
			super.onCreate(surfaceHolder);
			setTouchEventsEnabled(true);
		}

		@Override
		public void onDestroy() {
			super.onDestroy();
			mHandler.removeCallbacks(mRunnable);
		}

		@Override
		public void onVisibilityChanged(boolean visible) {
			isVisible = visible;

			if (visible) {
				drawFrame();
			} else {
				mHandler.removeCallbacks(mRunnable);
			}
		}

		@Override
		public void onSurfaceCreated(SurfaceHolder holder) {
			super.onSurfaceCreated(holder);
		}
		
		@Override
		public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
			super.onSurfaceChanged(holder, format, width, height);
			Log.v(null," :::: onSurfaceChanged : "+format+" / "+width+", "+height);
			drawFrame();
		}

		@Override
		public void onSurfaceDestroyed(SurfaceHolder holder) {
			super.onSurfaceDestroyed(holder);
			isVisible = false;
			mHandler.removeCallbacks(mRunnable);
		}

		@Override
		public void onOffsetsChanged(float xOffset, float yOffset, float xStep, float yStep, int xPixels, int yPixels) {
			Log.v(null," :::: onOffsetsChanged : "+xOffset+", "+yOffset+", "+xStep+", "+yStep+", "+xPixels+", "+yPixels);
			drawFrame();
		}

		@Override
		public void onTouchEvent(MotionEvent event) {
			if (event.getAction() == MotionEvent.ACTION_DOWN) {
				Log.v(null," :::: onTouchEvent");
			}
			super.onTouchEvent(event);
		}

		public void drawFrame() {
			final SurfaceHolder holder = getSurfaceHolder();

			Canvas canvas = null;
			try {
				canvas = holder.lockCanvas();
				if (canvas != null) {
					canvas.drawBitmap(imgIcon, 0, 0, null);
				}
			} finally {
				if (canvas != null)
					holder.unlockCanvasAndPost(canvas);
			}

			mHandler.removeCallbacks(mRunnable);
			if (isVisible) {
				mHandler.postDelayed(mRunnable, 1000 / 25);
			}
		}
	}
}

mHandler를 등록하고 이미지를 준비시킨다.

onVisibilityChanged();  화면이 보여지고 있는지 가려졌는지를 알아내 isVisible에 넣는다.  화면이 보여지고 있다면 drawFrame();으로 들어간다. drawFrame();  실직적으로 이미지가 그려지는 곳.  이미지 처리를 완료하고 핸들러를 제거한다. 화면이 계속 보여지는 중이라면 원하는 딜레이로 핸들러를 다시 등록하여준다.
 

화면이 가려지거나(다른어플 실행, 화면꺼짐 등) 해당 Live Wallpaper를 종료시킬때 핸들러를 제거하여준다.
아래 화면과 같이 타이틀바 영역을 포함하여 좌표가 시작된다.


 



  1. Stiven 2011.07.14 17:10

    안녕하세요.

    님 홈페이지를 통해 월페이퍼를 만들어보고있는데요.

    이미지띄우는것까지는 원활하게 구동되었습니다.

    그다음 추가할부분이 그림이미징 보시면 설정부분을 셋팅해야되는데요.

    그것을 셋팅하는 구조에 대해 알려주시면 감사하겠습니다.^^

    • berabue 2011.07.15 10:55 신고

      설정 부분을 추가 등록하였습니다 ^^
      설정부분을 공부를 안하고 넘어갔었네요.. 덕분에 좋은 공부했습니다^^
      http://berabue.tistory.com/56

  2. 2011.11.09 14:04

    비밀댓글입니다

    • berabue 2011.11.09 18:15 신고

      강제종료 현상이 발생할 경우에는 로그캣을 참조해보세요 ~ ^^ 어디 nullpointer나 xml에러일 경우가 많습니다!

  3. 2011.11.10 01:48

    비밀댓글입니다

    • berabue 2011.11.11 00:46 신고

      Manifest에서 액티비티명이나 패키지명 또는 버전등을 확인해보세요~! 정확히 어떤 에러인지 말씀해주시면 대충이라도 짐작할 수 있을것같습니다!

  4. 2011.11.11 01:13

    비밀댓글입니다

    • berabue 2011.11.12 18:02 신고

      배경화면을 가득 채우기 위해서는 해당 사이즈만큼의 이미지를 사용하거나, 더 작은 사이즈의 경우 비트맵을 늘려서 출력해 주시면 됩니다.
      이미지를 터치하는곳으로 보내는 것은 위 소스 109번 라인 0,0에 터치 좌표를 보내주면됩니다.

  5. ㅠㅠ 2011.11.13 02:10

    감사합니다 많은 도음 되었습니다ㅠㅠ
    정말 고수이신듯 ㅠㅠ



AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="pe.berabue.livewallpaper"
      android:versionCode="1"
      android:versionName="1.0">

    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".LiveWallPaPer_Canvas"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

  <service android:name=".WallPaPer_Canvas"  
        android:label="@string/app_name"  
        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/ex"/>  
</service>  
    </application>
    
    <uses-sdk android:minSdkVersion="7" />
    <uses-feature android:name="android.software.live_wallpaper" />
</manifest>

xml파일을 syntaxhighlighter로 변환하면 이상하게 /> 문자열이 자동으로 바뀌어버리는......
아무튼, Activity는 필수가 아니다. 기본적으로 service부분과 uses-feature 부분만 넣어주면된다.



ex.xml

<?xml version="1.0" encoding="UTF-8"?>
<wallpaper 
    xmlns:android="http://schemas.android.com/apk/res/android"  
    android:thumbnail="@drawable/icon" 
    android:description="@string/test"
    android:settingsActivity="PreferenceActivity"/>

Live Wallpaper를 적용시킬때 나오는 아이콘과 설명 그리고 설정화면을 등록해준다.
android:settingsActivity부분을 넣지않으면 설정 버튼이 나오지 않는다.



WallPePer_Canvas.java

package pe.berabue.livewallpaper;

import android.service.wallpaper.WallpaperService;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;

public class WallPaPer_Canvas extends WallpaperService {
    	
	@Override
	public void onCreate() {
		super.onCreate();
	}
	
	@Override
	public void onDestroy() {
		super.onDestroy();
	}

	@Override
	public Engine onCreateEngine() {
		return new CanvasEngine();
	}

	private class CanvasEngine extends Engine {  
        
		public CanvasEngine() {

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

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

		@Override
		public void onVisibilityChanged(boolean visible) {

		}

		@Override
		public void onSurfaceCreated(SurfaceHolder holder) {
			super.onSurfaceCreated(holder);
		}
		
		@Override
		public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
			super.onSurfaceChanged(holder, format, width, height);
			Log.v(null," :::: onSurfaceChanged : "+format+" / "+width+", "+height);
		}

		@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) {
			Log.v(null," :::: onOffsetsChanged : "+xOffset+", "+yOffset+", "+xStep+", "+yStep+", "+xPixels+", "+yPixels);
		}

		@Override
		public void onTouchEvent(MotionEvent event) {
			if (event.getAction() == MotionEvent.ACTION_DOWN) {
				Log.v(null," :::: onTouchEvent");
			}
			super.onTouchEvent(event);
		}
	}
}

Activity대신 WallpaperService를 상속받는데 그러면 onCreateEngine() 메서드를 구현해 주어야 한다. Engine을 상속받은 CanvasEngine클래스가 중요한 부분. 클래스 이름에 Canvas를 붙인 이유는.. 목표가 OpenGL용 live wallpaper이기 때문에...(?)

onVisibilityChanged();  메서드는 화면이 보여질때와 가려질때를 알아낸다. onOffsetsChanged();  화면을 밀어 옆으로 이동할때 실행된다. 



+ Recent posts