Home | History | Annotate | Download | only in launcher2
      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 package com.android.launcher2;
     17 
     18 import android.app.Activity;
     19 import android.app.Dialog;
     20 import android.app.DialogFragment;
     21 import android.app.WallpaperManager;
     22 import android.content.Context;
     23 import android.content.DialogInterface;
     24 import android.content.res.Resources;
     25 import android.graphics.Bitmap;
     26 import android.graphics.BitmapFactory;
     27 import android.graphics.Canvas;
     28 import android.graphics.ColorFilter;
     29 import android.graphics.Matrix;
     30 import android.graphics.drawable.BitmapDrawable;
     31 import android.graphics.drawable.Drawable;
     32 import android.os.AsyncTask;
     33 import android.os.Bundle;
     34 import android.util.Log;
     35 import android.view.LayoutInflater;
     36 import android.view.View;
     37 import android.view.View.OnClickListener;
     38 import android.view.ViewGroup;
     39 import android.widget.AdapterView;
     40 import android.widget.BaseAdapter;
     41 import android.widget.Gallery;
     42 import android.widget.ImageView;
     43 import android.widget.ListAdapter;
     44 import android.widget.SpinnerAdapter;
     45 
     46 import com.android.launcher.R;
     47 
     48 import java.io.IOException;
     49 import java.util.ArrayList;
     50 
     51 public class WallpaperChooserDialogFragment extends DialogFragment implements
     52         AdapterView.OnItemSelectedListener, AdapterView.OnItemClickListener {
     53 
     54     private static final String TAG = "Launcher.WallpaperChooserDialogFragment";
     55     private static final String EMBEDDED_KEY = "com.android.launcher2."
     56             + "WallpaperChooserDialogFragment.EMBEDDED_KEY";
     57 
     58     private boolean mEmbedded;
     59 
     60     private ArrayList<Integer> mThumbs;
     61     private ArrayList<Integer> mImages;
     62     private WallpaperLoader mLoader;
     63     private WallpaperDrawable mWallpaperDrawable = new WallpaperDrawable();
     64 
     65     public static WallpaperChooserDialogFragment newInstance() {
     66         WallpaperChooserDialogFragment fragment = new WallpaperChooserDialogFragment();
     67         fragment.setCancelable(true);
     68         return fragment;
     69     }
     70 
     71     @Override
     72     public void onCreate(Bundle savedInstanceState) {
     73         super.onCreate(savedInstanceState);
     74         if (savedInstanceState != null && savedInstanceState.containsKey(EMBEDDED_KEY)) {
     75             mEmbedded = savedInstanceState.getBoolean(EMBEDDED_KEY);
     76         } else {
     77             mEmbedded = isInLayout();
     78         }
     79     }
     80 
     81     @Override
     82     public void onSaveInstanceState(Bundle outState) {
     83         outState.putBoolean(EMBEDDED_KEY, mEmbedded);
     84     }
     85 
     86     private void cancelLoader() {
     87         if (mLoader != null && mLoader.getStatus() != WallpaperLoader.Status.FINISHED) {
     88             mLoader.cancel(true);
     89             mLoader = null;
     90         }
     91     }
     92 
     93     @Override
     94     public void onDetach() {
     95         super.onDetach();
     96 
     97         cancelLoader();
     98     }
     99 
    100     @Override
    101     public void onDestroy() {
    102         super.onDestroy();
    103 
    104         cancelLoader();
    105     }
    106 
    107     @Override
    108     public void onDismiss(DialogInterface dialog) {
    109         super.onDismiss(dialog);
    110         /* On orientation changes, the dialog is effectively "dismissed" so this is called
    111          * when the activity is no longer associated with this dying dialog fragment. We
    112          * should just safely ignore this case by checking if getActivity() returns null
    113          */
    114         Activity activity = getActivity();
    115         if (activity != null) {
    116             activity.finish();
    117         }
    118     }
    119 
    120     /* This will only be called when in XLarge mode, since this Fragment is invoked like
    121      * a dialog in that mode
    122      */
    123     @Override
    124     public Dialog onCreateDialog(Bundle savedInstanceState) {
    125         findWallpapers();
    126 
    127         return null;
    128     }
    129 
    130     @Override
    131     public View onCreateView(LayoutInflater inflater, ViewGroup container,
    132             Bundle savedInstanceState) {
    133         findWallpapers();
    134 
    135         /* If this fragment is embedded in the layout of this activity, then we should
    136          * generate a view to display. Otherwise, a dialog will be created in
    137          * onCreateDialog()
    138          */
    139         if (mEmbedded) {
    140             View view = inflater.inflate(R.layout.wallpaper_chooser, container, false);
    141             view.setBackground(mWallpaperDrawable);
    142 
    143             final Gallery gallery = (Gallery) view.findViewById(R.id.gallery);
    144             gallery.setCallbackDuringFling(false);
    145             gallery.setOnItemSelectedListener(this);
    146             gallery.setAdapter(new ImageAdapter(getActivity()));
    147 
    148             View setButton = view.findViewById(R.id.set);
    149             setButton.setOnClickListener(new OnClickListener() {
    150                 @Override
    151                 public void onClick(View v) {
    152                     selectWallpaper(gallery.getSelectedItemPosition());
    153                 }
    154             });
    155             return view;
    156         }
    157         return null;
    158     }
    159 
    160     private void selectWallpaper(int position) {
    161         try {
    162             WallpaperManager wpm = (WallpaperManager) getActivity().getSystemService(
    163                     Context.WALLPAPER_SERVICE);
    164             wpm.setResource(mImages.get(position));
    165             Activity activity = getActivity();
    166             activity.setResult(Activity.RESULT_OK);
    167             activity.finish();
    168         } catch (IOException e) {
    169             Log.e(TAG, "Failed to set wallpaper: " + e);
    170         }
    171     }
    172 
    173     // Click handler for the Dialog's GridView
    174     @Override
    175     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    176         selectWallpaper(position);
    177     }
    178 
    179     // Selection handler for the embedded Gallery view
    180     @Override
    181     public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
    182         if (mLoader != null && mLoader.getStatus() != WallpaperLoader.Status.FINISHED) {
    183             mLoader.cancel();
    184         }
    185         mLoader = (WallpaperLoader) new WallpaperLoader().execute(position);
    186     }
    187 
    188     @Override
    189     public void onNothingSelected(AdapterView<?> parent) {
    190     }
    191 
    192     private void findWallpapers() {
    193         mThumbs = new ArrayList<Integer>(24);
    194         mImages = new ArrayList<Integer>(24);
    195 
    196         final Resources resources = getResources();
    197         // Context.getPackageName() may return the "original" package name,
    198         // com.android.launcher2; Resources needs the real package name,
    199         // com.android.launcher. So we ask Resources for what it thinks the
    200         // package name should be.
    201         final String packageName = resources.getResourcePackageName(R.array.wallpapers);
    202 
    203         addWallpapers(resources, packageName, R.array.wallpapers);
    204         addWallpapers(resources, packageName, R.array.extra_wallpapers);
    205     }
    206 
    207     private void addWallpapers(Resources resources, String packageName, int list) {
    208         final String[] extras = resources.getStringArray(list);
    209         for (String extra : extras) {
    210             int res = resources.getIdentifier(extra, "drawable", packageName);
    211             if (res != 0) {
    212                 final int thumbRes = resources.getIdentifier(extra + "_small",
    213                         "drawable", packageName);
    214 
    215                 if (thumbRes != 0) {
    216                     mThumbs.add(thumbRes);
    217                     mImages.add(res);
    218                     // Log.d(TAG, "add: [" + packageName + "]: " + extra + " (" + res + ")");
    219                 }
    220             }
    221         }
    222     }
    223 
    224     private class ImageAdapter extends BaseAdapter implements ListAdapter, SpinnerAdapter {
    225         private LayoutInflater mLayoutInflater;
    226 
    227         ImageAdapter(Activity activity) {
    228             mLayoutInflater = activity.getLayoutInflater();
    229         }
    230 
    231         public int getCount() {
    232             return mThumbs.size();
    233         }
    234 
    235         public Object getItem(int position) {
    236             return position;
    237         }
    238 
    239         public long getItemId(int position) {
    240             return position;
    241         }
    242 
    243         public View getView(int position, View convertView, ViewGroup parent) {
    244             View view;
    245 
    246             if (convertView == null) {
    247                 view = mLayoutInflater.inflate(R.layout.wallpaper_item, parent, false);
    248             } else {
    249                 view = convertView;
    250             }
    251 
    252             ImageView image = (ImageView) view.findViewById(R.id.wallpaper_image);
    253 
    254             int thumbRes = mThumbs.get(position);
    255             image.setImageResource(thumbRes);
    256             Drawable thumbDrawable = image.getDrawable();
    257             if (thumbDrawable != null) {
    258                 thumbDrawable.setDither(true);
    259             } else {
    260                 Log.e(TAG, "Error decoding thumbnail resId=" + thumbRes + " for wallpaper #"
    261                         + position);
    262             }
    263 
    264             return view;
    265         }
    266     }
    267 
    268     class WallpaperLoader extends AsyncTask<Integer, Void, Bitmap> {
    269         WallpaperLoader() {
    270         }
    271 
    272         @Override
    273         protected Bitmap doInBackground(Integer... params) {
    274             if (isCancelled()) return null;
    275             try {
    276                 final Drawable d = getResources().getDrawable(mImages.get(params[0]));
    277                 if (d instanceof BitmapDrawable) {
    278                     return ((BitmapDrawable)d).getBitmap();
    279                 }
    280                 return null;
    281             } catch (OutOfMemoryError e) {
    282                 Log.w(TAG, String.format(
    283                         "Out of memory trying to load wallpaper res=%08x", params[0]),
    284                         e);
    285                 return null;
    286             }
    287         }
    288 
    289         @Override
    290         protected void onPostExecute(Bitmap b) {
    291             if (b == null) return;
    292 
    293             if (!isCancelled()) {
    294                 View v = getView();
    295                 if (v != null) {
    296                     mWallpaperDrawable.setBitmap(b);
    297                     v.postInvalidate();
    298                 } else {
    299                     mWallpaperDrawable.setBitmap(null);
    300                 }
    301                 mLoader = null;
    302             } else {
    303                b.recycle();
    304             }
    305         }
    306 
    307         void cancel() {
    308             super.cancel(true);
    309         }
    310     }
    311 
    312     /**
    313      * Custom drawable that centers the bitmap fed to it.
    314      */
    315     static class WallpaperDrawable extends Drawable {
    316 
    317         Bitmap mBitmap;
    318         int mIntrinsicWidth;
    319         int mIntrinsicHeight;
    320         Matrix mMatrix;
    321 
    322         /* package */void setBitmap(Bitmap bitmap) {
    323             mBitmap = bitmap;
    324             if (mBitmap == null)
    325                 return;
    326             mIntrinsicWidth = mBitmap.getWidth();
    327             mIntrinsicHeight = mBitmap.getHeight();
    328             mMatrix = null;
    329         }
    330 
    331         @Override
    332         public void draw(Canvas canvas) {
    333             if (mBitmap == null) return;
    334 
    335             if (mMatrix == null) {
    336                 final int vwidth = canvas.getWidth();
    337                 final int vheight = canvas.getHeight();
    338                 final int dwidth = mIntrinsicWidth;
    339                 final int dheight = mIntrinsicHeight;
    340 
    341                 float scale = 1.0f;
    342 
    343                 if (dwidth < vwidth || dheight < vheight) {
    344                     scale = Math.max((float) vwidth / (float) dwidth,
    345                             (float) vheight / (float) dheight);
    346                 }
    347 
    348                 float dx = (vwidth - dwidth * scale) * 0.5f + 0.5f;
    349                 float dy = (vheight - dheight * scale) * 0.5f + 0.5f;
    350 
    351                 mMatrix = new Matrix();
    352                 mMatrix.setScale(scale, scale);
    353                 mMatrix.postTranslate((int) dx, (int) dy);
    354             }
    355 
    356             canvas.drawBitmap(mBitmap, mMatrix, null);
    357         }
    358 
    359         @Override
    360         public int getOpacity() {
    361             return android.graphics.PixelFormat.OPAQUE;
    362         }
    363 
    364         @Override
    365         public void setAlpha(int alpha) {
    366             // Ignore
    367         }
    368 
    369         @Override
    370         public void setColorFilter(ColorFilter cf) {
    371             // Ignore
    372         }
    373     }
    374 }
    375