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