blob: 7c4ac2e3397815fbb191b3e3d8b00d704435e5c1 [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
Adam Lesinski2a898a02010-12-09 21:04:15 -080018import android.app.Activity;
Adam Lesinski2a898a02010-12-09 21:04:15 -080019import android.app.Dialog;
20import android.app.DialogFragment;
21import android.app.WallpaperManager;
22import android.content.Context;
23import android.content.DialogInterface;
24import android.content.res.Resources;
25import android.graphics.Bitmap;
26import android.graphics.BitmapFactory;
Amith Yamasani6be59492011-06-21 13:03:34 -070027import android.graphics.Canvas;
28import android.graphics.ColorFilter;
Adam Lesinski2a898a02010-12-09 21:04:15 -080029import android.graphics.drawable.Drawable;
30import android.os.AsyncTask;
31import android.os.Bundle;
32import android.util.Log;
33import android.view.LayoutInflater;
34import android.view.View;
Amith Yamasani6be59492011-06-21 13:03:34 -070035import android.view.View.OnClickListener;
Michael Jurka92f3d462011-11-22 21:02:29 -080036import android.view.ViewGroup;
Adam Lesinski2a898a02010-12-09 21:04:15 -080037import android.widget.AdapterView;
38import android.widget.BaseAdapter;
39import android.widget.Gallery;
Adam Lesinski2a898a02010-12-09 21:04:15 -080040import android.widget.ImageView;
41import android.widget.ListAdapter;
42import android.widget.SpinnerAdapter;
43
Amith Yamasani6be59492011-06-21 13:03:34 -070044import com.android.launcher.R;
45
Adam Lesinski2a898a02010-12-09 21:04:15 -080046import 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;
Adam Lesinski2a898a02010-12-09 21:04:15 -080057 private Bitmap mBitmap = null;
58
59 private ArrayList<Integer> mThumbs;
60 private ArrayList<Integer> mImages;
61 private WallpaperLoader mLoader;
Amith Yamasani6be59492011-06-21 13:03:34 -070062 private WallpaperDrawable mWallpaperDrawable = new WallpaperDrawable();
Adam Lesinski2a898a02010-12-09 21:04:15 -080063
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) {
Winson Chung3b7d86d2011-01-26 11:03:32 -0800113 findWallpapers();
114
Amith Yamasani6be59492011-06-21 13:03:34 -0700115 // TODO: The following code is not exercised right now and may be removed
116 // if the dialog version is not needed.
117 /*
Adam Lesinski2a898a02010-12-09 21:04:15 -0800118 final View v = getActivity().getLayoutInflater().inflate(
119 R.layout.wallpaper_chooser, null, false);
120
121 GridView gridView = (GridView) v.findViewById(R.id.gallery);
122 gridView.setOnItemClickListener(this);
123 gridView.setAdapter(new ImageAdapter(getActivity()));
124
125 final int viewInset =
126 getResources().getDimensionPixelSize(R.dimen.alert_dialog_content_inset);
Amith Yamasani6be59492011-06-21 13:03:34 -0700127
Adam Cohena6612cd2010-12-21 17:34:25 -0800128 FrameLayout wallPaperList = (FrameLayout) v.findViewById(R.id.wallpaper_list);
Adam Lesinski2a898a02010-12-09 21:04:15 -0800129 AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
130 builder.setNegativeButton(R.string.wallpaper_cancel, null);
131 builder.setTitle(R.string.wallpaper_dialog_title);
Amith Yamasani6be59492011-06-21 13:03:34 -0700132 builder.setView(wallPaperList,
133 viewInset, viewInset, viewInset, viewInset); return builder.create();
134 */
135 return null;
Adam Lesinski2a898a02010-12-09 21:04:15 -0800136 }
137
138 @Override
139 public View onCreateView(LayoutInflater inflater, ViewGroup container,
140 Bundle savedInstanceState) {
141 findWallpapers();
142
143 /* If this fragment is embedded in the layout of this activity, then we should
144 * generate a view to display. Otherwise, a dialog will be created in
145 * onCreateDialog()
146 */
147 if (mEmbedded) {
148 View view = inflater.inflate(R.layout.wallpaper_chooser, container, false);
Amith Yamasani6be59492011-06-21 13:03:34 -0700149 view.setBackgroundDrawable(mWallpaperDrawable);
Adam Lesinski2a898a02010-12-09 21:04:15 -0800150
151 final Gallery gallery = (Gallery) view.findViewById(R.id.gallery);
152 gallery.setCallbackDuringFling(false);
153 gallery.setOnItemSelectedListener(this);
154 gallery.setAdapter(new ImageAdapter(getActivity()));
155
156 View setButton = view.findViewById(R.id.set);
157 setButton.setOnClickListener(new OnClickListener() {
158 @Override
159 public void onClick(View v) {
160 selectWallpaper(gallery.getSelectedItemPosition());
161 }
162 });
Adam Lesinski2a898a02010-12-09 21:04:15 -0800163 return view;
164 }
165 return null;
166 }
167
168 private void selectWallpaper(int position) {
169 try {
170 WallpaperManager wpm = (WallpaperManager) getActivity().getSystemService(
171 Context.WALLPAPER_SERVICE);
172 wpm.setResource(mImages.get(position));
173 Activity activity = getActivity();
174 activity.setResult(Activity.RESULT_OK);
175 activity.finish();
176 } catch (IOException e) {
177 Log.e(TAG, "Failed to set wallpaper: " + e);
178 }
179 }
180
181 // Click handler for the Dialog's GridView
182 @Override
183 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
184 selectWallpaper(position);
185 }
186
187 // Selection handler for the embedded Gallery view
188 @Override
189 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
190 if (mLoader != null && mLoader.getStatus() != WallpaperLoader.Status.FINISHED) {
191 mLoader.cancel();
192 }
193 mLoader = (WallpaperLoader) new WallpaperLoader().execute(position);
194 }
195
196 @Override
197 public void onNothingSelected(AdapterView<?> parent) {
198 }
199
200 private void findWallpapers() {
201 mThumbs = new ArrayList<Integer>(24);
202 mImages = new ArrayList<Integer>(24);
203
204 final Resources resources = getResources();
205 // Context.getPackageName() may return the "original" package name,
206 // com.android.launcher2; Resources needs the real package name,
207 // com.android.launcher. So we ask Resources for what it thinks the
208 // package name should be.
209 final String packageName = resources.getResourcePackageName(R.array.wallpapers);
210
211 addWallpapers(resources, packageName, R.array.wallpapers);
212 addWallpapers(resources, packageName, R.array.extra_wallpapers);
213 }
214
215 private void addWallpapers(Resources resources, String packageName, int list) {
216 final String[] extras = resources.getStringArray(list);
217 for (String extra : extras) {
218 int res = resources.getIdentifier(extra, "drawable", packageName);
219 if (res != 0) {
220 final int thumbRes = resources.getIdentifier(extra + "_small",
221 "drawable", packageName);
222
223 if (thumbRes != 0) {
224 mThumbs.add(thumbRes);
225 mImages.add(res);
226 // Log.d(TAG, "add: [" + packageName + "]: " + extra + " (" + res + ")");
227 }
228 }
229 }
230 }
231
232 private class ImageAdapter extends BaseAdapter implements ListAdapter, SpinnerAdapter {
233 private LayoutInflater mLayoutInflater;
234
235 ImageAdapter(Activity activity) {
236 mLayoutInflater = activity.getLayoutInflater();
237 }
238
239 public int getCount() {
240 return mThumbs.size();
241 }
242
243 public Object getItem(int position) {
244 return position;
245 }
246
247 public long getItemId(int position) {
248 return position;
249 }
250
251 public View getView(int position, View convertView, ViewGroup parent) {
Adam Cohena6612cd2010-12-21 17:34:25 -0800252 View view;
Adam Lesinski2a898a02010-12-09 21:04:15 -0800253
254 if (convertView == null) {
Adam Cohena6612cd2010-12-21 17:34:25 -0800255 view = mLayoutInflater.inflate(R.layout.wallpaper_item, parent, false);
Adam Lesinski2a898a02010-12-09 21:04:15 -0800256 } else {
Adam Cohena6612cd2010-12-21 17:34:25 -0800257 view = convertView;
Adam Lesinski2a898a02010-12-09 21:04:15 -0800258 }
259
Adam Cohena6612cd2010-12-21 17:34:25 -0800260 ImageView image = (ImageView) view.findViewById(R.id.wallpaper_image);
261
Adam Lesinski2a898a02010-12-09 21:04:15 -0800262 int thumbRes = mThumbs.get(position);
263 image.setImageResource(thumbRes);
264 Drawable thumbDrawable = image.getDrawable();
265 if (thumbDrawable != null) {
266 thumbDrawable.setDither(true);
267 } else {
268 Log.e(TAG, "Error decoding thumbnail resId=" + thumbRes + " for wallpaper #"
269 + position);
270 }
271
Adam Cohena6612cd2010-12-21 17:34:25 -0800272 return view;
Adam Lesinski2a898a02010-12-09 21:04:15 -0800273 }
274 }
275
276 class WallpaperLoader extends AsyncTask<Integer, Void, Bitmap> {
277 BitmapFactory.Options mOptions;
278
279 WallpaperLoader() {
280 mOptions = new BitmapFactory.Options();
281 mOptions.inDither = false;
282 mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
283 }
284
285 @Override
286 protected Bitmap doInBackground(Integer... params) {
287 if (isCancelled()) return null;
288 try {
289 return BitmapFactory.decodeResource(getResources(),
290 mImages.get(params[0]), mOptions);
291 } catch (OutOfMemoryError e) {
292 return null;
293 }
294 }
295
296 @Override
297 protected void onPostExecute(Bitmap b) {
298 if (b == null) return;
299
300 if (!isCancelled() && !mOptions.mCancel) {
301 // Help the GC
302 if (mBitmap != null) {
303 mBitmap.recycle();
304 }
305
Winson Chungf8742be2011-08-22 16:19:31 -0700306 View v = getView();
307 if (v != null) {
308 mBitmap = b;
309 mWallpaperDrawable.setBitmap(b);
310 v.postInvalidate();
311 } else {
312 mBitmap = null;
313 mWallpaperDrawable.setBitmap(null);
314 }
Adam Lesinski2a898a02010-12-09 21:04:15 -0800315 mLoader = null;
316 } else {
317 b.recycle();
318 }
319 }
320
321 void cancel() {
322 mOptions.requestCancelDecode();
323 super.cancel(true);
324 }
325 }
Amith Yamasani6be59492011-06-21 13:03:34 -0700326
327 /**
328 * Custom drawable that centers the bitmap fed to it.
329 */
330 static class WallpaperDrawable extends Drawable {
331
332 Bitmap mBitmap;
333 int mIntrinsicWidth;
334 int mIntrinsicHeight;
335
336 /* package */void setBitmap(Bitmap bitmap) {
337 mBitmap = bitmap;
338 if (mBitmap == null)
339 return;
340 mIntrinsicWidth = mBitmap.getWidth();
341 mIntrinsicHeight = mBitmap.getHeight();
342 }
343
344 @Override
345 public void draw(Canvas canvas) {
346 if (mBitmap == null) return;
347 int width = canvas.getWidth();
348 int height = canvas.getHeight();
349 int x = (width - mIntrinsicWidth) / 2;
350 int y = (height - mIntrinsicHeight) / 2;
351 canvas.drawBitmap(mBitmap, x, y, null);
352 }
353
354 @Override
355 public int getOpacity() {
356 return android.graphics.PixelFormat.OPAQUE;
357 }
358
359 @Override
360 public void setAlpha(int alpha) {
361 // Ignore
362 }
363
364 @Override
365 public void setColorFilter(ColorFilter cf) {
366 // Ignore
367 }
368 }
Adam Lesinski2a898a02010-12-09 21:04:15 -0800369}