14c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn/*
24c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn * Copyright (C) 2009 The Android Open Source Project
34c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn *
44c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License");
54c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn * you may not use this file except in compliance with the License.
64c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn * You may obtain a copy of the License at
74c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn *
84c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn *      http://www.apache.org/licenses/LICENSE-2.0
94c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn *
104c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn * Unless required by applicable law or agreed to in writing, software
114c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS,
124c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn * See the License for the specific language governing permissions and
144c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn * limitations under the License.
154c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn */
164c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn
174c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackbornpackage com.android.internal.service.wallpaper;
184c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn
19ac3587d7ced544091264a35249dbd3f9531a3cabDianne Hackbornimport com.android.internal.view.WindowManagerPolicyThread;
20ac3587d7ced544091264a35249dbd3f9531a3cabDianne Hackborn
214c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackbornimport android.app.WallpaperManager;
224c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackbornimport android.graphics.Canvas;
23759a39e8d2a8b27ef07e102394629dce68aa186bDianne Hackbornimport android.graphics.Rect;
24e2d034c9014919a45ddd717d4e564e73771b2fefMathias Agopianimport android.graphics.Region.Op;
254c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackbornimport android.graphics.drawable.Drawable;
2619382ac1a4e4e7c23a1346d299368763f149de9cDianne Hackbornimport android.os.HandlerThread;
27ac3587d7ced544091264a35249dbd3f9531a3cabDianne Hackbornimport android.os.Looper;
2819382ac1a4e4e7c23a1346d299368763f149de9cDianne Hackbornimport android.os.Process;
294c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackbornimport android.service.wallpaper.WallpaperService;
30c9dbbe28f7879bd377114587ed1f40235a2d37caDianne Hackbornimport android.util.Log;
318df8b2b405c60cacf7a66c4e2ca078dd3d7ec7bdDianne Hackbornimport android.view.MotionEvent;
324c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackbornimport android.view.SurfaceHolder;
33ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guyimport android.content.Context;
34ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guyimport android.content.IntentFilter;
35ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guyimport android.content.Intent;
36ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guyimport android.content.BroadcastReceiver;
374c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn
384c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn/**
394c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn * Default built-in wallpaper that simply shows a static image.
404c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn */
414c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackbornpublic class ImageWallpaper extends WallpaperService {
42ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy    WallpaperManager mWallpaperManager;
4319382ac1a4e4e7c23a1346d299368763f149de9cDianne Hackborn    private HandlerThread mThread;
44ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy
45ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy    @Override
46ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy    public void onCreate() {
47ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy        super.onCreate();
48ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy        mWallpaperManager = (WallpaperManager) getSystemService(WALLPAPER_SERVICE);
49ac3587d7ced544091264a35249dbd3f9531a3cabDianne Hackborn        Looper looper = WindowManagerPolicyThread.getLooper();
50ac3587d7ced544091264a35249dbd3f9531a3cabDianne Hackborn        if (looper != null) {
51ac3587d7ced544091264a35249dbd3f9531a3cabDianne Hackborn            setCallbackLooper(looper);
52ac3587d7ced544091264a35249dbd3f9531a3cabDianne Hackborn        } else {
53ac3587d7ced544091264a35249dbd3f9531a3cabDianne Hackborn            mThread = new HandlerThread("Wallpaper", Process.THREAD_PRIORITY_FOREGROUND);
54ac3587d7ced544091264a35249dbd3f9531a3cabDianne Hackborn            mThread.start();
55ac3587d7ced544091264a35249dbd3f9531a3cabDianne Hackborn            setCallbackLooper(mThread.getLooper());
56ac3587d7ced544091264a35249dbd3f9531a3cabDianne Hackborn        }
57ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy    }
58ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy
59ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy    public Engine onCreateEngine() {
60284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn        return new DrawableEngine();
61ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy    }
62ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy
6319382ac1a4e4e7c23a1346d299368763f149de9cDianne Hackborn    @Override
6419382ac1a4e4e7c23a1346d299368763f149de9cDianne Hackborn    public void onDestroy() {
6519382ac1a4e4e7c23a1346d299368763f149de9cDianne Hackborn        super.onDestroy();
66ac3587d7ced544091264a35249dbd3f9531a3cabDianne Hackborn        if (mThread != null) {
67ac3587d7ced544091264a35249dbd3f9531a3cabDianne Hackborn            mThread.quit();
68ac3587d7ced544091264a35249dbd3f9531a3cabDianne Hackborn        }
6919382ac1a4e4e7c23a1346d299368763f149de9cDianne Hackborn    }
7019382ac1a4e4e7c23a1346d299368763f149de9cDianne Hackborn
71ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy    class DrawableEngine extends Engine {
72ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy        private final Object mLock = new Object();
73284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn        private WallpaperObserver mReceiver;
744c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn        Drawable mBackground;
757341d7a104b47996445d069a695e155a07184606Dianne Hackborn        float mXOffset;
767341d7a104b47996445d069a695e155a07184606Dianne Hackborn        float mYOffset;
77759a39e8d2a8b27ef07e102394629dce68aa186bDianne Hackborn
78284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn        class WallpaperObserver extends BroadcastReceiver {
79284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn            public void onReceive(Context context, Intent intent) {
80284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn                updateWallpaper();
81284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn                drawFrame();
8219382ac1a4e4e7c23a1346d299368763f149de9cDianne Hackborn                // Assume we are the only one using the wallpaper in this
8319382ac1a4e4e7c23a1346d299368763f149de9cDianne Hackborn                // process, and force a GC now to release the old wallpaper.
8419382ac1a4e4e7c23a1346d299368763f149de9cDianne Hackborn                System.gc();
85284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn            }
86284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn        }
87284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn
884c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn        @Override
89759a39e8d2a8b27ef07e102394629dce68aa186bDianne Hackborn        public void onCreate(SurfaceHolder surfaceHolder) {
90759a39e8d2a8b27ef07e102394629dce68aa186bDianne Hackborn            super.onCreate(surfaceHolder);
91284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn            IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
92284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn            mReceiver = new WallpaperObserver();
93284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn            registerReceiver(mReceiver, filter);
940cd48879dca53a9f4d449126d406527bc4b94bafDianne Hackborn            updateWallpaper();
9572c82ab9923025a91bbabb32e56bfea27bfd083bDianne Hackborn            surfaceHolder.setSizeFromLayout();
964c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn        }
974c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn
984c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn        @Override
99284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn        public void onDestroy() {
100284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn            super.onDestroy();
101284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn            unregisterReceiver(mReceiver);
102284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn        }
103284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn
104284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn        @Override
105759a39e8d2a8b27ef07e102394629dce68aa186bDianne Hackborn        public void onVisibilityChanged(boolean visible) {
106ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy            drawFrame();
107759a39e8d2a8b27ef07e102394629dce68aa186bDianne Hackborn        }
108759a39e8d2a8b27ef07e102394629dce68aa186bDianne Hackborn
109759a39e8d2a8b27ef07e102394629dce68aa186bDianne Hackborn        @Override
1108df8b2b405c60cacf7a66c4e2ca078dd3d7ec7bdDianne Hackborn        public void onTouchEvent(MotionEvent event) {
1118df8b2b405c60cacf7a66c4e2ca078dd3d7ec7bdDianne Hackborn            super.onTouchEvent(event);
1128df8b2b405c60cacf7a66c4e2ca078dd3d7ec7bdDianne Hackborn        }
1138df8b2b405c60cacf7a66c4e2ca078dd3d7ec7bdDianne Hackborn
1148df8b2b405c60cacf7a66c4e2ca078dd3d7ec7bdDianne Hackborn        @Override
11572c82ab9923025a91bbabb32e56bfea27bfd083bDianne Hackborn        public void onOffsetsChanged(float xOffset, float yOffset,
116bf6956b1d95442e9d9c483894d578fe6b7044cbbMarco Nelissen                float xOffsetStep, float yOffsetStep,
11772c82ab9923025a91bbabb32e56bfea27bfd083bDianne Hackborn                int xPixels, int yPixels) {
1187341d7a104b47996445d069a695e155a07184606Dianne Hackborn            mXOffset = xOffset;
11907ef599b9f35572a3a75b884febe500a6c390e7eRomain Guy            mYOffset = yOffset;
12072c82ab9923025a91bbabb32e56bfea27bfd083bDianne Hackborn            drawFrame();
12172c82ab9923025a91bbabb32e56bfea27bfd083bDianne Hackborn        }
12272c82ab9923025a91bbabb32e56bfea27bfd083bDianne Hackborn
12372c82ab9923025a91bbabb32e56bfea27bfd083bDianne Hackborn        @Override
1244c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn        public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
1254c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn            super.onSurfaceChanged(holder, format, width, height);
126ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy            drawFrame();
1274c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn        }
1284c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn
1294c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn        @Override
1304c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn        public void onSurfaceCreated(SurfaceHolder holder) {
1314c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn            super.onSurfaceCreated(holder);
1324c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn        }
1334c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn
1344c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn        @Override
1354c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn        public void onSurfaceDestroyed(SurfaceHolder holder) {
1364c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn            super.onSurfaceDestroyed(holder);
1374c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn        }
1384c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn
139ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy        void drawFrame() {
140759a39e8d2a8b27ef07e102394629dce68aa186bDianne Hackborn            SurfaceHolder sh = getSurfaceHolder();
14172c82ab9923025a91bbabb32e56bfea27bfd083bDianne Hackborn            Canvas c = sh.lockCanvas();
14272c82ab9923025a91bbabb32e56bfea27bfd083bDianne Hackborn            if (c != null) {
1437341d7a104b47996445d069a695e155a07184606Dianne Hackborn                final Rect frame = sh.getSurfaceFrame();
14472c82ab9923025a91bbabb32e56bfea27bfd083bDianne Hackborn                synchronized (mLock) {
14572c82ab9923025a91bbabb32e56bfea27bfd083bDianne Hackborn                    final Drawable background = mBackground;
1467341d7a104b47996445d069a695e155a07184606Dianne Hackborn                    final int dw = frame.width();
1477341d7a104b47996445d069a695e155a07184606Dianne Hackborn                    final int dh = frame.height();
148c9dbbe28f7879bd377114587ed1f40235a2d37caDianne Hackborn                    final int bw = background != null ? background.getIntrinsicWidth() : 0;
149c9dbbe28f7879bd377114587ed1f40235a2d37caDianne Hackborn                    final int bh = background != null ? background.getIntrinsicHeight() : 0;
150e2d034c9014919a45ddd717d4e564e73771b2fefMathias Agopian                    final int availw = dw-bw;
151e2d034c9014919a45ddd717d4e564e73771b2fefMathias Agopian                    final int availh = dh-bh;
152e2d034c9014919a45ddd717d4e564e73771b2fefMathias Agopian                    int xPixels = availw < 0 ? (int)(availw*mXOffset+.5f) : (availw/2);
153e2d034c9014919a45ddd717d4e564e73771b2fefMathias Agopian                    int yPixels = availh < 0 ? (int)(availh*mYOffset+.5f) : (availh/2);
154e2d034c9014919a45ddd717d4e564e73771b2fefMathias Agopian
1557341d7a104b47996445d069a695e155a07184606Dianne Hackborn                    c.translate(xPixels, yPixels);
156e2d034c9014919a45ddd717d4e564e73771b2fefMathias Agopian                    if (availw<0 || availh<0) {
157e2d034c9014919a45ddd717d4e564e73771b2fefMathias Agopian                        c.save(Canvas.CLIP_SAVE_FLAG);
158e2d034c9014919a45ddd717d4e564e73771b2fefMathias Agopian                        c.clipRect(0, 0, bw, bh, Op.DIFFERENCE);
159e2d034c9014919a45ddd717d4e564e73771b2fefMathias Agopian                        c.drawColor(0xff000000);
160e2d034c9014919a45ddd717d4e564e73771b2fefMathias Agopian                        c.restore();
161e2d034c9014919a45ddd717d4e564e73771b2fefMathias Agopian                    }
162c9dbbe28f7879bd377114587ed1f40235a2d37caDianne Hackborn                    if (background != null) {
163c9dbbe28f7879bd377114587ed1f40235a2d37caDianne Hackborn                        background.draw(c);
164c9dbbe28f7879bd377114587ed1f40235a2d37caDianne Hackborn                    }
165759a39e8d2a8b27ef07e102394629dce68aa186bDianne Hackborn                }
16672c82ab9923025a91bbabb32e56bfea27bfd083bDianne Hackborn                sh.unlockCanvasAndPost(c);
167759a39e8d2a8b27ef07e102394629dce68aa186bDianne Hackborn            }
168759a39e8d2a8b27ef07e102394629dce68aa186bDianne Hackborn        }
169ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy
170ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy        void updateWallpaper() {
171ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy            synchronized (mLock) {
172c9dbbe28f7879bd377114587ed1f40235a2d37caDianne Hackborn                try {
173c9dbbe28f7879bd377114587ed1f40235a2d37caDianne Hackborn                    mBackground = mWallpaperManager.getFastDrawable();
174c9dbbe28f7879bd377114587ed1f40235a2d37caDianne Hackborn                } catch (RuntimeException e) {
175c9dbbe28f7879bd377114587ed1f40235a2d37caDianne Hackborn                    Log.w("ImageWallpaper", "Unable to load wallpaper!", e);
176c9dbbe28f7879bd377114587ed1f40235a2d37caDianne Hackborn                }
177ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy            }
178ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy        }
1794c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn    }
1804c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn}
181