blob: 99de815f9a3a37ab9aae7bf3254397ab2ab0ce59 [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 */
Daniel Sandler325dc232013-06-05 22:57:57 -040016package com.android.launcher3;
Adam Lesinski2a898a02010-12-09 21:04:15 -080017
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
Daniel Sandler325dc232013-06-05 22:57:57 -040044import com.android.launcher3.R;
Amith Yamasani6be59492011-06-21 13:03:34 -070045
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";
Daniel Sandler325dc232013-06-05 22:57:57 -040053 private static final String EMBEDDED_KEY = "com.android.launcher3."
Adam Lesinski2a898a02010-12-09 21:04:15 -080054 + "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
Winson Chung97ea93e2012-03-23 16:34:59 -070085 private void cancelLoader() {
Adam Lesinski2a898a02010-12-09 21:04:15 -080086 if (mLoader != null && mLoader.getStatus() != WallpaperLoader.Status.FINISHED) {
87 mLoader.cancel(true);
88 mLoader = null;
89 }
90 }
91
92 @Override
Winson Chung97ea93e2012-03-23 16:34:59 -070093 public void onDetach() {
94 super.onDetach();
95
96 cancelLoader();
97 }
98
99 @Override
100 public void onDestroy() {
101 super.onDestroy();
102
103 cancelLoader();
104 }
105
106 @Override
Adam Lesinski2a898a02010-12-09 21:04:15 -0800107 public void onDismiss(DialogInterface dialog) {
108 super.onDismiss(dialog);
109 /* On orientation changes, the dialog is effectively "dismissed" so this is called
110 * when the activity is no longer associated with this dying dialog fragment. We
111 * should just safely ignore this case by checking if getActivity() returns null
112 */
113 Activity activity = getActivity();
114 if (activity != null) {
115 activity.finish();
116 }
117 }
118
119 /* This will only be called when in XLarge mode, since this Fragment is invoked like
120 * a dialog in that mode
121 */
122 @Override
123 public Dialog onCreateDialog(Bundle savedInstanceState) {
Winson Chung3b7d86d2011-01-26 11:03:32 -0800124 findWallpapers();
125
Amith Yamasani6be59492011-06-21 13:03:34 -0700126 return null;
Adam Lesinski2a898a02010-12-09 21:04:15 -0800127 }
128
129 @Override
130 public View onCreateView(LayoutInflater inflater, ViewGroup container,
131 Bundle savedInstanceState) {
132 findWallpapers();
133
134 /* If this fragment is embedded in the layout of this activity, then we should
135 * generate a view to display. Otherwise, a dialog will be created in
136 * onCreateDialog()
137 */
138 if (mEmbedded) {
139 View view = inflater.inflate(R.layout.wallpaper_chooser, container, false);
Michael Jurka3a9fced2012-04-13 14:44:29 -0700140 view.setBackground(mWallpaperDrawable);
Adam Lesinski2a898a02010-12-09 21:04:15 -0800141
142 final Gallery gallery = (Gallery) view.findViewById(R.id.gallery);
143 gallery.setCallbackDuringFling(false);
144 gallery.setOnItemSelectedListener(this);
145 gallery.setAdapter(new ImageAdapter(getActivity()));
146
147 View setButton = view.findViewById(R.id.set);
148 setButton.setOnClickListener(new OnClickListener() {
149 @Override
150 public void onClick(View v) {
151 selectWallpaper(gallery.getSelectedItemPosition());
152 }
153 });
Adam Lesinski2a898a02010-12-09 21:04:15 -0800154 return view;
155 }
156 return null;
157 }
158
159 private void selectWallpaper(int position) {
160 try {
161 WallpaperManager wpm = (WallpaperManager) getActivity().getSystemService(
162 Context.WALLPAPER_SERVICE);
163 wpm.setResource(mImages.get(position));
164 Activity activity = getActivity();
165 activity.setResult(Activity.RESULT_OK);
166 activity.finish();
167 } catch (IOException e) {
168 Log.e(TAG, "Failed to set wallpaper: " + e);
169 }
170 }
171
172 // Click handler for the Dialog's GridView
173 @Override
174 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
175 selectWallpaper(position);
176 }
177
178 // Selection handler for the embedded Gallery view
179 @Override
180 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
181 if (mLoader != null && mLoader.getStatus() != WallpaperLoader.Status.FINISHED) {
182 mLoader.cancel();
183 }
184 mLoader = (WallpaperLoader) new WallpaperLoader().execute(position);
185 }
186
187 @Override
188 public void onNothingSelected(AdapterView<?> parent) {
189 }
190
191 private void findWallpapers() {
192 mThumbs = new ArrayList<Integer>(24);
193 mImages = new ArrayList<Integer>(24);
194
195 final Resources resources = getResources();
196 // Context.getPackageName() may return the "original" package name,
Daniel Sandler325dc232013-06-05 22:57:57 -0400197 // com.android.launcher3; Resources needs the real package name,
198 // com.android.launcher3. So we ask Resources for what it thinks the
Adam Lesinski2a898a02010-12-09 21:04:15 -0800199 // package name should be.
200 final String packageName = resources.getResourcePackageName(R.array.wallpapers);
201
202 addWallpapers(resources, packageName, R.array.wallpapers);
203 addWallpapers(resources, packageName, R.array.extra_wallpapers);
204 }
205
206 private void addWallpapers(Resources resources, String packageName, int list) {
207 final String[] extras = resources.getStringArray(list);
208 for (String extra : extras) {
209 int res = resources.getIdentifier(extra, "drawable", packageName);
210 if (res != 0) {
211 final int thumbRes = resources.getIdentifier(extra + "_small",
212 "drawable", packageName);
213
214 if (thumbRes != 0) {
215 mThumbs.add(thumbRes);
216 mImages.add(res);
217 // Log.d(TAG, "add: [" + packageName + "]: " + extra + " (" + res + ")");
218 }
219 }
220 }
221 }
222
223 private class ImageAdapter extends BaseAdapter implements ListAdapter, SpinnerAdapter {
224 private LayoutInflater mLayoutInflater;
225
226 ImageAdapter(Activity activity) {
227 mLayoutInflater = activity.getLayoutInflater();
228 }
229
230 public int getCount() {
231 return mThumbs.size();
232 }
233
234 public Object getItem(int position) {
235 return position;
236 }
237
238 public long getItemId(int position) {
239 return position;
240 }
241
242 public View getView(int position, View convertView, ViewGroup parent) {
Adam Cohena6612cd2010-12-21 17:34:25 -0800243 View view;
Adam Lesinski2a898a02010-12-09 21:04:15 -0800244
245 if (convertView == null) {
Adam Cohena6612cd2010-12-21 17:34:25 -0800246 view = mLayoutInflater.inflate(R.layout.wallpaper_item, parent, false);
Adam Lesinski2a898a02010-12-09 21:04:15 -0800247 } else {
Adam Cohena6612cd2010-12-21 17:34:25 -0800248 view = convertView;
Adam Lesinski2a898a02010-12-09 21:04:15 -0800249 }
250
Adam Cohena6612cd2010-12-21 17:34:25 -0800251 ImageView image = (ImageView) view.findViewById(R.id.wallpaper_image);
252
Adam Lesinski2a898a02010-12-09 21:04:15 -0800253 int thumbRes = mThumbs.get(position);
254 image.setImageResource(thumbRes);
255 Drawable thumbDrawable = image.getDrawable();
256 if (thumbDrawable != null) {
257 thumbDrawable.setDither(true);
258 } else {
259 Log.e(TAG, "Error decoding thumbnail resId=" + thumbRes + " for wallpaper #"
260 + position);
261 }
262
Adam Cohena6612cd2010-12-21 17:34:25 -0800263 return view;
Adam Lesinski2a898a02010-12-09 21:04:15 -0800264 }
265 }
266
267 class WallpaperLoader extends AsyncTask<Integer, Void, Bitmap> {
268 BitmapFactory.Options mOptions;
269
270 WallpaperLoader() {
271 mOptions = new BitmapFactory.Options();
272 mOptions.inDither = false;
273 mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
274 }
275
276 @Override
277 protected Bitmap doInBackground(Integer... params) {
278 if (isCancelled()) return null;
279 try {
280 return BitmapFactory.decodeResource(getResources(),
281 mImages.get(params[0]), mOptions);
282 } catch (OutOfMemoryError e) {
283 return null;
284 }
285 }
286
287 @Override
288 protected void onPostExecute(Bitmap b) {
289 if (b == null) return;
290
291 if (!isCancelled() && !mOptions.mCancel) {
292 // Help the GC
293 if (mBitmap != null) {
294 mBitmap.recycle();
295 }
296
Winson Chungf8742be2011-08-22 16:19:31 -0700297 View v = getView();
298 if (v != null) {
299 mBitmap = b;
300 mWallpaperDrawable.setBitmap(b);
301 v.postInvalidate();
302 } else {
303 mBitmap = null;
304 mWallpaperDrawable.setBitmap(null);
305 }
Adam Lesinski2a898a02010-12-09 21:04:15 -0800306 mLoader = null;
307 } else {
308 b.recycle();
309 }
310 }
311
312 void cancel() {
313 mOptions.requestCancelDecode();
314 super.cancel(true);
315 }
316 }
Amith Yamasani6be59492011-06-21 13:03:34 -0700317
318 /**
319 * Custom drawable that centers the bitmap fed to it.
320 */
321 static class WallpaperDrawable extends Drawable {
322
323 Bitmap mBitmap;
324 int mIntrinsicWidth;
325 int mIntrinsicHeight;
326
327 /* package */void setBitmap(Bitmap bitmap) {
328 mBitmap = bitmap;
329 if (mBitmap == null)
330 return;
331 mIntrinsicWidth = mBitmap.getWidth();
332 mIntrinsicHeight = mBitmap.getHeight();
333 }
334
335 @Override
336 public void draw(Canvas canvas) {
337 if (mBitmap == null) return;
338 int width = canvas.getWidth();
339 int height = canvas.getHeight();
340 int x = (width - mIntrinsicWidth) / 2;
341 int y = (height - mIntrinsicHeight) / 2;
342 canvas.drawBitmap(mBitmap, x, y, null);
343 }
344
345 @Override
346 public int getOpacity() {
347 return android.graphics.PixelFormat.OPAQUE;
348 }
349
350 @Override
351 public void setAlpha(int alpha) {
352 // Ignore
353 }
354
355 @Override
356 public void setColorFilter(ColorFilter cf) {
357 // Ignore
358 }
359 }
Andrew Flynn79b79dd2012-02-24 09:32:33 -0800360}