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                 int thumbRes = resources.getIdentifier(extra + "_small",
    213                         "drawable", packageName);
    214 
    215                 //Log.d(TAG, "add: [" + packageName + "]: " + extra + " (res=" + res + " thumb=" + thumbRes + ")");
    216                 if (thumbRes == 0) {
    217                     Log.w(TAG, "warning: built-in wallpaper " + extra
    218                             + " without " + extra + "_thumb");
    219                     thumbRes = R.mipmap.ic_launcher_wallpaper;
    220                 }
    221                 mThumbs.add(thumbRes);
    222                 mImages.add(res);
    223             }
    224         }
    225     }
    226 
    227     private class ImageAdapter extends BaseAdapter implements ListAdapter, SpinnerAdapter {
    228         private LayoutInflater mLayoutInflater;
    229 
    230         ImageAdapter(Activity activity) {
    231             mLayoutInflater = activity.getLayoutInflater();
    232         }
    233 
    234         public int getCount() {
    235             return mThumbs.size();
    236         }
    237 
    238         public Object getItem(int position) {
    239             return position;
    240         }
    241 
    242         public long getItemId(int position) {
    243             return position;
    244         }
    245 
    246         public View getView(int position, View convertView, ViewGroup parent) {
    247             View view;
    248 
    249             if (convertView == null) {
    250                 view = mLayoutInflater.inflate(R.layout.wallpaper_item, parent, false);
    251             } else {
    252                 view = convertView;
    253             }
    254 
    255             ImageView image = (ImageView) view.findViewById(R.id.wallpaper_image);
    256 
    257             int thumbRes = mThumbs.get(position);
    258             image.setImageResource(thumbRes);
    259             Drawable thumbDrawable = image.getDrawable();
    260             if (thumbDrawable != null) {
    261                 thumbDrawable.setDither(true);
    262             } else {
    263                 Log.e(TAG, "Error decoding thumbnail resId=" + thumbRes + " for wallpaper #"
    264                         + position);
    265             }
    266 
    267             return view;
    268         }
    269     }
    270 
    271     class WallpaperLoader extends AsyncTask<Integer, Void, Bitmap> {
    272         WallpaperLoader() {
    273         }
    274 
    275         @Override
    276         protected Bitmap doInBackground(Integer... params) {
    277             if (isCancelled()) return null;
    278             try {
    279                 final Drawable d = getResources().getDrawable(mImages.get(params[0]));
    280                 if (d instanceof BitmapDrawable) {
    281                     return ((BitmapDrawable)d).getBitmap();
    282                 }
    283                 return null;
    284             } catch (OutOfMemoryError e) {
    285                 Log.w(TAG, String.format(
    286                         "Out of memory trying to load wallpaper res=%08x", params[0]),
    287                         e);
    288                 return null;
    289             }
    290         }
    291 
    292         @Override
    293         protected void onPostExecute(Bitmap b) {
    294             if (b == null) return;
    295 
    296             if (!isCancelled()) {
    297                 View v = getView();
    298                 if (v != null) {
    299                     mWallpaperDrawable.setBitmap(b);
    300                     v.postInvalidate();
    301                 } else {
    302                     mWallpaperDrawable.setBitmap(null);
    303                 }
    304                 mLoader = null;
    305             } else {
    306                b.recycle();
    307             }
    308         }
    309 
    310         void cancel() {
    311             super.cancel(true);
    312         }
    313     }
    314 
    315     /**
    316      * Custom drawable that centers the bitmap fed to it.
    317      */
    318     static class WallpaperDrawable extends Drawable {
    319 
    320         Bitmap mBitmap;
    321         int mIntrinsicWidth;
    322         int mIntrinsicHeight;
    323         Matrix mMatrix;
    324 
    325         /* package */void setBitmap(Bitmap bitmap) {
    326             mBitmap = bitmap;
    327             if (mBitmap == null)
    328                 return;
    329             mIntrinsicWidth = mBitmap.getWidth();
    330             mIntrinsicHeight = mBitmap.getHeight();
    331             mMatrix = null;
    332         }
    333 
    334         @Override
    335         public void draw(Canvas canvas) {
    336             if (mBitmap == null) return;
    337 
    338             if (mMatrix == null) {
    339                 final int vwidth = canvas.getWidth();
    340                 final int vheight = canvas.getHeight();
    341                 final int dwidth = mIntrinsicWidth;
    342                 final int dheight = mIntrinsicHeight;
    343 
    344                 float scale = 1.0f;
    345 
    346                 if (dwidth < vwidth || dheight < vheight) {
    347                     scale = Math.max((float) vwidth / (float) dwidth,
    348                             (float) vheight / (float) dheight);
    349                 }
    350 
    351                 float dx = (vwidth - dwidth * scale) * 0.5f + 0.5f;
    352                 float dy = (vheight - dheight * scale) * 0.5f + 0.5f;
    353 
    354                 mMatrix = new Matrix();
    355                 mMatrix.setScale(scale, scale);
    356                 mMatrix.postTranslate((int) dx, (int) dy);
    357             }
    358 
    359             canvas.drawBitmap(mBitmap, mMatrix, null);
    360         }
    361 
    362         @Override
    363         public int getOpacity() {
    364             return android.graphics.PixelFormat.OPAQUE;
    365         }
    366 
    367         @Override
    368         public void setAlpha(int alpha) {
    369             // Ignore
    370         }
    371 
    372         @Override
    373         public void setColorFilter(ColorFilter cf) {
    374             // Ignore
    375         }
    376     }
    377 }
    378