1524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy/*
2524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy * Copyright (C) 2009 The Android Open Source Project
3524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy *
4524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy * Licensed under the Apache License, Version 2.0 (the "License");
5524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy * you may not use this file except in compliance with the License.
6524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy * You may obtain a copy of the License at
7524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy *
8524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy *      http://www.apache.org/licenses/LICENSE-2.0
9524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy *
10524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy * Unless required by applicable law or agreed to in writing, software
11524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy * distributed under the License is distributed on an "AS IS" BASIS,
12524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy * See the License for the specific language governing permissions and
14524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy * limitations under the License.
15524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy */
16524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
17524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guypackage com.android.wallpaper.walkaround;
18524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
19524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guyimport android.service.wallpaper.WallpaperService;
20524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guyimport android.view.SurfaceHolder;
21524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guyimport android.hardware.Camera;
22524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guyimport android.util.Log;
23524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guyimport android.util.DisplayMetrics;
24524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guyimport android.graphics.Canvas;
25524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guyimport android.content.res.Configuration;
26524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guyimport android.content.res.Resources;
27524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
28524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guyimport java.io.IOException;
29524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guyimport java.util.List;
30524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
31524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guypublic class WalkAroundWallpaper extends WallpaperService {
32524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy    private static final String LOG_TAG = "WalkAround";
33524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
34524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy    private Camera mCamera;
35524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy    private WalkAroundEngine mOwner;
36524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
37524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy    public Engine onCreateEngine() {
38524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy        return mOwner = new WalkAroundEngine();
39524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy    }
40524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
41524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy    @Override
42524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy    public void onDestroy() {
43524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy        super.onDestroy();
44524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy        stopCamera();
45524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy    }
46524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
47524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy    @Override
48524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy    public void onCreate() {
49524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy        super.onCreate();
50524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy    }
51524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
52376b3510c6d37e4a9ffc175f33e92726efa753ddRomain Guy    @Override
53376b3510c6d37e4a9ffc175f33e92726efa753ddRomain Guy    public void onConfigurationChanged(Configuration newConfig) {
54376b3510c6d37e4a9ffc175f33e92726efa753ddRomain Guy        super.onConfigurationChanged(newConfig);
55376b3510c6d37e4a9ffc175f33e92726efa753ddRomain Guy
56376b3510c6d37e4a9ffc175f33e92726efa753ddRomain Guy        if (mCamera != null) {
57376b3510c6d37e4a9ffc175f33e92726efa753ddRomain Guy            if (mCamera.previewEnabled()) {
58376b3510c6d37e4a9ffc175f33e92726efa753ddRomain Guy                boolean portrait = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT;
59376b3510c6d37e4a9ffc175f33e92726efa753ddRomain Guy                final Camera.Parameters params = mCamera.getParameters();
60376b3510c6d37e4a9ffc175f33e92726efa753ddRomain Guy                params.set("orientation", portrait ? "portrait" : "landscape");
61376b3510c6d37e4a9ffc175f33e92726efa753ddRomain Guy                mCamera.setParameters(params);
62376b3510c6d37e4a9ffc175f33e92726efa753ddRomain Guy
63376b3510c6d37e4a9ffc175f33e92726efa753ddRomain Guy                if (mCamera.previewEnabled()) mCamera.stopPreview();
64376b3510c6d37e4a9ffc175f33e92726efa753ddRomain Guy                mCamera.startPreview();
65376b3510c6d37e4a9ffc175f33e92726efa753ddRomain Guy            }
66376b3510c6d37e4a9ffc175f33e92726efa753ddRomain Guy        }
67376b3510c6d37e4a9ffc175f33e92726efa753ddRomain Guy    }
68376b3510c6d37e4a9ffc175f33e92726efa753ddRomain Guy
69524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy    private void startCamera() {
70524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy        if (mCamera == null) {
71524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            mCamera = Camera.open();
72524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy        } else {
73524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            try {
74524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                mCamera.reconnect();
75524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            } catch (IOException e) {
76524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                mCamera.release();
77524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                mCamera = null;
78524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
79524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                Log.e(LOG_TAG, "Error opening the camera", e);
80524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            }
81524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy        }
82524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy    }
83524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
84524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy    private void stopCamera() {
85524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy        if (mCamera != null) {
86524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            try {
87524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                mCamera.stopPreview();
88524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            } catch (Exception e) {
89524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                // Ignore
90524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            }
91524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
92524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            try {
93524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                mCamera.release();
94524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            } catch (Exception e) {
95524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                // Ignore
96524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            }
97524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
98524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            mCamera = null;
99524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy        }
100524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy    }
101524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
102524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy    class WalkAroundEngine extends Engine {
103524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy        private SurfaceHolder mHolder;
104524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
105524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy        WalkAroundEngine() {
106524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy        }
107524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
108524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy        @Override
109524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy        public void onCreate(SurfaceHolder surfaceHolder) {
110524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            super.onCreate(surfaceHolder);
111524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
112524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
113524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            mHolder = surfaceHolder;
114524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy        }
115524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
116524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy        @Override
117524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy        public void onVisibilityChanged(boolean visible) {
118524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            if (!visible) {
119524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                if (mOwner == this) {
120524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                    stopCamera();
121524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                }
122524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            } else {
123524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                try {
124524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                    startCamera();
125524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                    mCamera.setPreviewDisplay(mHolder);
126524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                    startPreview();
127524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                } catch (IOException e) {
128524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                    mCamera.release();
129524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                    mCamera = null;
130524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
131524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                    Log.e(LOG_TAG, "Error opening the camera", e);
132524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                }
133524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            }
134524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy        }
135524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
136524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy        @Override
137524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy        public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
138524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            super.onSurfaceChanged(holder, format, width, height);
139524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
140524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            if (holder.isCreating()) {
141524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                try {
142524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                    if (mCamera.previewEnabled()) mCamera.stopPreview();
143524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                    mCamera.setPreviewDisplay(holder);
144524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                } catch (IOException e) {
145524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                    mCamera.release();
146524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                    mCamera = null;
147524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
148524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                    Log.e(LOG_TAG, "Error opening the camera", e);
149524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                }
150524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            }
151524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
152524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            if (isVisible()) startPreview();
153524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy        }
154524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
155524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy        @Override
156524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy        public void onSurfaceCreated(SurfaceHolder holder) {
157524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            super.onSurfaceCreated(holder);
158524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            startCamera();
159524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy        }
160524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
161524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy        private void startPreview() {
162524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            final Resources resources = getResources();
163524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            final boolean portrait = resources.getConfiguration().orientation ==
164524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                    Configuration.ORIENTATION_PORTRAIT;
165524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
166524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            final Camera.Parameters params = mCamera.getParameters();
167524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
168524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            final DisplayMetrics metrics = resources.getDisplayMetrics();
169524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            final List<Camera.Size> sizes = params.getSupportedPreviewSizes();
170524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
171524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            // Try to find a preview size that matches the screen first
172524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            boolean found = false;
173524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            for (Camera.Size size : sizes) {
174524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                if ((portrait &&
175524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                        size.width == metrics.heightPixels && size.height == metrics.widthPixels) ||
176524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                    (!portrait &&
177524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                        size.width == metrics.widthPixels && size.height == metrics.heightPixels)) {
178524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                    params.setPreviewSize(size.width, size.height);
179524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                    found = true;
180524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                }
181524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            }
182524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
183524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            // If no suitable preview size was found, try to find something large enough
184524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            if (!found) {
185524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                for (Camera.Size size : sizes) {
186524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                    if (size.width >= metrics.widthPixels && size.height >= metrics.heightPixels) {
187524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                        params.setPreviewSize(size.width, size.height);
188524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                        found = true;
189524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                    }
190524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                }
191524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            }
192524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
193524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            // If no suitable preview size was found, pick the first one
194524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            if (!found) {
195524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                // Fill the canvas with black
196524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                Canvas canvas = null;
197524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                try {
198524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                    canvas = mHolder.lockCanvas();
199524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                    if (canvas != null) canvas.drawColor(0);
200524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                } finally {
201524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                    if (canvas != null) mHolder.unlockCanvasAndPost(canvas);
202524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                }
203524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
204524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
205524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                Camera.Size size = sizes.get(0);
206524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy                params.setPreviewSize(size.width, size.height);
207524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            }
208524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy
209524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            params.set("orientation", portrait ? "portrait" : "landscape");
210524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            mCamera.setParameters(params);
211376b3510c6d37e4a9ffc175f33e92726efa753ddRomain Guy
212524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy            mCamera.startPreview();
213524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy        }
214524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy    }
215524a658626fa667e6cee3b4b1a3ed9b605b9fdb5Romain Guy}
216