13527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck/* 23527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck * Copyright (C) 2010 The Android Open Source Project 33527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck * 43527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck * Licensed under the Apache License, Version 2.0 (the "License"); 53527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck * you may not use this file except in compliance with the License. 63527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck * You may obtain a copy of the License at 73527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck * 83527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck * http://www.apache.org/licenses/LICENSE-2.0 93527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck * 103527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck * Unless required by applicable law or agreed to in writing, software 113527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck * distributed under the License is distributed on an "AS IS" BASIS, 123527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck * See the License for the specific language governing permissions and 143527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck * limitations under the License. 153527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck */ 163527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck 173527dd1ff849ec4798eab6289593aa404dcae40bJohn Reckpackage com.android.browser; 183527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck 193527dd1ff849ec4798eab6289593aa404dcae40bJohn Reckimport android.app.ProgressDialog; 203527dd1ff849ec4798eab6289593aa404dcae40bJohn Reckimport android.app.WallpaperManager; 213527dd1ff849ec4798eab6289593aa404dcae40bJohn Reckimport android.content.Context; 223527dd1ff849ec4798eab6289593aa404dcae40bJohn Reckimport android.content.DialogInterface; 233527dd1ff849ec4798eab6289593aa404dcae40bJohn Reckimport android.graphics.Bitmap; 24b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdochimport android.graphics.BitmapFactory; 253527dd1ff849ec4798eab6289593aa404dcae40bJohn Reckimport android.graphics.Canvas; 263527dd1ff849ec4798eab6289593aa404dcae40bJohn Reckimport android.graphics.drawable.Drawable; 273527dd1ff849ec4798eab6289593aa404dcae40bJohn Reckimport android.util.Log; 283527dd1ff849ec4798eab6289593aa404dcae40bJohn Reckimport android.view.MenuItem; 293527dd1ff849ec4798eab6289593aa404dcae40bJohn Reckimport android.view.MenuItem.OnMenuItemClickListener; 30b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdochimport java.io.BufferedInputStream; 31387d45d2284c7fd7f12cbadc96161f946ae29cadGeorge Mountimport java.io.ByteArrayInputStream; 323527dd1ff849ec4798eab6289593aa404dcae40bJohn Reckimport java.io.IOException; 333527dd1ff849ec4798eab6289593aa404dcae40bJohn Reckimport java.io.InputStream; 343527dd1ff849ec4798eab6289593aa404dcae40bJohn Reckimport java.net.MalformedURLException; 353527dd1ff849ec4798eab6289593aa404dcae40bJohn Reckimport java.net.URL; 363527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck 373527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck/** 383527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck * Handle setWallpaper requests 393527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck * 403527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck */ 413527dd1ff849ec4798eab6289593aa404dcae40bJohn Reckpublic class WallpaperHandler extends Thread 423527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck implements OnMenuItemClickListener, DialogInterface.OnCancelListener { 433527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck 443527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck private static final String LOGTAG = "WallpaperHandler"; 45b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch // This should be large enough for BitmapFactory to decode the header so 46b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch // that we can mark and reset the input stream to avoid duplicate network i/o 47b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch private static final int BUFFER_SIZE = 128 * 1024; 483527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck 493527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck private Context mContext; 50387d45d2284c7fd7f12cbadc96161f946ae29cadGeorge Mount private String mUrl; 513527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck private ProgressDialog mWallpaperProgress; 523527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck private boolean mCanceled = false; 533527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck 543527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck public WallpaperHandler(Context context, String url) { 553527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck mContext = context; 56387d45d2284c7fd7f12cbadc96161f946ae29cadGeorge Mount mUrl = url; 573527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck } 583527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck 593527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck @Override 603527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck public void onCancel(DialogInterface dialog) { 613527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck mCanceled = true; 623527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck } 633527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck 643527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck @Override 653527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck public boolean onMenuItemClick(MenuItem item) { 668549365bc3e7fe5af07f687286404dbcc3553815John Reck if (mUrl != null && getState() == State.NEW) { 673527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck // The user may have tried to set a image with a large file size as 683527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck // their background so it may take a few moments to perform the 693527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck // operation. 703527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck // Display a progress spinner while it is working. 713527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck mWallpaperProgress = new ProgressDialog(mContext); 723527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck mWallpaperProgress.setIndeterminate(true); 733527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck mWallpaperProgress.setMessage(mContext.getResources() 743527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck .getText(R.string.progress_dialog_setting_wallpaper)); 753527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck mWallpaperProgress.setCancelable(true); 763527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck mWallpaperProgress.setOnCancelListener(this); 773527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck mWallpaperProgress.show(); 783527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck start(); 793527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck } 803527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck return true; 813527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck } 823527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck 833527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck @Override 843527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck public void run() { 85b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch WallpaperManager wm = WallpaperManager.getInstance(mContext); 86b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch Drawable oldWallpaper = wm.getDrawable(); 87b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch InputStream inputstream = null; 883527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck try { 893527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck // TODO: This will cause the resource to be downloaded again, when 903527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck // we should in most cases be able to grab it from the cache. To fix 913527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck // this we should query WebCore to see if we can access a cached 923527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck // version and instead open an input stream on that. This pattern 933527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck // could also be used in the download manager where the same problem 943527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck // exists. 95387d45d2284c7fd7f12cbadc96161f946ae29cadGeorge Mount inputstream = openStream(); 963527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck if (inputstream != null) { 97b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch if (!inputstream.markSupported()) { 98b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch inputstream = new BufferedInputStream(inputstream, BUFFER_SIZE); 99b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch } 100b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch inputstream.mark(BUFFER_SIZE); 101b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch BitmapFactory.Options options = new BitmapFactory.Options(); 102b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch options.inJustDecodeBounds = true; 103b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch // We give decodeStream a wrapped input stream so it doesn't 104b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch // mess with our mark (currently it sets a mark of 1024) 105b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch BitmapFactory.decodeStream( 106b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch new BufferedInputStream(inputstream), null, options); 107b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch int maxWidth = wm.getDesiredMinimumWidth(); 108b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch int maxHeight = wm.getDesiredMinimumHeight(); 109b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch // Give maxWidth and maxHeight some leeway 110b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch maxWidth *= 1.25; 111b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch maxHeight *= 1.25; 112b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch int bmWidth = options.outWidth; 113b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch int bmHeight = options.outHeight; 114b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch 115b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch int scale = 1; 116387d45d2284c7fd7f12cbadc96161f946ae29cadGeorge Mount while (bmWidth > maxWidth || bmHeight > maxHeight) { 117b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch scale <<= 1; 118b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch bmWidth >>= 1; 119b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch bmHeight >>= 1; 120b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch } 121b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch options.inJustDecodeBounds = false; 122b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch options.inSampleSize = scale; 123b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch try { 124b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch inputstream.reset(); 125b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch } catch (IOException e) { 126b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch // BitmapFactory read more than we could buffer 127b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch // Re-open the stream 128b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch inputstream.close(); 129387d45d2284c7fd7f12cbadc96161f946ae29cadGeorge Mount inputstream = openStream(); 130b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch } 131b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch Bitmap scaledWallpaper = BitmapFactory.decodeStream(inputstream, 132b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch null, options); 1334db7e933f4c26e28f82dc912863f7d02d8fb94abNils Holmström if (scaledWallpaper != null) { 1344db7e933f4c26e28f82dc912863f7d02d8fb94abNils Holmström wm.setBitmap(scaledWallpaper); 1354db7e933f4c26e28f82dc912863f7d02d8fb94abNils Holmström } else { 1364db7e933f4c26e28f82dc912863f7d02d8fb94abNils Holmström Log.e(LOGTAG, "Unable to set new wallpaper, " + 1374db7e933f4c26e28f82dc912863f7d02d8fb94abNils Holmström "decodeStream returned null."); 1384db7e933f4c26e28f82dc912863f7d02d8fb94abNils Holmström } 1393527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck } 1403527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck } catch (IOException e) { 1413527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck Log.e(LOGTAG, "Unable to set new wallpaper"); 1423527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck // Act as though the user canceled the operation so we try to 1433527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck // restore the old wallpaper. 1443527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck mCanceled = true; 145b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch } finally { 146b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch if (inputstream != null) { 147b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch try { 148b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch inputstream.close(); 149b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch } catch (IOException e) { 150b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch // Ignore 151b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch } 152b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch } 1533527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck } 1543527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck 1553527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck if (mCanceled) { 1563527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck // Restore the old wallpaper if the user cancelled whilst we were 1573527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck // setting 1583527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck // the new wallpaper. 1593527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck int width = oldWallpaper.getIntrinsicWidth(); 1603527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck int height = oldWallpaper.getIntrinsicHeight(); 1613527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck Bitmap bm = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); 1623527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck Canvas canvas = new Canvas(bm); 1633527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck oldWallpaper.setBounds(0, 0, width, height); 1643527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck oldWallpaper.draw(canvas); 16543cfe8a4521b5c153055fbfa181940bc56bb3b06Dianne Hackborn canvas.setBitmap(null); 1663527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck try { 167b860a62a7fc645fa3b4f5b2733766f60570d65f9Ben Murdoch wm.setBitmap(bm); 1683527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck } catch (IOException e) { 1693527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck Log.e(LOGTAG, "Unable to restore old wallpaper."); 1703527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck } 1713527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck mCanceled = false; 1723527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck } 1733527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck 1743527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck if (mWallpaperProgress.isShowing()) { 1753527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck mWallpaperProgress.dismiss(); 1763527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck } 1773527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck } 178387d45d2284c7fd7f12cbadc96161f946ae29cadGeorge Mount 179387d45d2284c7fd7f12cbadc96161f946ae29cadGeorge Mount /** 180387d45d2284c7fd7f12cbadc96161f946ae29cadGeorge Mount * Opens the input stream for the URL that the class should 181387d45d2284c7fd7f12cbadc96161f946ae29cadGeorge Mount * use to set the wallpaper. Abstracts the difference between 182387d45d2284c7fd7f12cbadc96161f946ae29cadGeorge Mount * standard URLs and data URLs. 183387d45d2284c7fd7f12cbadc96161f946ae29cadGeorge Mount * @return An open InputStream for the data at the URL 184387d45d2284c7fd7f12cbadc96161f946ae29cadGeorge Mount * @throws IOException if there is an error opening the URL stream 185387d45d2284c7fd7f12cbadc96161f946ae29cadGeorge Mount * @throws MalformedURLException if the URL is malformed 186387d45d2284c7fd7f12cbadc96161f946ae29cadGeorge Mount */ 187387d45d2284c7fd7f12cbadc96161f946ae29cadGeorge Mount private InputStream openStream() throws IOException, MalformedURLException { 188387d45d2284c7fd7f12cbadc96161f946ae29cadGeorge Mount InputStream inputStream = null; 189387d45d2284c7fd7f12cbadc96161f946ae29cadGeorge Mount if (DataUri.isDataUri(mUrl)) { 190387d45d2284c7fd7f12cbadc96161f946ae29cadGeorge Mount DataUri dataUri = new DataUri(mUrl); 191387d45d2284c7fd7f12cbadc96161f946ae29cadGeorge Mount inputStream = new ByteArrayInputStream(dataUri.getData()); 192387d45d2284c7fd7f12cbadc96161f946ae29cadGeorge Mount } else { 193387d45d2284c7fd7f12cbadc96161f946ae29cadGeorge Mount URL url = new URL(mUrl); 194387d45d2284c7fd7f12cbadc96161f946ae29cadGeorge Mount inputStream = url.openStream(); 195387d45d2284c7fd7f12cbadc96161f946ae29cadGeorge Mount } 196387d45d2284c7fd7f12cbadc96161f946ae29cadGeorge Mount return inputStream; 197387d45d2284c7fd7f12cbadc96161f946ae29cadGeorge Mount } 1983527dd1ff849ec4798eab6289593aa404dcae40bJohn Reck} 199