• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
newInstance()65     public static WallpaperChooserDialogFragment newInstance() {
66         WallpaperChooserDialogFragment fragment = new WallpaperChooserDialogFragment();
67         fragment.setCancelable(true);
68         return fragment;
69     }
70 
71     @Override
onCreate(Bundle savedInstanceState)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
onSaveInstanceState(Bundle outState)82     public void onSaveInstanceState(Bundle outState) {
83         outState.putBoolean(EMBEDDED_KEY, mEmbedded);
84     }
85 
cancelLoader()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
onDetach()94     public void onDetach() {
95         super.onDetach();
96 
97         cancelLoader();
98     }
99 
100     @Override
onDestroy()101     public void onDestroy() {
102         super.onDestroy();
103 
104         cancelLoader();
105     }
106 
107     @Override
onDismiss(DialogInterface dialog)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
onCreateDialog(Bundle savedInstanceState)124     public Dialog onCreateDialog(Bundle savedInstanceState) {
125         findWallpapers();
126 
127         return null;
128     }
129 
130     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)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 
selectWallpaper(int position)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
onItemClick(AdapterView<?> parent, View view, int position, long id)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
onItemSelected(AdapterView<?> parent, View view, int position, long id)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
onNothingSelected(AdapterView<?> parent)189     public void onNothingSelected(AdapterView<?> parent) {
190     }
191 
findWallpapers()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 
addWallpapers(Resources resources, String packageName, int list)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 
ImageAdapter(Activity activity)230         ImageAdapter(Activity activity) {
231             mLayoutInflater = activity.getLayoutInflater();
232         }
233 
getCount()234         public int getCount() {
235             return mThumbs.size();
236         }
237 
getItem(int position)238         public Object getItem(int position) {
239             return position;
240         }
241 
getItemId(int position)242         public long getItemId(int position) {
243             return position;
244         }
245 
getView(int position, View convertView, ViewGroup parent)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> {
WallpaperLoader()272         WallpaperLoader() {
273         }
274 
275         @Override
doInBackground(Integer... params)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
onPostExecute(Bitmap b)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 
cancel()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 
setBitmap(Bitmap bitmap)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
draw(Canvas canvas)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
getOpacity()363         public int getOpacity() {
364             return android.graphics.PixelFormat.OPAQUE;
365         }
366 
367         @Override
setAlpha(int alpha)368         public void setAlpha(int alpha) {
369             // Ignore
370         }
371 
372         @Override
setColorFilter(ColorFilter cf)373         public void setColorFilter(ColorFilter cf) {
374             // Ignore
375         }
376     }
377 }
378