blob: 030d33d9f96b718d3d639f90f7fa7c45bc9268a7 [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 return null;
Adam Lesinski2a898a02010-12-09 21:04:15 -0800116 }
117
118 @Override
119 public View onCreateView(LayoutInflater inflater, ViewGroup container,
120 Bundle savedInstanceState) {
121 findWallpapers();
122
123 /* If this fragment is embedded in the layout of this activity, then we should
124 * generate a view to display. Otherwise, a dialog will be created in
125 * onCreateDialog()
126 */
127 if (mEmbedded) {
128 View view = inflater.inflate(R.layout.wallpaper_chooser, container, false);
Amith Yamasani6be59492011-06-21 13:03:34 -0700129 view.setBackgroundDrawable(mWallpaperDrawable);
Adam Lesinski2a898a02010-12-09 21:04:15 -0800130
131 final Gallery gallery = (Gallery) view.findViewById(R.id.gallery);
132 gallery.setCallbackDuringFling(false);
133 gallery.setOnItemSelectedListener(this);
134 gallery.setAdapter(new ImageAdapter(getActivity()));
135
136 View setButton = view.findViewById(R.id.set);
137 setButton.setOnClickListener(new OnClickListener() {
138 @Override
139 public void onClick(View v) {
140 selectWallpaper(gallery.getSelectedItemPosition());
141 }
142 });
Adam Lesinski2a898a02010-12-09 21:04:15 -0800143 return view;
144 }
145 return null;
146 }
147
148 private void selectWallpaper(int position) {
149 try {
150 WallpaperManager wpm = (WallpaperManager) getActivity().getSystemService(
151 Context.WALLPAPER_SERVICE);
152 wpm.setResource(mImages.get(position));
153 Activity activity = getActivity();
154 activity.setResult(Activity.RESULT_OK);
155 activity.finish();
156 } catch (IOException e) {
157 Log.e(TAG, "Failed to set wallpaper: " + e);
158 }
159 }
160
161 // Click handler for the Dialog's GridView
162 @Override
163 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
164 selectWallpaper(position);
165 }
166
167 // Selection handler for the embedded Gallery view
168 @Override
169 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
170 if (mLoader != null && mLoader.getStatus() != WallpaperLoader.Status.FINISHED) {
171 mLoader.cancel();
172 }
173 mLoader = (WallpaperLoader) new WallpaperLoader().execute(position);
174 }
175
176 @Override
177 public void onNothingSelected(AdapterView<?> parent) {
178 }
179
180 private void findWallpapers() {
181 mThumbs = new ArrayList<Integer>(24);
182 mImages = new ArrayList<Integer>(24);
183
184 final Resources resources = getResources();
185 // Context.getPackageName() may return the "original" package name,
186 // com.android.launcher2; Resources needs the real package name,
187 // com.android.launcher. So we ask Resources for what it thinks the
188 // package name should be.
189 final String packageName = resources.getResourcePackageName(R.array.wallpapers);
190
191 addWallpapers(resources, packageName, R.array.wallpapers);
192 addWallpapers(resources, packageName, R.array.extra_wallpapers);
193 }
194
195 private void addWallpapers(Resources resources, String packageName, int list) {
196 final String[] extras = resources.getStringArray(list);
197 for (String extra : extras) {
198 int res = resources.getIdentifier(extra, "drawable", packageName);
199 if (res != 0) {
200 final int thumbRes = resources.getIdentifier(extra + "_small",
201 "drawable", packageName);
202
203 if (thumbRes != 0) {
204 mThumbs.add(thumbRes);
205 mImages.add(res);
206 // Log.d(TAG, "add: [" + packageName + "]: " + extra + " (" + res + ")");
207 }
208 }
209 }
210 }
211
212 private class ImageAdapter extends BaseAdapter implements ListAdapter, SpinnerAdapter {
213 private LayoutInflater mLayoutInflater;
214
215 ImageAdapter(Activity activity) {
216 mLayoutInflater = activity.getLayoutInflater();
217 }
218
219 public int getCount() {
220 return mThumbs.size();
221 }
222
223 public Object getItem(int position) {
224 return position;
225 }
226
227 public long getItemId(int position) {
228 return position;
229 }
230
231 public View getView(int position, View convertView, ViewGroup parent) {
Adam Cohena6612cd2010-12-21 17:34:25 -0800232 View view;
Adam Lesinski2a898a02010-12-09 21:04:15 -0800233
234 if (convertView == null) {
Adam Cohena6612cd2010-12-21 17:34:25 -0800235 view = mLayoutInflater.inflate(R.layout.wallpaper_item, parent, false);
Adam Lesinski2a898a02010-12-09 21:04:15 -0800236 } else {
Adam Cohena6612cd2010-12-21 17:34:25 -0800237 view = convertView;
Adam Lesinski2a898a02010-12-09 21:04:15 -0800238 }
239
Adam Cohena6612cd2010-12-21 17:34:25 -0800240 ImageView image = (ImageView) view.findViewById(R.id.wallpaper_image);
241
Adam Lesinski2a898a02010-12-09 21:04:15 -0800242 int thumbRes = mThumbs.get(position);
243 image.setImageResource(thumbRes);
244 Drawable thumbDrawable = image.getDrawable();
245 if (thumbDrawable != null) {
246 thumbDrawable.setDither(true);
247 } else {
248 Log.e(TAG, "Error decoding thumbnail resId=" + thumbRes + " for wallpaper #"
249 + position);
250 }
251
Adam Cohena6612cd2010-12-21 17:34:25 -0800252 return view;
Adam Lesinski2a898a02010-12-09 21:04:15 -0800253 }
254 }
255
256 class WallpaperLoader extends AsyncTask<Integer, Void, Bitmap> {
257 BitmapFactory.Options mOptions;
258
259 WallpaperLoader() {
260 mOptions = new BitmapFactory.Options();
261 mOptions.inDither = false;
262 mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
263 }
264
265 @Override
266 protected Bitmap doInBackground(Integer... params) {
267 if (isCancelled()) return null;
268 try {
269 return BitmapFactory.decodeResource(getResources(),
270 mImages.get(params[0]), mOptions);
271 } catch (OutOfMemoryError e) {
272 return null;
273 }
274 }
275
276 @Override
277 protected void onPostExecute(Bitmap b) {
278 if (b == null) return;
279
280 if (!isCancelled() && !mOptions.mCancel) {
281 // Help the GC
282 if (mBitmap != null) {
283 mBitmap.recycle();
284 }
285
Winson Chungf8742be2011-08-22 16:19:31 -0700286 View v = getView();
287 if (v != null) {
288 mBitmap = b;
289 mWallpaperDrawable.setBitmap(b);
290 v.postInvalidate();
291 } else {
292 mBitmap = null;
293 mWallpaperDrawable.setBitmap(null);
294 }
Adam Lesinski2a898a02010-12-09 21:04:15 -0800295 mLoader = null;
296 } else {
297 b.recycle();
298 }
299 }
300
301 void cancel() {
302 mOptions.requestCancelDecode();
303 super.cancel(true);
304 }
305 }
Amith Yamasani6be59492011-06-21 13:03:34 -0700306
307 /**
308 * Custom drawable that centers the bitmap fed to it.
309 */
310 static class WallpaperDrawable extends Drawable {
311
312 Bitmap mBitmap;
313 int mIntrinsicWidth;
314 int mIntrinsicHeight;
315
316 /* package */void setBitmap(Bitmap bitmap) {
317 mBitmap = bitmap;
318 if (mBitmap == null)
319 return;
320 mIntrinsicWidth = mBitmap.getWidth();
321 mIntrinsicHeight = mBitmap.getHeight();
322 }
323
324 @Override
325 public void draw(Canvas canvas) {
326 if (mBitmap == null) return;
327 int width = canvas.getWidth();
328 int height = canvas.getHeight();
329 int x = (width - mIntrinsicWidth) / 2;
330 int y = (height - mIntrinsicHeight) / 2;
331 canvas.drawBitmap(mBitmap, x, y, null);
332 }
333
334 @Override
335 public int getOpacity() {
336 return android.graphics.PixelFormat.OPAQUE;
337 }
338
339 @Override
340 public void setAlpha(int alpha) {
341 // Ignore
342 }
343
344 @Override
345 public void setColorFilter(ColorFilter cf) {
346 // Ignore
347 }
348 }
Andrew Flynn79b79dd2012-02-24 09:32:33 -0800349}