blob: 113a8e66394e057e99068fc225346fbcf60a85a0 [file] [log] [blame]
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001/*
2 * Copyright (C) 2008 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 */
16
Joe Onoratoa5902522009-07-30 13:37:37 -070017package com.android.launcher2;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080018
19import android.app.Activity;
Adam Lesinskicd5d8072010-11-19 15:06:46 -080020import android.app.AlertDialog;
21import android.app.Dialog;
22import android.app.DialogFragment;
23import android.app.FragmentTransaction;
Dianne Hackborn107f8392009-08-05 21:32:16 -070024import android.app.WallpaperManager;
Adam Lesinskicd5d8072010-11-19 15:06:46 -080025import android.content.Context;
26import android.content.DialogInterface;
Joe Onorato1b126452009-07-28 18:26:47 -070027import android.content.res.Resources;
28import android.graphics.BitmapFactory;
29import android.graphics.Bitmap;
30import android.graphics.drawable.Drawable;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080031import android.os.Bundle;
Romain Guy8c724f52009-09-14 15:18:12 -070032import android.os.AsyncTask;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080033import android.util.Log;
34import android.view.LayoutInflater;
35import android.view.View;
36import android.view.ViewGroup;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080037import android.view.View.OnClickListener;
38import android.widget.AdapterView;
39import android.widget.BaseAdapter;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080040import android.widget.Gallery;
Adam Lesinskicd5d8072010-11-19 15:06:46 -080041import android.widget.GridView;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080042import android.widget.ImageView;
Adam Lesinskicd5d8072010-11-19 15:06:46 -080043import android.widget.ListAdapter;
44import android.widget.SpinnerAdapter;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080045
46import java.io.IOException;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080047import java.util.ArrayList;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080048
Romain Guyedcce092010-03-04 13:03:17 -080049import com.android.launcher.R;
50
Adam Lesinskicd5d8072010-11-19 15:06:46 -080051public class WallpaperChooser extends Activity {
Joe Onoratoa30ce8e2009-11-11 08:16:49 -080052 private static final String TAG = "Launcher.WallpaperChooser";
The Android Open Source Project31dd5032009-03-03 19:32:27 -080053
Adam Lesinskicd5d8072010-11-19 15:06:46 -080054 private ViewGroup mWallpaperChooserBase;
55 private ImageView mImageView = null;
56 private Bitmap mBitmap = null;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080057
58 private ArrayList<Integer> mThumbs;
59 private ArrayList<Integer> mImages;
Romain Guye82140f2009-09-16 16:54:21 -070060 private WallpaperLoader mLoader;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080061
62 @Override
63 public void onCreate(Bundle icicle) {
64 super.onCreate(icicle);
Adam Lesinskicd5d8072010-11-19 15:06:46 -080065 /* We need some container to attach to in order for the fragment to be
66 * considered embedded, so inflate an empty FrameLayout and use that
67 * as the parent view
68 */
69 setContentView(R.layout.wallpaper_chooser_base);
70 mWallpaperChooserBase = (ViewGroup) findViewById(R.id.wallpaper_chooser_base);
The Android Open Source Project31dd5032009-03-03 19:32:27 -080071
72 findWallpapers();
73
Adam Lesinskicd5d8072010-11-19 15:06:46 -080074 DialogFragment newFragment = new WallpaperDialogFragment(this);
75 if (LauncherApplication.isScreenXLarge()) {
76 // Display a dialog instead of embedding the view in the activity
77 newFragment.show(getFragmentManager(), "dialog");
78 } else {
79 // Embed the fragment in the base view
80 FragmentTransaction ft = getFragmentManager().openTransaction();
81 ft.add(R.id.wallpaper_chooser_base, newFragment);
82 ft.commit();
83 }
84 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -080085
Adam Lesinskicd5d8072010-11-19 15:06:46 -080086 @Override
87 protected void onDestroy() {
88 super.onDestroy();
The Android Open Source Project31dd5032009-03-03 19:32:27 -080089
Adam Lesinskicd5d8072010-11-19 15:06:46 -080090 if (mLoader != null && mLoader.getStatus() != WallpaperLoader.Status.FINISHED) {
91 mLoader.cancel(true);
92 mLoader = null;
93 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -080094 }
95
96 private void findWallpapers() {
Romain Guy8eb50952009-09-02 15:57:21 -070097 mThumbs = new ArrayList<Integer>(24);
98 mImages = new ArrayList<Integer>(24);
The Android Open Source Project31dd5032009-03-03 19:32:27 -080099
100 final Resources resources = getResources();
Daniel Sandler76c0e142010-03-05 11:04:10 -0500101 // Context.getPackageName() may return the "original" package name,
102 // com.android.launcher2; Resources needs the real package name,
103 // com.android.launcher. So we ask Resources for what it thinks the
104 // package name should be.
105 final String packageName = resources.getResourcePackageName(R.array.wallpapers);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800106
Romain Guy8eb50952009-09-02 15:57:21 -0700107 addWallpapers(resources, packageName, R.array.wallpapers);
108 addWallpapers(resources, packageName, R.array.extra_wallpapers);
109 }
110
111 private void addWallpapers(Resources resources, String packageName, int list) {
112 final String[] extras = resources.getStringArray(list);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800113 for (String extra : extras) {
114 int res = resources.getIdentifier(extra, "drawable", packageName);
115 if (res != 0) {
116 final int thumbRes = resources.getIdentifier(extra + "_small",
117 "drawable", packageName);
118
119 if (thumbRes != 0) {
120 mThumbs.add(thumbRes);
121 mImages.add(res);
Daniel Sandler76c0e142010-03-05 11:04:10 -0500122 // Log.d(TAG, "addWallpapers: [" + packageName + "]: " + extra + " (" + res + ")");
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800123 }
124 }
125 }
126 }
127
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800128 private void selectWallpaper(int position) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800129 try {
Romain Guy8eb50952009-09-02 15:57:21 -0700130 WallpaperManager wpm = (WallpaperManager)getSystemService(WALLPAPER_SERVICE);
Dianne Hackborn64271802009-08-08 20:54:24 -0700131 wpm.setResource(mImages.get(position));
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800132 setResult(RESULT_OK);
133 finish();
134 } catch (IOException e) {
Joe Onoratoa30ce8e2009-11-11 08:16:49 -0800135 Log.e(TAG, "Failed to set wallpaper: " + e);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800136 }
137 }
138
Adam Lesinskicd5d8072010-11-19 15:06:46 -0800139 private class WallpaperDialogFragment extends DialogFragment implements
140 AdapterView.OnItemSelectedListener, AdapterView.OnItemClickListener {
141 private Context mContext;
142
143 public WallpaperDialogFragment(Context context) {
144 super();
145 mContext = context;
146 setCancelable(true);
147 }
148
149 @Override
150 public void onDismiss(DialogInterface dialog) {
151 WallpaperChooser.this.finish();
152 }
153
154 /* This will only be called when in XLarge mode, since this Fragment is invoked like
155 * a dialog in that mode
156 */
157 @Override
158 public Dialog onCreateDialog(Bundle savedInstanceState) {
159 final View v = getLayoutInflater().inflate(
160 R.layout.wallpaper_chooser, mWallpaperChooserBase, false);
161
162 GridView gridView = (GridView) v.findViewById(R.id.gallery);
163 gridView.setOnItemClickListener(this);
164 gridView.setAdapter(new ImageAdapter(WallpaperChooser.this));
165
166 final int viewInset =
167 getResources().getDimensionPixelSize(R.dimen.alert_dialog_content_inset);
168
169 AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
170 builder.setCancelable(true);
171 builder.setNegativeButton(R.string.wallpaper_cancel, null);
172 builder.setTitle(R.string.pick_wallpaper);
173 builder.setView(gridView, viewInset, viewInset, viewInset, viewInset);
174 return builder.create();
175 }
176
177 /* This will be called on both XLarge and small screens, but since the dialog
178 * is already created on XLarge, we want to skip this view creation
179 */
180 @Override
181 public View onCreateView(LayoutInflater inflater, ViewGroup container,
182 Bundle savedInstanceState) {
183 /* Only generate a custom view if this fragment is being embedded in a view,
184 * i.e: on a small screen
185 */
186 if (!LauncherApplication.isScreenXLarge()) {
187 View view = inflater.inflate(R.layout.wallpaper_chooser, container, false);
188
189 final Gallery gallery = (Gallery) view.findViewById(R.id.gallery);
190 gallery.setCallbackDuringFling(false);
191 gallery.setOnItemSelectedListener(this);
192 gallery.setAdapter(new ImageAdapter(WallpaperChooser.this));
193
194 View setButton = view.findViewById(R.id.set);
195 setButton.setOnClickListener(new OnClickListener() {
196 @Override
197 public void onClick(View v) {
198 selectWallpaper(gallery.getSelectedItemPosition());
199 }
200 });
201 mImageView = (ImageView) view.findViewById(R.id.wallpaper);
202 return view;
203 }
204 return super.onCreateView(inflater, container, savedInstanceState);
205 }
206
207 // Click handler for the Dialog's GridView
208 @Override
209 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
210 selectWallpaper(position);
211 }
212
213 // Selection handler for the embedded Gallery view
214 @Override
215 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
216 if (mLoader != null && mLoader.getStatus() != WallpaperLoader.Status.FINISHED) {
217 mLoader.cancel();
218 }
219 mLoader = (WallpaperLoader) new WallpaperLoader().execute(position);
220 }
221
222 @Override
223 public void onNothingSelected(AdapterView<?> parent) {
224 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800225 }
226
Adam Lesinskicd5d8072010-11-19 15:06:46 -0800227 private class ImageAdapter extends BaseAdapter implements ListAdapter, SpinnerAdapter {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800228 private LayoutInflater mLayoutInflater;
229
230 ImageAdapter(WallpaperChooser context) {
231 mLayoutInflater = context.getLayoutInflater();
232 }
233
234 public int getCount() {
235 return mThumbs.size();
236 }
237
238 public Object getItem(int position) {
239 return position;
240 }
241
242 public long getItemId(int position) {
243 return position;
244 }
245
246 public View getView(int position, View convertView, ViewGroup parent) {
247 ImageView image;
248
249 if (convertView == null) {
250 image = (ImageView) mLayoutInflater.inflate(R.layout.wallpaper_item, parent, false);
251 } else {
252 image = (ImageView) convertView;
253 }
Adam Lesinskicd5d8072010-11-19 15:06:46 -0800254
Daniel Sandler1325f552009-09-21 15:13:31 -0400255 int thumbRes = mThumbs.get(position);
256 image.setImageResource(thumbRes);
257 Drawable thumbDrawable = image.getDrawable();
258 if (thumbDrawable != null) {
259 thumbDrawable.setDither(true);
260 } else {
Joe Onoratoa30ce8e2009-11-11 08:16:49 -0800261 Log.e(TAG, "Error decoding thumbnail resId=" + thumbRes + " for wallpaper #"
262 + position);
Daniel Sandler1325f552009-09-21 15:13:31 -0400263 }
Adam Lesinskicd5d8072010-11-19 15:06:46 -0800264
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800265 return image;
266 }
267 }
268
Romain Guy8c724f52009-09-14 15:18:12 -0700269 class WallpaperLoader extends AsyncTask<Integer, Void, Bitmap> {
Romain Guye82140f2009-09-16 16:54:21 -0700270 BitmapFactory.Options mOptions;
271
272 WallpaperLoader() {
273 mOptions = new BitmapFactory.Options();
274 mOptions.inDither = false;
275 mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
276 }
Adam Lesinskicd5d8072010-11-19 15:06:46 -0800277
278 @Override
Romain Guy8c724f52009-09-14 15:18:12 -0700279 protected Bitmap doInBackground(Integer... params) {
280 if (isCancelled()) return null;
Romain Guye82140f2009-09-16 16:54:21 -0700281 try {
282 return BitmapFactory.decodeResource(getResources(),
283 mImages.get(params[0]), mOptions);
284 } catch (OutOfMemoryError e) {
285 return null;
286 }
Romain Guy8c724f52009-09-14 15:18:12 -0700287 }
288
289 @Override
290 protected void onPostExecute(Bitmap b) {
291 if (b == null) return;
292
Romain Guye82140f2009-09-16 16:54:21 -0700293 if (!isCancelled() && !mOptions.mCancel) {
Romain Guy8c724f52009-09-14 15:18:12 -0700294 // Help the GC
295 if (mBitmap != null) {
296 mBitmap.recycle();
297 }
Romain Guy8c724f52009-09-14 15:18:12 -0700298
Adam Lesinskicd5d8072010-11-19 15:06:46 -0800299 // This should always be the case, but check anyways
300 final ImageView view = mImageView;
301 if (view != null) {
302 view.setImageBitmap(b);
303
304 mBitmap = b;
305
306 final Drawable drawable = view.getDrawable();
307 drawable.setFilterBitmap(true);
308 drawable.setDither(true);
309
310 view.postInvalidate();
311 }
Romain Guy4e55c772009-09-14 15:26:18 -0700312
313 mLoader = null;
314 } else {
315 b.recycle();
Romain Guy8c724f52009-09-14 15:18:12 -0700316 }
317 }
Romain Guye82140f2009-09-16 16:54:21 -0700318
319 void cancel() {
320 mOptions.requestCancelDecode();
321 super.cancel(true);
322 }
Romain Guy8c724f52009-09-14 15:18:12 -0700323 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800324}