1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.service.wallpaper; 18 19 import com.android.internal.view.WindowManagerPolicyThread; 20 21 import android.app.WallpaperManager; 22 import android.graphics.Canvas; 23 import android.graphics.Rect; 24 import android.graphics.Region.Op; 25 import android.graphics.drawable.Drawable; 26 import android.os.HandlerThread; 27 import android.os.Looper; 28 import android.os.Process; 29 import android.service.wallpaper.WallpaperService; 30 import android.util.Log; 31 import android.view.MotionEvent; 32 import android.view.SurfaceHolder; 33 import android.content.Context; 34 import android.content.IntentFilter; 35 import android.content.Intent; 36 import android.content.BroadcastReceiver; 37 38 /** 39 * Default built-in wallpaper that simply shows a static image. 40 */ 41 public class ImageWallpaper extends WallpaperService { 42 WallpaperManager mWallpaperManager; 43 private HandlerThread mThread; 44 45 @Override 46 public void onCreate() { 47 super.onCreate(); 48 mWallpaperManager = (WallpaperManager) getSystemService(WALLPAPER_SERVICE); 49 Looper looper = WindowManagerPolicyThread.getLooper(); 50 if (looper != null) { 51 setCallbackLooper(looper); 52 } else { 53 mThread = new HandlerThread("Wallpaper", Process.THREAD_PRIORITY_FOREGROUND); 54 mThread.start(); 55 setCallbackLooper(mThread.getLooper()); 56 } 57 } 58 59 public Engine onCreateEngine() { 60 return new DrawableEngine(); 61 } 62 63 @Override 64 public void onDestroy() { 65 super.onDestroy(); 66 if (mThread != null) { 67 mThread.quit(); 68 } 69 } 70 71 class DrawableEngine extends Engine { 72 private final Object mLock = new Object(); 73 private WallpaperObserver mReceiver; 74 Drawable mBackground; 75 float mXOffset; 76 float mYOffset; 77 78 class WallpaperObserver extends BroadcastReceiver { 79 public void onReceive(Context context, Intent intent) { 80 updateWallpaper(); 81 drawFrame(); 82 // Assume we are the only one using the wallpaper in this 83 // process, and force a GC now to release the old wallpaper. 84 System.gc(); 85 } 86 } 87 88 @Override 89 public void onCreate(SurfaceHolder surfaceHolder) { 90 super.onCreate(surfaceHolder); 91 IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED); 92 mReceiver = new WallpaperObserver(); 93 registerReceiver(mReceiver, filter); 94 updateWallpaper(); 95 surfaceHolder.setSizeFromLayout(); 96 } 97 98 @Override 99 public void onDestroy() { 100 super.onDestroy(); 101 unregisterReceiver(mReceiver); 102 } 103 104 @Override 105 public void onVisibilityChanged(boolean visible) { 106 drawFrame(); 107 } 108 109 @Override 110 public void onTouchEvent(MotionEvent event) { 111 super.onTouchEvent(event); 112 } 113 114 @Override 115 public void onOffsetsChanged(float xOffset, float yOffset, 116 float xOffsetStep, float yOffsetStep, 117 int xPixels, int yPixels) { 118 mXOffset = xOffset; 119 mYOffset = yOffset; 120 drawFrame(); 121 } 122 123 @Override 124 public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) { 125 super.onSurfaceChanged(holder, format, width, height); 126 drawFrame(); 127 } 128 129 @Override 130 public void onSurfaceCreated(SurfaceHolder holder) { 131 super.onSurfaceCreated(holder); 132 } 133 134 @Override 135 public void onSurfaceDestroyed(SurfaceHolder holder) { 136 super.onSurfaceDestroyed(holder); 137 } 138 139 void drawFrame() { 140 SurfaceHolder sh = getSurfaceHolder(); 141 Canvas c = sh.lockCanvas(); 142 if (c != null) { 143 final Rect frame = sh.getSurfaceFrame(); 144 synchronized (mLock) { 145 final Drawable background = mBackground; 146 final int dw = frame.width(); 147 final int dh = frame.height(); 148 final int bw = background != null ? background.getIntrinsicWidth() : 0; 149 final int bh = background != null ? background.getIntrinsicHeight() : 0; 150 final int availw = dw-bw; 151 final int availh = dh-bh; 152 int xPixels = availw < 0 ? (int)(availw*mXOffset+.5f) : (availw/2); 153 int yPixels = availh < 0 ? (int)(availh*mYOffset+.5f) : (availh/2); 154 155 c.translate(xPixels, yPixels); 156 if (availw<0 || availh<0) { 157 c.save(Canvas.CLIP_SAVE_FLAG); 158 c.clipRect(0, 0, bw, bh, Op.DIFFERENCE); 159 c.drawColor(0xff000000); 160 c.restore(); 161 } 162 if (background != null) { 163 background.draw(c); 164 } 165 } 166 sh.unlockCanvasAndPost(c); 167 } 168 } 169 170 void updateWallpaper() { 171 synchronized (mLock) { 172 try { 173 mBackground = mWallpaperManager.getFastDrawable(); 174 } catch (RuntimeException e) { 175 Log.w("ImageWallpaper", "Unable to load wallpaper!", e); 176 } 177 } 178 } 179 } 180 } 181