blob: 4f133324cfcef994abf5e975982f6dd891f99d41 [file] [log] [blame]
Adam Lesinski2a898a02010-12-09 21:04:15 -08001/*
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 */
16package com.android.launcher2;
17
18import com.android.launcher.R;
19
20import android.app.Activity;
21import android.app.AlertDialog;
22import android.app.Dialog;
23import android.app.DialogFragment;
24import android.app.WallpaperManager;
25import android.content.Context;
26import android.content.DialogInterface;
27import android.content.res.Resources;
28import android.graphics.Bitmap;
29import android.graphics.BitmapFactory;
30import android.graphics.drawable.Drawable;
31import android.os.AsyncTask;
32import android.os.Bundle;
33import android.util.Log;
34import android.view.LayoutInflater;
35import android.view.View;
36import android.view.View.OnClickListener;
37import android.view.ViewGroup;
38import android.widget.AdapterView;
39import android.widget.BaseAdapter;
Adam Cohena6612cd2010-12-21 17:34:25 -080040import android.widget.FrameLayout;
Adam Lesinski2a898a02010-12-09 21:04:15 -080041import android.widget.Gallery;
42import android.widget.GridView;
43import android.widget.ImageView;
44import android.widget.ListAdapter;
45import android.widget.SpinnerAdapter;
46
47import java.io.IOException;
48import java.util.ArrayList;
49
50public class WallpaperChooserDialogFragment extends DialogFragment implements
51 AdapterView.OnItemSelectedListener, AdapterView.OnItemClickListener {
52
53 private static final String TAG = "Launcher.WallpaperChooserDialogFragment";
54 private static final String EMBEDDED_KEY = "com.android.launcher2."
55 + "WallpaperChooserDialogFragment.EMBEDDED_KEY";
56
57 private boolean mEmbedded;
58 private ImageView mImageView = null;
59 private Bitmap mBitmap = null;
60
61 private ArrayList<Integer> mThumbs;
62 private ArrayList<Integer> mImages;
63 private WallpaperLoader mLoader;
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 @Override
87 public void onDestroy() {
88 super.onDestroy();
89
90 if (mLoader != null && mLoader.getStatus() != WallpaperLoader.Status.FINISHED) {
91 mLoader.cancel(true);
92 mLoader = null;
93 }
94 }
95
96 @Override
97 public void onDismiss(DialogInterface dialog) {
98 super.onDismiss(dialog);
99 /* On orientation changes, the dialog is effectively "dismissed" so this is called
100 * when the activity is no longer associated with this dying dialog fragment. We
101 * should just safely ignore this case by checking if getActivity() returns null
102 */
103 Activity activity = getActivity();
104 if (activity != null) {
105 activity.finish();
106 }
107 }
108
109 /* This will only be called when in XLarge mode, since this Fragment is invoked like
110 * a dialog in that mode
111 */
112 @Override
113 public Dialog onCreateDialog(Bundle savedInstanceState) {
Winson Chung3b7d86d2011-01-26 11:03:32 -0800114 findWallpapers();
115
Adam Lesinski2a898a02010-12-09 21:04:15 -0800116 final View v = getActivity().getLayoutInflater().inflate(
117 R.layout.wallpaper_chooser, null, false);
118
119 GridView gridView = (GridView) v.findViewById(R.id.gallery);
120 gridView.setOnItemClickListener(this);
121 gridView.setAdapter(new ImageAdapter(getActivity()));
122
123 final int viewInset =
124 getResources().getDimensionPixelSize(R.dimen.alert_dialog_content_inset);
125
Adam Cohena6612cd2010-12-21 17:34:25 -0800126 FrameLayout wallPaperList = (FrameLayout) v.findViewById(R.id.wallpaper_list);
Adam Lesinski2a898a02010-12-09 21:04:15 -0800127 AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
128 builder.setNegativeButton(R.string.wallpaper_cancel, null);
129 builder.setTitle(R.string.wallpaper_dialog_title);
Adam Cohena6612cd2010-12-21 17:34:25 -0800130 builder.setView(wallPaperList, viewInset, viewInset, viewInset, viewInset);
Adam Lesinski2a898a02010-12-09 21:04:15 -0800131 return builder.create();
132 }
133
134 @Override
135 public View onCreateView(LayoutInflater inflater, ViewGroup container,
136 Bundle savedInstanceState) {
137 findWallpapers();
138
139 /* If this fragment is embedded in the layout of this activity, then we should
140 * generate a view to display. Otherwise, a dialog will be created in
141 * onCreateDialog()
142 */
143 if (mEmbedded) {
144 View view = inflater.inflate(R.layout.wallpaper_chooser, container, false);
145
146 final Gallery gallery = (Gallery) view.findViewById(R.id.gallery);
147 gallery.setCallbackDuringFling(false);
148 gallery.setOnItemSelectedListener(this);
149 gallery.setAdapter(new ImageAdapter(getActivity()));
150
151 View setButton = view.findViewById(R.id.set);
152 setButton.setOnClickListener(new OnClickListener() {
153 @Override
154 public void onClick(View v) {
155 selectWallpaper(gallery.getSelectedItemPosition());
156 }
157 });
158 mImageView = (ImageView) view.findViewById(R.id.wallpaper);
159 return view;
160 }
161 return null;
162 }
163
164 private void selectWallpaper(int position) {
165 try {
166 WallpaperManager wpm = (WallpaperManager) getActivity().getSystemService(
167 Context.WALLPAPER_SERVICE);
168 wpm.setResource(mImages.get(position));
169 Activity activity = getActivity();
170 activity.setResult(Activity.RESULT_OK);
171 activity.finish();
172 } catch (IOException e) {
173 Log.e(TAG, "Failed to set wallpaper: " + e);
174 }
175 }
176
177 // Click handler for the Dialog's GridView
178 @Override
179 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
180 selectWallpaper(position);
181 }
182
183 // Selection handler for the embedded Gallery view
184 @Override
185 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
186 if (mLoader != null && mLoader.getStatus() != WallpaperLoader.Status.FINISHED) {
187 mLoader.cancel();
188 }
189 mLoader = (WallpaperLoader) new WallpaperLoader().execute(position);
190 }
191
192 @Override
193 public void onNothingSelected(AdapterView<?> parent) {
194 }
195
196 private void findWallpapers() {
197 mThumbs = new ArrayList<Integer>(24);
198 mImages = new ArrayList<Integer>(24);
199
200 final Resources resources = getResources();
201 // Context.getPackageName() may return the "original" package name,
202 // com.android.launcher2; Resources needs the real package name,
203 // com.android.launcher. So we ask Resources for what it thinks the
204 // package name should be.
205 final String packageName = resources.getResourcePackageName(R.array.wallpapers);
206
207 addWallpapers(resources, packageName, R.array.wallpapers);
208 addWallpapers(resources, packageName, R.array.extra_wallpapers);
209 }
210
211 private void addWallpapers(Resources resources, String packageName, int list) {
212 final String[] extras = resources.getStringArray(list);
213 for (String extra : extras) {
214 int res = resources.getIdentifier(extra, "drawable", packageName);
215 if (res != 0) {
216 final int thumbRes = resources.getIdentifier(extra + "_small",
217 "drawable", packageName);
218
219 if (thumbRes != 0) {
220 mThumbs.add(thumbRes);
221 mImages.add(res);
222 // Log.d(TAG, "add: [" + packageName + "]: " + extra + " (" + res + ")");
223 }
224 }
225 }
226 }
227
228 private class ImageAdapter extends BaseAdapter implements ListAdapter, SpinnerAdapter {
229 private LayoutInflater mLayoutInflater;
230
231 ImageAdapter(Activity activity) {
232 mLayoutInflater = activity.getLayoutInflater();
233 }
234
235 public int getCount() {
236 return mThumbs.size();
237 }
238
239 public Object getItem(int position) {
240 return position;
241 }
242
243 public long getItemId(int position) {
244 return position;
245 }
246
247 public View getView(int position, View convertView, ViewGroup parent) {
Adam Cohena6612cd2010-12-21 17:34:25 -0800248 View view;
Adam Lesinski2a898a02010-12-09 21:04:15 -0800249
250 if (convertView == null) {
Adam Cohena6612cd2010-12-21 17:34:25 -0800251 view = mLayoutInflater.inflate(R.layout.wallpaper_item, parent, false);
Adam Lesinski2a898a02010-12-09 21:04:15 -0800252 } else {
Adam Cohena6612cd2010-12-21 17:34:25 -0800253 view = convertView;
Adam Lesinski2a898a02010-12-09 21:04:15 -0800254 }
255
Adam Cohena6612cd2010-12-21 17:34:25 -0800256 ImageView image = (ImageView) view.findViewById(R.id.wallpaper_image);
257
Adam Lesinski2a898a02010-12-09 21:04:15 -0800258 int thumbRes = mThumbs.get(position);
259 image.setImageResource(thumbRes);
260 Drawable thumbDrawable = image.getDrawable();
261 if (thumbDrawable != null) {
262 thumbDrawable.setDither(true);
263 } else {
264 Log.e(TAG, "Error decoding thumbnail resId=" + thumbRes + " for wallpaper #"
265 + position);
266 }
267
Adam Cohena6612cd2010-12-21 17:34:25 -0800268 return view;
Adam Lesinski2a898a02010-12-09 21:04:15 -0800269 }
270 }
271
272 class WallpaperLoader extends AsyncTask<Integer, Void, Bitmap> {
273 BitmapFactory.Options mOptions;
274
275 WallpaperLoader() {
276 mOptions = new BitmapFactory.Options();
277 mOptions.inDither = false;
278 mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
279 }
280
281 @Override
282 protected Bitmap doInBackground(Integer... params) {
283 if (isCancelled()) return null;
284 try {
285 return BitmapFactory.decodeResource(getResources(),
286 mImages.get(params[0]), mOptions);
287 } catch (OutOfMemoryError e) {
288 return null;
289 }
290 }
291
292 @Override
293 protected void onPostExecute(Bitmap b) {
294 if (b == null) return;
295
296 if (!isCancelled() && !mOptions.mCancel) {
297 // Help the GC
298 if (mBitmap != null) {
299 mBitmap.recycle();
300 }
301
302 // This should always be the case, but check anyways
303 final ImageView view = mImageView;
304 if (view != null) {
305 view.setImageBitmap(b);
306
307 mBitmap = b;
308
309 final Drawable drawable = view.getDrawable();
310 drawable.setFilterBitmap(true);
311 drawable.setDither(true);
312
313 view.postInvalidate();
314 }
315
316 mLoader = null;
317 } else {
318 b.recycle();
319 }
320 }
321
322 void cancel() {
323 mOptions.requestCancelDecode();
324 super.cancel(true);
325 }
326 }
327}