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