blob: c9e21f2dadf7c6ae4d4cba90e4711682f5aca1f3 [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;
19import android.app.AlertDialog;
20import android.app.Dialog;
21import android.app.DialogFragment;
22import android.app.WallpaperManager;
23import android.content.Context;
24import android.content.DialogInterface;
25import android.content.res.Resources;
26import android.graphics.Bitmap;
27import android.graphics.BitmapFactory;
Amith Yamasani6be59492011-06-21 13:03:34 -070028import android.graphics.Canvas;
29import android.graphics.ColorFilter;
30import android.graphics.Paint;
Adam Lesinski2a898a02010-12-09 21:04:15 -080031import android.graphics.drawable.Drawable;
32import android.os.AsyncTask;
33import android.os.Bundle;
34import android.util.Log;
35import android.view.LayoutInflater;
36import android.view.View;
Adam Lesinski2a898a02010-12-09 21:04:15 -080037import android.view.ViewGroup;
Amith Yamasani6be59492011-06-21 13:03:34 -070038import android.view.View.OnClickListener;
Adam Lesinski2a898a02010-12-09 21:04:15 -080039import android.widget.AdapterView;
40import android.widget.BaseAdapter;
Adam Cohena6612cd2010-12-21 17:34:25 -080041import android.widget.FrameLayout;
Adam Lesinski2a898a02010-12-09 21:04:15 -080042import android.widget.Gallery;
43import android.widget.GridView;
44import android.widget.ImageView;
45import android.widget.ListAdapter;
46import android.widget.SpinnerAdapter;
47
Amith Yamasani6be59492011-06-21 13:03:34 -070048import com.android.launcher.R;
49
Adam Lesinski2a898a02010-12-09 21:04:15 -080050import java.io.IOException;
51import java.util.ArrayList;
52
53public 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;
Adam Lesinski2a898a02010-12-09 21:04:15 -080061 private Bitmap mBitmap = null;
62
63 private ArrayList<Integer> mThumbs;
64 private ArrayList<Integer> mImages;
65 private WallpaperLoader mLoader;
Amith Yamasani6be59492011-06-21 13:03:34 -070066 private WallpaperDrawable mWallpaperDrawable = new WallpaperDrawable();
Adam Lesinski2a898a02010-12-09 21:04:15 -080067
68 public static WallpaperChooserDialogFragment newInstance() {
69 WallpaperChooserDialogFragment fragment = new WallpaperChooserDialogFragment();
70 fragment.setCancelable(true);
71 return fragment;
72 }
73
74 @Override
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
85 public void onSaveInstanceState(Bundle outState) {
86 outState.putBoolean(EMBEDDED_KEY, mEmbedded);
87 }
88
89 @Override
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
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
116 public Dialog onCreateDialog(Bundle savedInstanceState) {
Winson Chung3b7d86d2011-01-26 11:03:32 -0800117 findWallpapers();
118
Amith Yamasani6be59492011-06-21 13:03:34 -0700119 // TODO: The following code is not exercised right now and may be removed
120 // if the dialog version is not needed.
121 /*
Adam Lesinski2a898a02010-12-09 21:04:15 -0800122 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);
Amith Yamasani6be59492011-06-21 13:03:34 -0700131
Adam Cohena6612cd2010-12-21 17:34:25 -0800132 FrameLayout wallPaperList = (FrameLayout) v.findViewById(R.id.wallpaper_list);
Adam Lesinski2a898a02010-12-09 21:04:15 -0800133 AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
134 builder.setNegativeButton(R.string.wallpaper_cancel, null);
135 builder.setTitle(R.string.wallpaper_dialog_title);
Amith Yamasani6be59492011-06-21 13:03:34 -0700136 builder.setView(wallPaperList,
137 viewInset, viewInset, viewInset, viewInset); return builder.create();
138 */
139 return null;
Adam Lesinski2a898a02010-12-09 21:04:15 -0800140 }
141
142 @Override
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);
Amith Yamasani6be59492011-06-21 13:03:34 -0700153 view.setBackgroundDrawable(mWallpaperDrawable);
Adam Lesinski2a898a02010-12-09 21:04:15 -0800154
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 });
Adam Lesinski2a898a02010-12-09 21:04:15 -0800167 return view;
168 }
169 return null;
170 }
171
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
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
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
201 public void onNothingSelected(AdapterView<?> parent) {
202 }
203
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
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
239 ImageAdapter(Activity activity) {
240 mLayoutInflater = activity.getLayoutInflater();
241 }
242
243 public int getCount() {
244 return mThumbs.size();
245 }
246
247 public Object getItem(int position) {
248 return position;
249 }
250
251 public long getItemId(int position) {
252 return position;
253 }
254
255 public View getView(int position, View convertView, ViewGroup parent) {
Adam Cohena6612cd2010-12-21 17:34:25 -0800256 View view;
Adam Lesinski2a898a02010-12-09 21:04:15 -0800257
258 if (convertView == null) {
Adam Cohena6612cd2010-12-21 17:34:25 -0800259 view = mLayoutInflater.inflate(R.layout.wallpaper_item, parent, false);
Adam Lesinski2a898a02010-12-09 21:04:15 -0800260 } else {
Adam Cohena6612cd2010-12-21 17:34:25 -0800261 view = convertView;
Adam Lesinski2a898a02010-12-09 21:04:15 -0800262 }
263
Adam Cohena6612cd2010-12-21 17:34:25 -0800264 ImageView image = (ImageView) view.findViewById(R.id.wallpaper_image);
265
Adam Lesinski2a898a02010-12-09 21:04:15 -0800266 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
Adam Cohena6612cd2010-12-21 17:34:25 -0800276 return view;
Adam Lesinski2a898a02010-12-09 21:04:15 -0800277 }
278 }
279
280 class WallpaperLoader extends AsyncTask<Integer, Void, Bitmap> {
281 BitmapFactory.Options mOptions;
282
283 WallpaperLoader() {
284 mOptions = new BitmapFactory.Options();
285 mOptions.inDither = false;
286 mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
287 }
288
289 @Override
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
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
Amith Yamasani6be59492011-06-21 13:03:34 -0700310 mBitmap = b;
311 mWallpaperDrawable.setBitmap(b);
312 getView().postInvalidate();
Adam Lesinski2a898a02010-12-09 21:04:15 -0800313 mLoader = null;
314 } else {
315 b.recycle();
316 }
317 }
318
319 void cancel() {
320 mOptions.requestCancelDecode();
321 super.cancel(true);
322 }
323 }
Amith Yamasani6be59492011-06-21 13:03:34 -0700324
325 /**
326 * Custom drawable that centers the bitmap fed to it.
327 */
328 static class WallpaperDrawable extends Drawable {
329
330 Bitmap mBitmap;
331 int mIntrinsicWidth;
332 int mIntrinsicHeight;
333
334 /* package */void setBitmap(Bitmap bitmap) {
335 mBitmap = bitmap;
336 if (mBitmap == null)
337 return;
338 mIntrinsicWidth = mBitmap.getWidth();
339 mIntrinsicHeight = mBitmap.getHeight();
340 }
341
342 @Override
343 public void draw(Canvas canvas) {
344 if (mBitmap == null) return;
345 int width = canvas.getWidth();
346 int height = canvas.getHeight();
347 int x = (width - mIntrinsicWidth) / 2;
348 int y = (height - mIntrinsicHeight) / 2;
349 canvas.drawBitmap(mBitmap, x, y, null);
350 }
351
352 @Override
353 public int getOpacity() {
354 return android.graphics.PixelFormat.OPAQUE;
355 }
356
357 @Override
358 public void setAlpha(int alpha) {
359 // Ignore
360 }
361
362 @Override
363 public void setColorFilter(ColorFilter cf) {
364 // Ignore
365 }
366 }
Adam Lesinski2a898a02010-12-09 21:04:15 -0800367}