blob: 61945cc37225e7aaafc53f2bd71fc5c75f42245c [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;
Dan Sandlere6851f52014-08-15 11:25:16 -040029import android.graphics.Matrix;
Dan Sandler2711d072014-08-20 00:33:46 -040030import android.graphics.drawable.BitmapDrawable;
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;
Amith Yamasani6be59492011-06-21 13:03:34 -070037import android.view.View.OnClickListener;
Michael Jurka92f3d462011-11-22 21:02:29 -080038import android.view.ViewGroup;
Adam Lesinski2a898a02010-12-09 21:04:15 -080039import android.widget.AdapterView;
40import android.widget.BaseAdapter;
41import android.widget.Gallery;
Adam Lesinski2a898a02010-12-09 21:04:15 -080042import android.widget.ImageView;
43import android.widget.ListAdapter;
44import android.widget.SpinnerAdapter;
45
Amith Yamasani6be59492011-06-21 13:03:34 -070046import com.android.launcher.R;
47
Adam Lesinski2a898a02010-12-09 21:04:15 -080048import java.io.IOException;
49import java.util.ArrayList;
50
51public class WallpaperChooserDialogFragment extends DialogFragment implements
52 AdapterView.OnItemSelectedListener, AdapterView.OnItemClickListener {
53
54 private static final String TAG = "Launcher.WallpaperChooserDialogFragment";
55 private static final String EMBEDDED_KEY = "com.android.launcher2."
56 + "WallpaperChooserDialogFragment.EMBEDDED_KEY";
57
58 private boolean mEmbedded;
Adam Lesinski2a898a02010-12-09 21:04:15 -080059
60 private ArrayList<Integer> mThumbs;
61 private ArrayList<Integer> mImages;
62 private WallpaperLoader mLoader;
Amith Yamasani6be59492011-06-21 13:03:34 -070063 private WallpaperDrawable mWallpaperDrawable = new WallpaperDrawable();
Adam Lesinski2a898a02010-12-09 21:04:15 -080064
65 public static WallpaperChooserDialogFragment newInstance() {
66 WallpaperChooserDialogFragment fragment = new WallpaperChooserDialogFragment();
67 fragment.setCancelable(true);
68 return fragment;
69 }
70
71 @Override
72 public void onCreate(Bundle savedInstanceState) {
73 super.onCreate(savedInstanceState);
74 if (savedInstanceState != null && savedInstanceState.containsKey(EMBEDDED_KEY)) {
75 mEmbedded = savedInstanceState.getBoolean(EMBEDDED_KEY);
76 } else {
77 mEmbedded = isInLayout();
78 }
79 }
80
81 @Override
82 public void onSaveInstanceState(Bundle outState) {
83 outState.putBoolean(EMBEDDED_KEY, mEmbedded);
84 }
85
Winson Chung97ea93e2012-03-23 16:34:59 -070086 private void cancelLoader() {
Adam Lesinski2a898a02010-12-09 21:04:15 -080087 if (mLoader != null && mLoader.getStatus() != WallpaperLoader.Status.FINISHED) {
88 mLoader.cancel(true);
89 mLoader = null;
90 }
91 }
92
93 @Override
Winson Chung97ea93e2012-03-23 16:34:59 -070094 public void onDetach() {
95 super.onDetach();
96
97 cancelLoader();
98 }
99
100 @Override
101 public void onDestroy() {
102 super.onDestroy();
103
104 cancelLoader();
105 }
106
107 @Override
Adam Lesinski2a898a02010-12-09 21:04:15 -0800108 public void onDismiss(DialogInterface dialog) {
109 super.onDismiss(dialog);
110 /* On orientation changes, the dialog is effectively "dismissed" so this is called
111 * when the activity is no longer associated with this dying dialog fragment. We
112 * should just safely ignore this case by checking if getActivity() returns null
113 */
114 Activity activity = getActivity();
115 if (activity != null) {
116 activity.finish();
117 }
118 }
119
120 /* This will only be called when in XLarge mode, since this Fragment is invoked like
121 * a dialog in that mode
122 */
123 @Override
124 public Dialog onCreateDialog(Bundle savedInstanceState) {
Winson Chung3b7d86d2011-01-26 11:03:32 -0800125 findWallpapers();
126
Amith Yamasani6be59492011-06-21 13:03:34 -0700127 return null;
Adam Lesinski2a898a02010-12-09 21:04:15 -0800128 }
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);
Michael Jurka3a9fced2012-04-13 14:44:29 -0700141 view.setBackground(mWallpaperDrawable);
Adam Lesinski2a898a02010-12-09 21:04:15 -0800142
143 final Gallery gallery = (Gallery) view.findViewById(R.id.gallery);
144 gallery.setCallbackDuringFling(false);
145 gallery.setOnItemSelectedListener(this);
146 gallery.setAdapter(new ImageAdapter(getActivity()));
147
148 View setButton = view.findViewById(R.id.set);
149 setButton.setOnClickListener(new OnClickListener() {
150 @Override
151 public void onClick(View v) {
152 selectWallpaper(gallery.getSelectedItemPosition());
153 }
154 });
Adam Lesinski2a898a02010-12-09 21:04:15 -0800155 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) {
Adam Cohena6612cd2010-12-21 17:34:25 -0800244 View view;
Adam Lesinski2a898a02010-12-09 21:04:15 -0800245
246 if (convertView == null) {
Adam Cohena6612cd2010-12-21 17:34:25 -0800247 view = mLayoutInflater.inflate(R.layout.wallpaper_item, parent, false);
Adam Lesinski2a898a02010-12-09 21:04:15 -0800248 } else {
Adam Cohena6612cd2010-12-21 17:34:25 -0800249 view = convertView;
Adam Lesinski2a898a02010-12-09 21:04:15 -0800250 }
251
Adam Cohena6612cd2010-12-21 17:34:25 -0800252 ImageView image = (ImageView) view.findViewById(R.id.wallpaper_image);
253
Adam Lesinski2a898a02010-12-09 21:04:15 -0800254 int thumbRes = mThumbs.get(position);
255 image.setImageResource(thumbRes);
256 Drawable thumbDrawable = image.getDrawable();
257 if (thumbDrawable != null) {
258 thumbDrawable.setDither(true);
259 } else {
260 Log.e(TAG, "Error decoding thumbnail resId=" + thumbRes + " for wallpaper #"
261 + position);
262 }
263
Adam Cohena6612cd2010-12-21 17:34:25 -0800264 return view;
Adam Lesinski2a898a02010-12-09 21:04:15 -0800265 }
266 }
267
268 class WallpaperLoader extends AsyncTask<Integer, Void, Bitmap> {
Adam Lesinski2a898a02010-12-09 21:04:15 -0800269 WallpaperLoader() {
Adam Lesinski2a898a02010-12-09 21:04:15 -0800270 }
271
272 @Override
273 protected Bitmap doInBackground(Integer... params) {
274 if (isCancelled()) return null;
275 try {
Dan Sandler2711d072014-08-20 00:33:46 -0400276 final Drawable d = getResources().getDrawable(mImages.get(params[0]));
277 if (d instanceof BitmapDrawable) {
278 return ((BitmapDrawable)d).getBitmap();
279 }
280 return null;
Adam Lesinski2a898a02010-12-09 21:04:15 -0800281 } catch (OutOfMemoryError e) {
Dan Sandler2711d072014-08-20 00:33:46 -0400282 Log.w(TAG, String.format(
283 "Out of memory trying to load wallpaper res=%08x", params[0]),
284 e);
Adam Lesinski2a898a02010-12-09 21:04:15 -0800285 return null;
286 }
287 }
288
289 @Override
290 protected void onPostExecute(Bitmap b) {
291 if (b == null) return;
292
Dan Sandler2711d072014-08-20 00:33:46 -0400293 if (!isCancelled()) {
Winson Chungf8742be2011-08-22 16:19:31 -0700294 View v = getView();
295 if (v != null) {
Winson Chungf8742be2011-08-22 16:19:31 -0700296 mWallpaperDrawable.setBitmap(b);
297 v.postInvalidate();
298 } else {
Winson Chungf8742be2011-08-22 16:19:31 -0700299 mWallpaperDrawable.setBitmap(null);
300 }
Adam Lesinski2a898a02010-12-09 21:04:15 -0800301 mLoader = null;
302 } else {
303 b.recycle();
304 }
305 }
306
307 void cancel() {
Adam Lesinski2a898a02010-12-09 21:04:15 -0800308 super.cancel(true);
309 }
310 }
Amith Yamasani6be59492011-06-21 13:03:34 -0700311
312 /**
313 * Custom drawable that centers the bitmap fed to it.
314 */
315 static class WallpaperDrawable extends Drawable {
316
317 Bitmap mBitmap;
318 int mIntrinsicWidth;
319 int mIntrinsicHeight;
Dan Sandlere6851f52014-08-15 11:25:16 -0400320 Matrix mMatrix;
Amith Yamasani6be59492011-06-21 13:03:34 -0700321
322 /* package */void setBitmap(Bitmap bitmap) {
323 mBitmap = bitmap;
324 if (mBitmap == null)
325 return;
326 mIntrinsicWidth = mBitmap.getWidth();
327 mIntrinsicHeight = mBitmap.getHeight();
Dan Sandlere6851f52014-08-15 11:25:16 -0400328 mMatrix = null;
Amith Yamasani6be59492011-06-21 13:03:34 -0700329 }
330
331 @Override
332 public void draw(Canvas canvas) {
333 if (mBitmap == null) return;
Dan Sandlere6851f52014-08-15 11:25:16 -0400334
335 if (mMatrix == null) {
336 final int vwidth = canvas.getWidth();
337 final int vheight = canvas.getHeight();
338 final int dwidth = mIntrinsicWidth;
339 final int dheight = mIntrinsicHeight;
340
341 float scale = 1.0f;
342
343 if (dwidth < vwidth || dheight < vheight) {
344 scale = Math.max((float) vwidth / (float) dwidth,
345 (float) vheight / (float) dheight);
346 }
347
348 float dx = (vwidth - dwidth * scale) * 0.5f + 0.5f;
349 float dy = (vheight - dheight * scale) * 0.5f + 0.5f;
350
351 mMatrix = new Matrix();
352 mMatrix.setScale(scale, scale);
353 mMatrix.postTranslate((int) dx, (int) dy);
354 }
355
356 canvas.drawBitmap(mBitmap, mMatrix, null);
Amith Yamasani6be59492011-06-21 13:03:34 -0700357 }
358
359 @Override
360 public int getOpacity() {
361 return android.graphics.PixelFormat.OPAQUE;
362 }
363
364 @Override
365 public void setAlpha(int alpha) {
366 // Ignore
367 }
368
369 @Override
370 public void setColorFilter(ColorFilter cf) {
371 // Ignore
372 }
373 }
Andrew Flynn79b79dd2012-02-24 09:32:33 -0800374}