blob: 10bfc56bcaf6e4c981f4c3aa5864c6ab41a673d8 [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;
40import android.widget.Gallery;
41import android.widget.GridView;
42import android.widget.ImageView;
43import android.widget.ListAdapter;
44import android.widget.SpinnerAdapter;
45
46import java.io.IOException;
47import java.util.ArrayList;
48
49public 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 ImageView mImageView = null;
58 private Bitmap mBitmap = null;
59
60 private ArrayList<Integer> mThumbs;
61 private ArrayList<Integer> mImages;
62 private WallpaperLoader mLoader;
63
64 public static WallpaperChooserDialogFragment newInstance() {
65 WallpaperChooserDialogFragment fragment = new WallpaperChooserDialogFragment();
66 fragment.setCancelable(true);
67 return fragment;
68 }
69
70 @Override
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
81 public void onSaveInstanceState(Bundle outState) {
82 outState.putBoolean(EMBEDDED_KEY, mEmbedded);
83 }
84
85 @Override
86 public void onDestroy() {
87 super.onDestroy();
88
89 if (mLoader != null && mLoader.getStatus() != WallpaperLoader.Status.FINISHED) {
90 mLoader.cancel(true);
91 mLoader = null;
92 }
93 }
94
95 @Override
96 public void onDismiss(DialogInterface dialog) {
97 super.onDismiss(dialog);
98 /* On orientation changes, the dialog is effectively "dismissed" so this is called
99 * when the activity is no longer associated with this dying dialog fragment. We
100 * should just safely ignore this case by checking if getActivity() returns null
101 */
102 Activity activity = getActivity();
103 if (activity != null) {
104 activity.finish();
105 }
106 }
107
108 /* This will only be called when in XLarge mode, since this Fragment is invoked like
109 * a dialog in that mode
110 */
111 @Override
112 public Dialog onCreateDialog(Bundle savedInstanceState) {
113 final View v = getActivity().getLayoutInflater().inflate(
114 R.layout.wallpaper_chooser, null, false);
115
116 GridView gridView = (GridView) v.findViewById(R.id.gallery);
117 gridView.setOnItemClickListener(this);
118 gridView.setAdapter(new ImageAdapter(getActivity()));
119
120 final int viewInset =
121 getResources().getDimensionPixelSize(R.dimen.alert_dialog_content_inset);
122
123 AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
124 builder.setNegativeButton(R.string.wallpaper_cancel, null);
125 builder.setTitle(R.string.wallpaper_dialog_title);
126 builder.setView(gridView, viewInset, viewInset, viewInset, viewInset);
127 return builder.create();
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
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 mImageView = (ImageView) view.findViewById(R.id.wallpaper);
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 final int thumbRes = resources.getIdentifier(extra + "_small",
213 "drawable", packageName);
214
215 if (thumbRes != 0) {
216 mThumbs.add(thumbRes);
217 mImages.add(res);
218 // Log.d(TAG, "add: [" + packageName + "]: " + extra + " (" + res + ")");
219 }
220 }
221 }
222 }
223
224 private class ImageAdapter extends BaseAdapter implements ListAdapter, SpinnerAdapter {
225 private LayoutInflater mLayoutInflater;
226
227 ImageAdapter(Activity activity) {
228 mLayoutInflater = activity.getLayoutInflater();
229 }
230
231 public int getCount() {
232 return mThumbs.size();
233 }
234
235 public Object getItem(int position) {
236 return position;
237 }
238
239 public long getItemId(int position) {
240 return position;
241 }
242
243 public View getView(int position, View convertView, ViewGroup parent) {
244 ImageView image;
245
246 if (convertView == null) {
247 image = (ImageView) mLayoutInflater.inflate(R.layout.wallpaper_item, parent, false);
248 } else {
249 image = (ImageView) convertView;
250 }
251
252 int thumbRes = mThumbs.get(position);
253 image.setImageResource(thumbRes);
254 Drawable thumbDrawable = image.getDrawable();
255 if (thumbDrawable != null) {
256 thumbDrawable.setDither(true);
257 } else {
258 Log.e(TAG, "Error decoding thumbnail resId=" + thumbRes + " for wallpaper #"
259 + position);
260 }
261
262 return image;
263 }
264 }
265
266 class WallpaperLoader extends AsyncTask<Integer, Void, Bitmap> {
267 BitmapFactory.Options mOptions;
268
269 WallpaperLoader() {
270 mOptions = new BitmapFactory.Options();
271 mOptions.inDither = false;
272 mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
273 }
274
275 @Override
276 protected Bitmap doInBackground(Integer... params) {
277 if (isCancelled()) return null;
278 try {
279 return BitmapFactory.decodeResource(getResources(),
280 mImages.get(params[0]), mOptions);
281 } catch (OutOfMemoryError e) {
282 return null;
283 }
284 }
285
286 @Override
287 protected void onPostExecute(Bitmap b) {
288 if (b == null) return;
289
290 if (!isCancelled() && !mOptions.mCancel) {
291 // Help the GC
292 if (mBitmap != null) {
293 mBitmap.recycle();
294 }
295
296 // This should always be the case, but check anyways
297 final ImageView view = mImageView;
298 if (view != null) {
299 view.setImageBitmap(b);
300
301 mBitmap = b;
302
303 final Drawable drawable = view.getDrawable();
304 drawable.setFilterBitmap(true);
305 drawable.setDither(true);
306
307 view.postInvalidate();
308 }
309
310 mLoader = null;
311 } else {
312 b.recycle();
313 }
314 }
315
316 void cancel() {
317 mOptions.requestCancelDecode();
318 super.cancel(true);
319 }
320 }
321}