• 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.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 
newInstance()64     public static WallpaperChooserDialogFragment newInstance() {
65         WallpaperChooserDialogFragment fragment = new WallpaperChooserDialogFragment();
66         fragment.setCancelable(true);
67         return fragment;
68     }
69 
70     @Override
onCreate(Bundle savedInstanceState)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
onSaveInstanceState(Bundle outState)81     public void onSaveInstanceState(Bundle outState) {
82         outState.putBoolean(EMBEDDED_KEY, mEmbedded);
83     }
84 
cancelLoader()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
onDetach()93     public void onDetach() {
94         super.onDetach();
95 
96         cancelLoader();
97     }
98 
99     @Override
onDestroy()100     public void onDestroy() {
101         super.onDestroy();
102 
103         cancelLoader();
104     }
105 
106     @Override
onDismiss(DialogInterface dialog)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
onCreateDialog(Bundle savedInstanceState)123     public Dialog onCreateDialog(Bundle savedInstanceState) {
124         findWallpapers();
125 
126         return null;
127     }
128 
129     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)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 
selectWallpaper(int position)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
onItemClick(AdapterView<?> parent, View view, int position, long id)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
onItemSelected(AdapterView<?> parent, View view, int position, long id)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
onNothingSelected(AdapterView<?> parent)188     public void onNothingSelected(AdapterView<?> parent) {
189     }
190 
findWallpapers()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 
addWallpapers(Resources resources, String packageName, int list)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 
ImageAdapter(Activity activity)226         ImageAdapter(Activity activity) {
227             mLayoutInflater = activity.getLayoutInflater();
228         }
229 
getCount()230         public int getCount() {
231             return mThumbs.size();
232         }
233 
getItem(int position)234         public Object getItem(int position) {
235             return position;
236         }
237 
getItemId(int position)238         public long getItemId(int position) {
239             return position;
240         }
241 
getView(int position, View convertView, ViewGroup parent)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 
WallpaperLoader()270         WallpaperLoader() {
271             mOptions = new BitmapFactory.Options();
272             mOptions.inDither = false;
273             mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
274         }
275 
276         @Override
doInBackground(Integer... params)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
onPostExecute(Bitmap b)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 
cancel()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 
setBitmap(Bitmap bitmap)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
draw(Canvas canvas)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
getOpacity()346         public int getOpacity() {
347             return android.graphics.PixelFormat.OPAQUE;
348         }
349 
350         @Override
setAlpha(int alpha)351         public void setAlpha(int alpha) {
352             // Ignore
353         }
354 
355         @Override
setColorFilter(ColorFilter cf)356         public void setColorFilter(ColorFilter cf) {
357             // Ignore
358         }
359     }
360 }
361