• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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.browser;
18 
19 import android.app.ProgressDialog;
20 import android.app.WallpaperManager;
21 import android.content.Context;
22 import android.content.DialogInterface;
23 import android.graphics.Bitmap;
24 import android.graphics.BitmapFactory;
25 import android.graphics.Canvas;
26 import android.graphics.drawable.Drawable;
27 import android.util.Log;
28 import android.view.MenuItem;
29 import android.view.MenuItem.OnMenuItemClickListener;
30 import java.io.BufferedInputStream;
31 import java.io.ByteArrayInputStream;
32 import java.io.IOException;
33 import java.io.InputStream;
34 import java.net.MalformedURLException;
35 import java.net.URL;
36 
37 /**
38  * Handle setWallpaper requests
39  *
40  */
41 public class WallpaperHandler extends Thread
42         implements OnMenuItemClickListener, DialogInterface.OnCancelListener {
43 
44     private static final String LOGTAG = "WallpaperHandler";
45     // This should be large enough for BitmapFactory to decode the header so
46     // that we can mark and reset the input stream to avoid duplicate network i/o
47     private static final int BUFFER_SIZE = 128 * 1024;
48 
49     private Context mContext;
50     private String  mUrl;
51     private ProgressDialog mWallpaperProgress;
52     private boolean mCanceled = false;
53 
WallpaperHandler(Context context, String url)54     public WallpaperHandler(Context context, String url) {
55         mContext = context;
56         mUrl = url;
57     }
58 
59     @Override
onCancel(DialogInterface dialog)60     public void onCancel(DialogInterface dialog) {
61         mCanceled = true;
62     }
63 
64     @Override
onMenuItemClick(MenuItem item)65     public boolean onMenuItemClick(MenuItem item) {
66         if (mUrl != null && getState() == State.NEW) {
67             // The user may have tried to set a image with a large file size as
68             // their background so it may take a few moments to perform the
69             // operation.
70             // Display a progress spinner while it is working.
71             mWallpaperProgress = new ProgressDialog(mContext);
72             mWallpaperProgress.setIndeterminate(true);
73             mWallpaperProgress.setMessage(mContext.getResources()
74                     .getText(R.string.progress_dialog_setting_wallpaper));
75             mWallpaperProgress.setCancelable(true);
76             mWallpaperProgress.setOnCancelListener(this);
77             mWallpaperProgress.show();
78             start();
79         }
80         return true;
81     }
82 
83     @Override
run()84     public void run() {
85         WallpaperManager wm = WallpaperManager.getInstance(mContext);
86         Drawable oldWallpaper = wm.getDrawable();
87         InputStream inputstream = null;
88         try {
89             // TODO: This will cause the resource to be downloaded again, when
90             // we should in most cases be able to grab it from the cache. To fix
91             // this we should query WebCore to see if we can access a cached
92             // version and instead open an input stream on that. This pattern
93             // could also be used in the download manager where the same problem
94             // exists.
95             inputstream = openStream();
96             if (inputstream != null) {
97                 if (!inputstream.markSupported()) {
98                     inputstream = new BufferedInputStream(inputstream, BUFFER_SIZE);
99                 }
100                 inputstream.mark(BUFFER_SIZE);
101                 BitmapFactory.Options options = new BitmapFactory.Options();
102                 options.inJustDecodeBounds = true;
103                 // We give decodeStream a wrapped input stream so it doesn't
104                 // mess with our mark (currently it sets a mark of 1024)
105                 BitmapFactory.decodeStream(
106                         new BufferedInputStream(inputstream), null, options);
107                 int maxWidth = wm.getDesiredMinimumWidth();
108                 int maxHeight = wm.getDesiredMinimumHeight();
109                 // Give maxWidth and maxHeight some leeway
110                 maxWidth *= 1.25;
111                 maxHeight *= 1.25;
112                 int bmWidth = options.outWidth;
113                 int bmHeight = options.outHeight;
114 
115                 int scale = 1;
116                 while (bmWidth > maxWidth || bmHeight > maxHeight) {
117                     scale <<= 1;
118                     bmWidth >>= 1;
119                     bmHeight >>= 1;
120                 }
121                 options.inJustDecodeBounds = false;
122                 options.inSampleSize = scale;
123                 try {
124                     inputstream.reset();
125                 } catch (IOException e) {
126                     // BitmapFactory read more than we could buffer
127                     // Re-open the stream
128                     inputstream.close();
129                     inputstream = openStream();
130                 }
131                 Bitmap scaledWallpaper = BitmapFactory.decodeStream(inputstream,
132                         null, options);
133                 if (scaledWallpaper != null) {
134                     wm.setBitmap(scaledWallpaper);
135                 } else {
136                     Log.e(LOGTAG, "Unable to set new wallpaper, " +
137                             "decodeStream returned null.");
138                 }
139             }
140         } catch (IOException e) {
141             Log.e(LOGTAG, "Unable to set new wallpaper");
142             // Act as though the user canceled the operation so we try to
143             // restore the old wallpaper.
144             mCanceled = true;
145         } finally {
146             if (inputstream != null) {
147                 try {
148                     inputstream.close();
149                 } catch (IOException e) {
150                     // Ignore
151                 }
152             }
153         }
154 
155         if (mCanceled) {
156             // Restore the old wallpaper if the user cancelled whilst we were
157             // setting
158             // the new wallpaper.
159             int width = oldWallpaper.getIntrinsicWidth();
160             int height = oldWallpaper.getIntrinsicHeight();
161             Bitmap bm = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
162             Canvas canvas = new Canvas(bm);
163             oldWallpaper.setBounds(0, 0, width, height);
164             oldWallpaper.draw(canvas);
165             canvas.setBitmap(null);
166             try {
167                 wm.setBitmap(bm);
168             } catch (IOException e) {
169                 Log.e(LOGTAG, "Unable to restore old wallpaper.");
170             }
171             mCanceled = false;
172         }
173 
174         if (mWallpaperProgress.isShowing()) {
175             mWallpaperProgress.dismiss();
176         }
177     }
178 
179     /**
180      * Opens the input stream for the URL that the class should
181      * use to set the wallpaper. Abstracts the difference between
182      * standard URLs and data URLs.
183      * @return An open InputStream for the data at the URL
184      * @throws IOException if there is an error opening the URL stream
185      * @throws MalformedURLException if the URL is malformed
186      */
openStream()187     private InputStream openStream() throws IOException, MalformedURLException {
188         InputStream inputStream = null;
189         if (DataUri.isDataUri(mUrl)) {
190             DataUri dataUri = new DataUri(mUrl);
191             inputStream = new ByteArrayInputStream(dataUri.getData());
192         } else {
193             URL url = new URL(mUrl);
194             inputStream = url.openStream();
195         }
196         return inputStream;
197     }
198 }
199