Home | History | Annotate | Download | only in browser
      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 
     54     public WallpaperHandler(Context context, String url) {
     55         mContext = context;
     56         mUrl = url;
     57     }
     58 
     59     @Override
     60     public void onCancel(DialogInterface dialog) {
     61         mCanceled = true;
     62     }
     63 
     64     @Override
     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
     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                 wm.setBitmap(scaledWallpaper);
    134             }
    135         } catch (IOException e) {
    136             Log.e(LOGTAG, "Unable to set new wallpaper");
    137             // Act as though the user canceled the operation so we try to
    138             // restore the old wallpaper.
    139             mCanceled = true;
    140         } finally {
    141             if (inputstream != null) {
    142                 try {
    143                     inputstream.close();
    144                 } catch (IOException e) {
    145                     // Ignore
    146                 }
    147             }
    148         }
    149 
    150         if (mCanceled) {
    151             // Restore the old wallpaper if the user cancelled whilst we were
    152             // setting
    153             // the new wallpaper.
    154             int width = oldWallpaper.getIntrinsicWidth();
    155             int height = oldWallpaper.getIntrinsicHeight();
    156             Bitmap bm = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
    157             Canvas canvas = new Canvas(bm);
    158             oldWallpaper.setBounds(0, 0, width, height);
    159             oldWallpaper.draw(canvas);
    160             canvas.setBitmap(null);
    161             try {
    162                 wm.setBitmap(bm);
    163             } catch (IOException e) {
    164                 Log.e(LOGTAG, "Unable to restore old wallpaper.");
    165             }
    166             mCanceled = false;
    167         }
    168 
    169         if (mWallpaperProgress.isShowing()) {
    170             mWallpaperProgress.dismiss();
    171         }
    172     }
    173 
    174     /**
    175      * Opens the input stream for the URL that the class should
    176      * use to set the wallpaper. Abstracts the difference between
    177      * standard URLs and data URLs.
    178      * @return An open InputStream for the data at the URL
    179      * @throws IOException if there is an error opening the URL stream
    180      * @throws MalformedURLException if the URL is malformed
    181      */
    182     private InputStream openStream() throws IOException, MalformedURLException {
    183         InputStream inputStream = null;
    184         if (DataUri.isDataUri(mUrl)) {
    185             DataUri dataUri = new DataUri(mUrl);
    186             inputStream = new ByteArrayInputStream(dataUri.getData());
    187         } else {
    188             URL url = new URL(mUrl);
    189             inputStream = url.openStream();
    190         }
    191         return inputStream;
    192     }
    193 }
    194