• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 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 
17 package com.android.launcher3;
18 
19 import android.animation.LayoutTransition;
20 import android.annotation.TargetApi;
21 import android.app.ActionBar;
22 import android.app.Activity;
23 import android.app.WallpaperInfo;
24 import android.app.WallpaperManager;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.pm.ApplicationInfo;
28 import android.content.pm.PackageManager;
29 import android.content.res.Resources;
30 import android.database.Cursor;
31 import android.database.DataSetObserver;
32 import android.graphics.Bitmap;
33 import android.graphics.BitmapFactory;
34 import android.graphics.Canvas;
35 import android.graphics.Matrix;
36 import android.graphics.Point;
37 import android.graphics.PorterDuff;
38 import android.graphics.Rect;
39 import android.graphics.RectF;
40 import android.graphics.drawable.BitmapDrawable;
41 import android.graphics.drawable.Drawable;
42 import android.graphics.drawable.LevelListDrawable;
43 import android.net.Uri;
44 import android.os.AsyncTask;
45 import android.os.Build;
46 import android.os.Bundle;
47 import android.provider.MediaStore;
48 import android.util.Log;
49 import android.util.Pair;
50 import android.view.ActionMode;
51 import android.view.LayoutInflater;
52 import android.view.Menu;
53 import android.view.MenuInflater;
54 import android.view.MenuItem;
55 import android.view.View;
56 import android.view.View.OnClickListener;
57 import android.view.View.OnLayoutChangeListener;
58 import android.view.ViewGroup;
59 import android.view.ViewPropertyAnimator;
60 import android.view.ViewTreeObserver;
61 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
62 import android.view.WindowManager;
63 import android.view.animation.AccelerateInterpolator;
64 import android.view.animation.DecelerateInterpolator;
65 import android.widget.ArrayAdapter;
66 import android.widget.BaseAdapter;
67 import android.widget.FrameLayout;
68 import android.widget.HorizontalScrollView;
69 import android.widget.ImageView;
70 import android.widget.LinearLayout;
71 import android.widget.Toast;
72 
73 import com.android.photos.BitmapRegionTileSource;
74 import com.android.photos.BitmapRegionTileSource.BitmapSource;
75 
76 import java.io.File;
77 import java.io.FileOutputStream;
78 import java.io.IOException;
79 import java.util.ArrayList;
80 
81 public class WallpaperPickerActivity extends WallpaperCropActivity {
82     static final String TAG = "Launcher.WallpaperPickerActivity";
83 
84     public static final int IMAGE_PICK = 5;
85     public static final int PICK_WALLPAPER_THIRD_PARTY_ACTIVITY = 6;
86     public static final int PICK_LIVE_WALLPAPER = 7;
87     private static final String TEMP_WALLPAPER_TILES = "TEMP_WALLPAPER_TILES";
88     private static final String SELECTED_INDEX = "SELECTED_INDEX";
89     private static final String OLD_DEFAULT_WALLPAPER_THUMBNAIL_FILENAME = "default_thumb.jpg";
90     private static final String DEFAULT_WALLPAPER_THUMBNAIL_FILENAME = "default_thumb2.jpg";
91     private static final int FLAG_POST_DELAY_MILLIS = 200;
92 
93     private View mSelectedTile;
94     private boolean mIgnoreNextTap;
95     private OnClickListener mThumbnailOnClickListener;
96 
97     private LinearLayout mWallpapersView;
98     private View mWallpaperStrip;
99 
100     private ActionMode.Callback mActionModeCallback;
101     private ActionMode mActionMode;
102 
103     private View.OnLongClickListener mLongClickListener;
104 
105     ArrayList<Uri> mTempWallpaperTiles = new ArrayList<Uri>();
106     private SavedWallpaperImages mSavedImages;
107     private WallpaperInfo mLiveWallpaperInfoOnPickerLaunch;
108     private int mSelectedIndex = -1;
109     private WallpaperInfo mLastClickedLiveWallpaperInfo;
110 
111     public static abstract class WallpaperTileInfo {
112         protected View mView;
113         public Drawable mThumb;
114 
setView(View v)115         public void setView(View v) {
116             mView = v;
117         }
onClick(WallpaperPickerActivity a)118         public void onClick(WallpaperPickerActivity a) {}
onSave(WallpaperPickerActivity a)119         public void onSave(WallpaperPickerActivity a) {}
onDelete(WallpaperPickerActivity a)120         public void onDelete(WallpaperPickerActivity a) {}
isSelectable()121         public boolean isSelectable() { return false; }
isNamelessWallpaper()122         public boolean isNamelessWallpaper() { return false; }
onIndexUpdated(CharSequence label)123         public void onIndexUpdated(CharSequence label) {
124             if (isNamelessWallpaper()) {
125                 mView.setContentDescription(label);
126             }
127         }
128     }
129 
130     public static class PickImageInfo extends WallpaperTileInfo {
131         @Override
onClick(WallpaperPickerActivity a)132         public void onClick(WallpaperPickerActivity a) {
133             Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
134             intent.setType("image/*");
135             a.startActivityForResultSafely(intent, IMAGE_PICK);
136         }
137     }
138 
139     public static class UriWallpaperInfo extends WallpaperTileInfo {
140         private Uri mUri;
141         private boolean mFirstClick = true;
142         private BitmapRegionTileSource.UriBitmapSource mBitmapSource;
UriWallpaperInfo(Uri uri)143         public UriWallpaperInfo(Uri uri) {
144             mUri = uri;
145         }
146         @Override
onClick(final WallpaperPickerActivity a)147         public void onClick(final WallpaperPickerActivity a) {
148             final Runnable onLoad;
149             if (!mFirstClick) {
150                 onLoad = null;
151             } else {
152                 mFirstClick = false;
153                 a.mSetWallpaperButton.setEnabled(false);
154                 onLoad = new Runnable() {
155                     public void run() {
156                         if (mBitmapSource != null &&
157                                 mBitmapSource.getLoadingState() == BitmapSource.State.LOADED) {
158                             a.selectTile(mView);
159                             a.mSetWallpaperButton.setEnabled(true);
160                         } else {
161                             ViewGroup parent = (ViewGroup) mView.getParent();
162                             if (parent != null) {
163                                 parent.removeView(mView);
164                                 Toast.makeText(a,
165                                         a.getString(R.string.image_load_fail),
166                                         Toast.LENGTH_SHORT).show();
167                             }
168                         }
169                     }
170                 };
171             }
172             mBitmapSource = new BitmapRegionTileSource.UriBitmapSource(
173                     a, mUri, BitmapRegionTileSource.MAX_PREVIEW_SIZE);
174             a.setCropViewTileSource(mBitmapSource, true, false, onLoad);
175         }
176         @Override
onSave(final WallpaperPickerActivity a)177         public void onSave(final WallpaperPickerActivity a) {
178             boolean finishActivityWhenDone = true;
179             OnBitmapCroppedHandler h = new OnBitmapCroppedHandler() {
180                 public void onBitmapCropped(byte[] imageBytes) {
181                     Point thumbSize = getDefaultThumbnailSize(a.getResources());
182                     // rotation is set to 0 since imageBytes has already been correctly rotated
183                     Bitmap thumb = createThumbnail(
184                             thumbSize, null, null, imageBytes, null, 0, 0, true);
185                     a.getSavedImages().writeImage(thumb, imageBytes);
186                 }
187             };
188             a.cropImageAndSetWallpaper(mUri, h, finishActivityWhenDone);
189         }
190         @Override
isSelectable()191         public boolean isSelectable() {
192             return true;
193         }
194         @Override
isNamelessWallpaper()195         public boolean isNamelessWallpaper() {
196             return true;
197         }
198     }
199 
200     public static class FileWallpaperInfo extends WallpaperTileInfo {
201         private File mFile;
202 
FileWallpaperInfo(File target, Drawable thumb)203         public FileWallpaperInfo(File target, Drawable thumb) {
204             mFile = target;
205             mThumb = thumb;
206         }
207         @Override
onClick(WallpaperPickerActivity a)208         public void onClick(WallpaperPickerActivity a) {
209             BitmapRegionTileSource.UriBitmapSource bitmapSource =
210                     new BitmapRegionTileSource.UriBitmapSource(a, Uri.fromFile(mFile), 1024);
211             a.setCropViewTileSource(bitmapSource, false, true, null);
212         }
213         @Override
onSave(WallpaperPickerActivity a)214         public void onSave(WallpaperPickerActivity a) {
215             a.setWallpaper(Uri.fromFile(mFile), true);
216         }
217         @Override
isSelectable()218         public boolean isSelectable() {
219             return true;
220         }
221         @Override
isNamelessWallpaper()222         public boolean isNamelessWallpaper() {
223             return true;
224         }
225     }
226 
227     public static class ResourceWallpaperInfo extends WallpaperTileInfo {
228         private Resources mResources;
229         private int mResId;
230 
ResourceWallpaperInfo(Resources res, int resId, Drawable thumb)231         public ResourceWallpaperInfo(Resources res, int resId, Drawable thumb) {
232             mResources = res;
233             mResId = resId;
234             mThumb = thumb;
235         }
236         @Override
onClick(WallpaperPickerActivity a)237         public void onClick(WallpaperPickerActivity a) {
238             BitmapRegionTileSource.ResourceBitmapSource bitmapSource =
239                     new BitmapRegionTileSource.ResourceBitmapSource(
240                             mResources, mResId, BitmapRegionTileSource.MAX_PREVIEW_SIZE);
241             bitmapSource.loadInBackground();
242             BitmapRegionTileSource source = new BitmapRegionTileSource(a, bitmapSource);
243             CropView v = a.getCropView();
244             v.setTileSource(source, null);
245             Point wallpaperSize = WallpaperCropActivity.getDefaultWallpaperSize(
246                     a.getResources(), a.getWindowManager());
247             RectF crop = WallpaperCropActivity.getMaxCropRect(
248                     source.getImageWidth(), source.getImageHeight(),
249                     wallpaperSize.x, wallpaperSize.y, false);
250             v.setScale(wallpaperSize.x / crop.width());
251             v.setTouchEnabled(false);
252             a.setSystemWallpaperVisiblity(false);
253         }
254         @Override
onSave(WallpaperPickerActivity a)255         public void onSave(WallpaperPickerActivity a) {
256             boolean finishActivityWhenDone = true;
257             a.cropImageAndSetWallpaper(mResources, mResId, finishActivityWhenDone);
258         }
259         @Override
isSelectable()260         public boolean isSelectable() {
261             return true;
262         }
263         @Override
isNamelessWallpaper()264         public boolean isNamelessWallpaper() {
265             return true;
266         }
267     }
268 
269     @TargetApi(Build.VERSION_CODES.KITKAT)
270     public static class DefaultWallpaperInfo extends WallpaperTileInfo {
DefaultWallpaperInfo(Drawable thumb)271         public DefaultWallpaperInfo(Drawable thumb) {
272             mThumb = thumb;
273         }
274         @Override
onClick(WallpaperPickerActivity a)275         public void onClick(WallpaperPickerActivity a) {
276             CropView c = a.getCropView();
277 
278             Drawable defaultWallpaper = WallpaperManager.getInstance(a).getBuiltInDrawable(
279                     c.getWidth(), c.getHeight(), false, 0.5f, 0.5f);
280 
281             if (defaultWallpaper == null) {
282                 Log.w(TAG, "Null default wallpaper encountered.");
283                 c.setTileSource(null, null);
284                 return;
285             }
286 
287             c.setTileSource(
288                     new DrawableTileSource(a, defaultWallpaper, DrawableTileSource.MAX_PREVIEW_SIZE), null);
289             c.setScale(1f);
290             c.setTouchEnabled(false);
291             a.setSystemWallpaperVisiblity(false);
292         }
293         @Override
onSave(WallpaperPickerActivity a)294         public void onSave(WallpaperPickerActivity a) {
295             try {
296                 WallpaperManager.getInstance(a).clear();
297                 a.setResult(RESULT_OK);
298             } catch (IOException e) {
299                 Log.w("Setting wallpaper to default threw exception", e);
300             }
301             a.finish();
302         }
303         @Override
isSelectable()304         public boolean isSelectable() {
305             return true;
306         }
307         @Override
isNamelessWallpaper()308         public boolean isNamelessWallpaper() {
309             return true;
310         }
311     }
312 
setWallpaperStripYOffset(float offset)313     public void setWallpaperStripYOffset(float offset) {
314         mWallpaperStrip.setPadding(0, 0, 0, (int) offset);
315     }
316 
317     /**
318      * shows the system wallpaper behind the window and hides the {@link
319      * #mCropView} if visible
320      * @param visible should the system wallpaper be shown
321      */
setSystemWallpaperVisiblity(final boolean visible)322     protected void setSystemWallpaperVisiblity(final boolean visible) {
323         // hide our own wallpaper preview if necessary
324         if(!visible) {
325             mCropView.setVisibility(View.VISIBLE);
326         } else {
327             changeWallpaperFlags(visible);
328         }
329         // the change of the flag must be delayed in order to avoid flickering,
330         // a simple post / double post does not suffice here
331         mCropView.postDelayed(new Runnable() {
332             @Override
333             public void run() {
334                 if(!visible) {
335                     changeWallpaperFlags(visible);
336                 } else {
337                     mCropView.setVisibility(View.INVISIBLE);
338                 }
339             }
340         }, FLAG_POST_DELAY_MILLIS);
341     }
342 
changeWallpaperFlags(boolean visible)343     private void changeWallpaperFlags(boolean visible) {
344         int desiredWallpaperFlag = visible ? WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER : 0;
345         int currentWallpaperFlag = getWindow().getAttributes().flags
346                 & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
347         if (desiredWallpaperFlag != currentWallpaperFlag) {
348             getWindow().setFlags(desiredWallpaperFlag,
349                     WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER);
350         }
351     }
352 
353     @Override
setCropViewTileSource(BitmapSource bitmapSource, boolean touchEnabled, boolean moveToLeft, final Runnable postExecute)354     public void setCropViewTileSource(BitmapSource bitmapSource,
355                                       boolean touchEnabled,
356                                       boolean moveToLeft,
357                                       final Runnable postExecute) {
358         // we also want to show our own wallpaper instead of the one in the background
359         Runnable showPostExecuteRunnable = new Runnable() {
360             @Override
361             public void run() {
362                 if(postExecute != null) {
363                     postExecute.run();
364                 }
365                 setSystemWallpaperVisiblity(false);
366             }
367         };
368         super.setCropViewTileSource(bitmapSource,
369                 touchEnabled,
370                 moveToLeft,
371                 showPostExecuteRunnable);
372     }
373 
374     // called by onCreate; this is subclassed to overwrite WallpaperCropActivity
init()375     protected void init() {
376         setContentView(R.layout.wallpaper_picker);
377 
378         mCropView = (CropView) findViewById(R.id.cropView);
379         mCropView.setVisibility(View.INVISIBLE);
380 
381         mWallpaperStrip = findViewById(R.id.wallpaper_strip);
382         mCropView.setTouchCallback(new CropView.TouchCallback() {
383             ViewPropertyAnimator mAnim;
384             @Override
385             public void onTouchDown() {
386                 if (mAnim != null) {
387                     mAnim.cancel();
388                 }
389                 if (mWallpaperStrip.getAlpha() == 1f) {
390                     mIgnoreNextTap = true;
391                 }
392                 mAnim = mWallpaperStrip.animate();
393                 mAnim.alpha(0f)
394                     .setDuration(150)
395                     .withEndAction(new Runnable() {
396                         public void run() {
397                             mWallpaperStrip.setVisibility(View.INVISIBLE);
398                         }
399                     });
400                 mAnim.setInterpolator(new AccelerateInterpolator(0.75f));
401                 mAnim.start();
402             }
403             @Override
404             public void onTouchUp() {
405                 mIgnoreNextTap = false;
406             }
407             @Override
408             public void onTap() {
409                 boolean ignoreTap = mIgnoreNextTap;
410                 mIgnoreNextTap = false;
411                 if (!ignoreTap) {
412                     if (mAnim != null) {
413                         mAnim.cancel();
414                     }
415                     mWallpaperStrip.setVisibility(View.VISIBLE);
416                     mAnim = mWallpaperStrip.animate();
417                     mAnim.alpha(1f)
418                          .setDuration(150)
419                          .setInterpolator(new DecelerateInterpolator(0.75f));
420                     mAnim.start();
421                 }
422             }
423         });
424 
425         mThumbnailOnClickListener = new OnClickListener() {
426             public void onClick(View v) {
427                 if (mActionMode != null) {
428                     // When CAB is up, clicking toggles the item instead
429                     if (v.isLongClickable()) {
430                         mLongClickListener.onLongClick(v);
431                     }
432                     return;
433                 }
434                 mSetWallpaperButton.setEnabled(true);
435                 WallpaperTileInfo info = (WallpaperTileInfo) v.getTag();
436                 if (info.isSelectable() && v.getVisibility() == View.VISIBLE) {
437                     selectTile(v);
438                 }
439                 info.onClick(WallpaperPickerActivity.this);
440             }
441         };
442         mLongClickListener = new View.OnLongClickListener() {
443             // Called when the user long-clicks on someView
444             public boolean onLongClick(View view) {
445                 CheckableFrameLayout c = (CheckableFrameLayout) view;
446                 c.toggle();
447 
448                 if (mActionMode != null) {
449                     mActionMode.invalidate();
450                 } else {
451                     // Start the CAB using the ActionMode.Callback defined below
452                     mActionMode = startActionMode(mActionModeCallback);
453                     int childCount = mWallpapersView.getChildCount();
454                     for (int i = 0; i < childCount; i++) {
455                         mWallpapersView.getChildAt(i).setSelected(false);
456                     }
457                 }
458                 return true;
459             }
460         };
461 
462         // Populate the built-in wallpapers
463         ArrayList<WallpaperTileInfo> wallpapers = findBundledWallpapers();
464         mWallpapersView = (LinearLayout) findViewById(R.id.wallpaper_list);
465         SimpleWallpapersAdapter ia = new SimpleWallpapersAdapter(this, wallpapers);
466         populateWallpapersFromAdapter(mWallpapersView, ia, false);
467 
468         // Populate the saved wallpapers
469         mSavedImages = new SavedWallpaperImages(this);
470         mSavedImages.loadThumbnailsAndImageIdList();
471         populateWallpapersFromAdapter(mWallpapersView, mSavedImages, true);
472 
473         // Populate the live wallpapers
474         final LinearLayout liveWallpapersView =
475                 (LinearLayout) findViewById(R.id.live_wallpaper_list);
476         final LiveWallpaperListAdapter a = new LiveWallpaperListAdapter(this);
477         a.registerDataSetObserver(new DataSetObserver() {
478             public void onChanged() {
479                 liveWallpapersView.removeAllViews();
480                 populateWallpapersFromAdapter(liveWallpapersView, a, false);
481                 initializeScrollForRtl();
482                 updateTileIndices();
483             }
484         });
485 
486         // Populate the third-party wallpaper pickers
487         final LinearLayout thirdPartyWallpapersView =
488                 (LinearLayout) findViewById(R.id.third_party_wallpaper_list);
489         final ThirdPartyWallpaperPickerListAdapter ta =
490                 new ThirdPartyWallpaperPickerListAdapter(this);
491         populateWallpapersFromAdapter(thirdPartyWallpapersView, ta, false);
492 
493         // Add a tile for the Gallery
494         LinearLayout masterWallpaperList = (LinearLayout) findViewById(R.id.master_wallpaper_list);
495         FrameLayout pickImageTile = (FrameLayout) getLayoutInflater().
496                 inflate(R.layout.wallpaper_picker_image_picker_item, masterWallpaperList, false);
497         setWallpaperItemPaddingToZero(pickImageTile);
498         masterWallpaperList.addView(pickImageTile, 0);
499 
500         // Make its background the last photo taken on external storage
501         Bitmap lastPhoto = getThumbnailOfLastPhoto();
502         if (lastPhoto != null) {
503             ImageView galleryThumbnailBg =
504                     (ImageView) pickImageTile.findViewById(R.id.wallpaper_image);
505             galleryThumbnailBg.setImageBitmap(getThumbnailOfLastPhoto());
506             int colorOverlay = getResources().getColor(R.color.wallpaper_picker_translucent_gray);
507             galleryThumbnailBg.setColorFilter(colorOverlay, PorterDuff.Mode.SRC_ATOP);
508 
509         }
510 
511         PickImageInfo pickImageInfo = new PickImageInfo();
512         pickImageTile.setTag(pickImageInfo);
513         pickImageInfo.setView(pickImageTile);
514         pickImageTile.setOnClickListener(mThumbnailOnClickListener);
515 
516         // Select the first item; wait for a layout pass so that we initialize the dimensions of
517         // cropView or the defaultWallpaperView first
518         mCropView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
519             @Override
520             public void onLayoutChange(View v, int left, int top, int right, int bottom,
521                     int oldLeft, int oldTop, int oldRight, int oldBottom) {
522                 if ((right - left) > 0 && (bottom - top) > 0) {
523                     if (mSelectedIndex >= 0 && mSelectedIndex < mWallpapersView.getChildCount()) {
524                         mThumbnailOnClickListener.onClick(
525                                 mWallpapersView.getChildAt(mSelectedIndex));
526                         setSystemWallpaperVisiblity(false);
527                     }
528                     v.removeOnLayoutChangeListener(this);
529                 }
530             }
531         });
532 
533         updateTileIndices();
534 
535         // Update the scroll for RTL
536         initializeScrollForRtl();
537 
538         // Create smooth layout transitions for when items are deleted
539         final LayoutTransition transitioner = new LayoutTransition();
540         transitioner.setDuration(200);
541         transitioner.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 0);
542         transitioner.setAnimator(LayoutTransition.DISAPPEARING, null);
543         mWallpapersView.setLayoutTransition(transitioner);
544 
545         // Action bar
546         // Show the custom action bar view
547         final ActionBar actionBar = getActionBar();
548         actionBar.setCustomView(R.layout.actionbar_set_wallpaper);
549         actionBar.getCustomView().setOnClickListener(
550                 new View.OnClickListener() {
551                     @Override
552                     public void onClick(View v) {
553                         if (mSelectedTile != null) {
554                             WallpaperTileInfo info = (WallpaperTileInfo) mSelectedTile.getTag();
555                             info.onSave(WallpaperPickerActivity.this);
556                         } else {
557                             // no tile was selected, so we just finish the activity and go back
558                             setResult(Activity.RESULT_OK);
559                             finish();
560                         }
561                     }
562                 });
563         mSetWallpaperButton = findViewById(R.id.set_wallpaper_button);
564 
565         // CAB for deleting items
566         mActionModeCallback = new ActionMode.Callback() {
567             // Called when the action mode is created; startActionMode() was called
568             @Override
569             public boolean onCreateActionMode(ActionMode mode, Menu menu) {
570                 // Inflate a menu resource providing context menu items
571                 MenuInflater inflater = mode.getMenuInflater();
572                 inflater.inflate(R.menu.cab_delete_wallpapers, menu);
573                 return true;
574             }
575 
576             private int numCheckedItems() {
577                 int childCount = mWallpapersView.getChildCount();
578                 int numCheckedItems = 0;
579                 for (int i = 0; i < childCount; i++) {
580                     CheckableFrameLayout c = (CheckableFrameLayout) mWallpapersView.getChildAt(i);
581                     if (c.isChecked()) {
582                         numCheckedItems++;
583                     }
584                 }
585                 return numCheckedItems;
586             }
587 
588             // Called each time the action mode is shown. Always called after onCreateActionMode,
589             // but may be called multiple times if the mode is invalidated.
590             @Override
591             public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
592                 int numCheckedItems = numCheckedItems();
593                 if (numCheckedItems == 0) {
594                     mode.finish();
595                     return true;
596                 } else {
597                     mode.setTitle(getResources().getQuantityString(
598                             R.plurals.number_of_items_selected, numCheckedItems, numCheckedItems));
599                     return true;
600                 }
601             }
602 
603             // Called when the user selects a contextual menu item
604             @Override
605             public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
606                 int itemId = item.getItemId();
607                 if (itemId == R.id.menu_delete) {
608                     int childCount = mWallpapersView.getChildCount();
609                     ArrayList<View> viewsToRemove = new ArrayList<View>();
610                     boolean selectedTileRemoved = false;
611                     for (int i = 0; i < childCount; i++) {
612                         CheckableFrameLayout c =
613                                 (CheckableFrameLayout) mWallpapersView.getChildAt(i);
614                         if (c.isChecked()) {
615                             WallpaperTileInfo info = (WallpaperTileInfo) c.getTag();
616                             info.onDelete(WallpaperPickerActivity.this);
617                             viewsToRemove.add(c);
618                             if (i == mSelectedIndex) {
619                                 selectedTileRemoved = true;
620                             }
621                         }
622                     }
623                     for (View v : viewsToRemove) {
624                         mWallpapersView.removeView(v);
625                     }
626                     if (selectedTileRemoved) {
627                         mSelectedIndex = -1;
628                         mSelectedTile = null;
629                         setSystemWallpaperVisiblity(true);
630                     }
631                     updateTileIndices();
632                     mode.finish(); // Action picked, so close the CAB
633                     return true;
634                 } else {
635                     return false;
636                 }
637             }
638 
639             // Called when the user exits the action mode
640             @Override
641             public void onDestroyActionMode(ActionMode mode) {
642                 int childCount = mWallpapersView.getChildCount();
643                 for (int i = 0; i < childCount; i++) {
644                     CheckableFrameLayout c = (CheckableFrameLayout) mWallpapersView.getChildAt(i);
645                     c.setChecked(false);
646                 }
647                 if (mSelectedTile != null) {
648                     mSelectedTile.setSelected(true);
649                 }
650                 mActionMode = null;
651             }
652         };
653     }
654 
selectTile(View v)655     private void selectTile(View v) {
656         if (mSelectedTile != null) {
657             mSelectedTile.setSelected(false);
658             mSelectedTile = null;
659         }
660         mSelectedTile = v;
661         v.setSelected(true);
662         mSelectedIndex = mWallpapersView.indexOfChild(v);
663         // TODO: Remove this once the accessibility framework and
664         // services have better support for selection state.
665         v.announceForAccessibility(
666                 getString(R.string.announce_selection, v.getContentDescription()));
667     }
668 
initializeScrollForRtl()669     private void initializeScrollForRtl() {
670         final HorizontalScrollView scroll =
671                 (HorizontalScrollView) findViewById(R.id.wallpaper_scroll_container);
672 
673         if (scroll.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
674             final ViewTreeObserver observer = scroll.getViewTreeObserver();
675             observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
676                 public void onGlobalLayout() {
677                     LinearLayout masterWallpaperList =
678                             (LinearLayout) findViewById(R.id.master_wallpaper_list);
679                     scroll.scrollTo(masterWallpaperList.getWidth(), 0);
680                     scroll.getViewTreeObserver().removeOnGlobalLayoutListener(this);
681                 }
682             });
683         }
684     }
685 
getThumbnailOfLastPhoto()686     protected Bitmap getThumbnailOfLastPhoto() {
687         Cursor cursor = MediaStore.Images.Media.query(getContentResolver(),
688                 MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
689                 new String[] { MediaStore.Images.ImageColumns._ID,
690                     MediaStore.Images.ImageColumns.DATE_TAKEN},
691                 null, null, MediaStore.Images.ImageColumns.DATE_TAKEN + " DESC LIMIT 1");
692 
693         Bitmap thumb = null;
694         if (cursor != null) {
695             if (cursor.moveToNext()) {
696                 int id = cursor.getInt(0);
697                 thumb = MediaStore.Images.Thumbnails.getThumbnail(getContentResolver(),
698                         id, MediaStore.Images.Thumbnails.MINI_KIND, null);
699             }
700             cursor.close();
701         }
702         return thumb;
703     }
704 
onStop()705     protected void onStop() {
706         super.onStop();
707         mWallpaperStrip = findViewById(R.id.wallpaper_strip);
708         if (mWallpaperStrip.getAlpha() < 1f) {
709             mWallpaperStrip.setAlpha(1f);
710             mWallpaperStrip.setVisibility(View.VISIBLE);
711         }
712     }
713 
onSaveInstanceState(Bundle outState)714     protected void onSaveInstanceState(Bundle outState) {
715         outState.putParcelableArrayList(TEMP_WALLPAPER_TILES, mTempWallpaperTiles);
716         outState.putInt(SELECTED_INDEX, mSelectedIndex);
717     }
718 
onRestoreInstanceState(Bundle savedInstanceState)719     protected void onRestoreInstanceState(Bundle savedInstanceState) {
720         ArrayList<Uri> uris = savedInstanceState.getParcelableArrayList(TEMP_WALLPAPER_TILES);
721         for (Uri uri : uris) {
722             addTemporaryWallpaperTile(uri, true);
723         }
724         mSelectedIndex = savedInstanceState.getInt(SELECTED_INDEX, -1);
725     }
726 
populateWallpapersFromAdapter(ViewGroup parent, BaseAdapter adapter, boolean addLongPressHandler)727     private void populateWallpapersFromAdapter(ViewGroup parent, BaseAdapter adapter,
728             boolean addLongPressHandler) {
729         for (int i = 0; i < adapter.getCount(); i++) {
730             FrameLayout thumbnail = (FrameLayout) adapter.getView(i, null, parent);
731             parent.addView(thumbnail, i);
732             WallpaperTileInfo info = (WallpaperTileInfo) adapter.getItem(i);
733             thumbnail.setTag(info);
734             info.setView(thumbnail);
735             if (addLongPressHandler) {
736                 addLongPressHandler(thumbnail);
737             }
738             thumbnail.setOnClickListener(mThumbnailOnClickListener);
739         }
740     }
741 
updateTileIndices()742     private void updateTileIndices() {
743         LinearLayout masterWallpaperList = (LinearLayout) findViewById(R.id.master_wallpaper_list);
744         final int childCount = masterWallpaperList.getChildCount();
745         final Resources res = getResources();
746 
747         // Do two passes; the first pass gets the total number of tiles
748         int numTiles = 0;
749         for (int passNum = 0; passNum < 2; passNum++) {
750             int tileIndex = 0;
751             for (int i = 0; i < childCount; i++) {
752                 View child = masterWallpaperList.getChildAt(i);
753                 LinearLayout subList;
754 
755                 int subListStart;
756                 int subListEnd;
757                 if (child.getTag() instanceof WallpaperTileInfo) {
758                     subList = masterWallpaperList;
759                     subListStart = i;
760                     subListEnd = i + 1;
761                 } else { // if (child instanceof LinearLayout) {
762                     subList = (LinearLayout) child;
763                     subListStart = 0;
764                     subListEnd = subList.getChildCount();
765                 }
766 
767                 for (int j = subListStart; j < subListEnd; j++) {
768                     WallpaperTileInfo info = (WallpaperTileInfo) subList.getChildAt(j).getTag();
769                     if (info.isNamelessWallpaper()) {
770                         if (passNum == 0) {
771                             numTiles++;
772                         } else {
773                             CharSequence label = res.getString(
774                                     R.string.wallpaper_accessibility_name, ++tileIndex, numTiles);
775                             info.onIndexUpdated(label);
776                         }
777                     }
778                 }
779             }
780         }
781     }
782 
getDefaultThumbnailSize(Resources res)783     private static Point getDefaultThumbnailSize(Resources res) {
784         return new Point(res.getDimensionPixelSize(R.dimen.wallpaperThumbnailWidth),
785                 res.getDimensionPixelSize(R.dimen.wallpaperThumbnailHeight));
786 
787     }
788 
createThumbnail(Point size, Context context, Uri uri, byte[] imageBytes, Resources res, int resId, int rotation, boolean leftAligned)789     private static Bitmap createThumbnail(Point size, Context context, Uri uri, byte[] imageBytes,
790             Resources res, int resId, int rotation, boolean leftAligned) {
791         int width = size.x;
792         int height = size.y;
793 
794         BitmapCropTask cropTask;
795         if (uri != null) {
796             cropTask = new BitmapCropTask(
797                     context, uri, null, rotation, width, height, false, true, null);
798         } else if (imageBytes != null) {
799             cropTask = new BitmapCropTask(
800                     imageBytes, null, rotation, width, height, false, true, null);
801         }  else {
802             cropTask = new BitmapCropTask(
803                     context, res, resId, null, rotation, width, height, false, true, null);
804         }
805         Point bounds = cropTask.getImageBounds();
806         if (bounds == null || bounds.x == 0 || bounds.y == 0) {
807             return null;
808         }
809 
810         Matrix rotateMatrix = new Matrix();
811         rotateMatrix.setRotate(rotation);
812         float[] rotatedBounds = new float[] { bounds.x, bounds.y };
813         rotateMatrix.mapPoints(rotatedBounds);
814         rotatedBounds[0] = Math.abs(rotatedBounds[0]);
815         rotatedBounds[1] = Math.abs(rotatedBounds[1]);
816 
817         RectF cropRect = WallpaperCropActivity.getMaxCropRect(
818                 (int) rotatedBounds[0], (int) rotatedBounds[1], width, height, leftAligned);
819         cropTask.setCropBounds(cropRect);
820 
821         if (cropTask.cropBitmap()) {
822             return cropTask.getCroppedBitmap();
823         } else {
824             return null;
825         }
826     }
827 
addTemporaryWallpaperTile(final Uri uri, boolean fromRestore)828     private void addTemporaryWallpaperTile(final Uri uri, boolean fromRestore) {
829         mTempWallpaperTiles.add(uri);
830         // Add a tile for the image picked from Gallery
831         final FrameLayout pickedImageThumbnail = (FrameLayout) getLayoutInflater().
832                 inflate(R.layout.wallpaper_picker_item, mWallpapersView, false);
833         pickedImageThumbnail.setVisibility(View.GONE);
834         setWallpaperItemPaddingToZero(pickedImageThumbnail);
835         mWallpapersView.addView(pickedImageThumbnail, 0);
836 
837         // Load the thumbnail
838         final ImageView image = (ImageView) pickedImageThumbnail.findViewById(R.id.wallpaper_image);
839         final Point defaultSize = getDefaultThumbnailSize(this.getResources());
840         final Context context = this;
841         new AsyncTask<Void, Bitmap, Bitmap>() {
842             protected Bitmap doInBackground(Void...args) {
843                 try {
844                     int rotation = WallpaperCropActivity.getRotationFromExif(context, uri);
845                     return createThumbnail(defaultSize, context, uri, null, null, 0, rotation, false);
846                 } catch (SecurityException securityException) {
847                     if (isDestroyed()) {
848                         // Temporarily granted permissions are revoked when the activity
849                         // finishes, potentially resulting in a SecurityException here.
850                         // Even though {@link #isDestroyed} might also return true in different
851                         // situations where the configuration changes, we are fine with
852                         // catching these cases here as well.
853                         cancel(false);
854                     } else {
855                         // otherwise it had a different cause and we throw it further
856                         throw securityException;
857                     }
858                     return null;
859                 }
860             }
861             protected void onPostExecute(Bitmap thumb) {
862                 if (!isCancelled() && thumb != null) {
863                     image.setImageBitmap(thumb);
864                     Drawable thumbDrawable = image.getDrawable();
865                     thumbDrawable.setDither(true);
866                     pickedImageThumbnail.setVisibility(View.VISIBLE);
867                 } else {
868                     Log.e(TAG, "Error loading thumbnail for uri=" + uri);
869                 }
870             }
871         }.execute();
872 
873         UriWallpaperInfo info = new UriWallpaperInfo(uri);
874         pickedImageThumbnail.setTag(info);
875         info.setView(pickedImageThumbnail);
876         addLongPressHandler(pickedImageThumbnail);
877         updateTileIndices();
878         pickedImageThumbnail.setOnClickListener(mThumbnailOnClickListener);
879         if (!fromRestore) {
880             mThumbnailOnClickListener.onClick(pickedImageThumbnail);
881         }
882     }
883 
onActivityResult(int requestCode, int resultCode, Intent data)884     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
885         if (requestCode == IMAGE_PICK && resultCode == RESULT_OK) {
886             if (data != null && data.getData() != null) {
887                 Uri uri = data.getData();
888                 addTemporaryWallpaperTile(uri, false);
889             }
890         } else if (requestCode == PICK_WALLPAPER_THIRD_PARTY_ACTIVITY) {
891             setResult(RESULT_OK);
892             finish();
893         } else if (requestCode == PICK_LIVE_WALLPAPER) {
894             WallpaperManager wm = WallpaperManager.getInstance(this);
895             final WallpaperInfo oldLiveWallpaper = mLiveWallpaperInfoOnPickerLaunch;
896             final WallpaperInfo clickedWallpaper = mLastClickedLiveWallpaperInfo;
897             WallpaperInfo newLiveWallpaper = wm.getWallpaperInfo();
898             // Try to figure out if a live wallpaper was set;
899             if (newLiveWallpaper != null &&
900                     (oldLiveWallpaper == null
901                             || !oldLiveWallpaper.getComponent()
902                                     .equals(newLiveWallpaper.getComponent())
903                             || clickedWallpaper.getComponent()
904                                     .equals(oldLiveWallpaper.getComponent()))) {
905                 // Return if a live wallpaper was set
906                 setResult(RESULT_OK);
907                 finish();
908             }
909         }
910     }
911 
setWallpaperItemPaddingToZero(FrameLayout frameLayout)912     static void setWallpaperItemPaddingToZero(FrameLayout frameLayout) {
913         frameLayout.setPadding(0, 0, 0, 0);
914         frameLayout.setForeground(new ZeroPaddingDrawable(frameLayout.getForeground()));
915     }
916 
addLongPressHandler(View v)917     private void addLongPressHandler(View v) {
918         v.setOnLongClickListener(mLongClickListener);
919     }
920 
findBundledWallpapers()921     private ArrayList<WallpaperTileInfo> findBundledWallpapers() {
922         final PackageManager pm = getPackageManager();
923         final ArrayList<WallpaperTileInfo> bundled = new ArrayList<WallpaperTileInfo>(24);
924 
925         Partner partner = Partner.get(pm);
926         if (partner != null) {
927             final Resources partnerRes = partner.getResources();
928             final int resId = partnerRes.getIdentifier(Partner.RES_WALLPAPERS, "array",
929                     partner.getPackageName());
930             if (resId != 0) {
931                 addWallpapers(bundled, partnerRes, partner.getPackageName(), resId);
932             }
933 
934             // Add system wallpapers
935             File systemDir = partner.getWallpaperDirectory();
936             if (systemDir != null && systemDir.isDirectory()) {
937                 for (File file : systemDir.listFiles()) {
938                     if (!file.isFile()) {
939                         continue;
940                     }
941                     String name = file.getName();
942                     int dotPos = name.lastIndexOf('.');
943                     String extension = "";
944                     if (dotPos >= -1) {
945                         extension = name.substring(dotPos);
946                         name = name.substring(0, dotPos);
947                     }
948 
949                     if (name.endsWith("_small")) {
950                         // it is a thumbnail
951                         continue;
952                     }
953 
954                     File thumbnail = new File(systemDir, name + "_small" + extension);
955                     Bitmap thumb = BitmapFactory.decodeFile(thumbnail.getAbsolutePath());
956                     if (thumb != null) {
957                         bundled.add(new FileWallpaperInfo(file, new BitmapDrawable(thumb)));
958                     }
959                 }
960             }
961         }
962 
963         Pair<ApplicationInfo, Integer> r = getWallpaperArrayResourceId();
964         if (r != null) {
965             try {
966                 Resources wallpaperRes = getPackageManager().getResourcesForApplication(r.first);
967                 addWallpapers(bundled, wallpaperRes, r.first.packageName, r.second);
968             } catch (PackageManager.NameNotFoundException e) {
969             }
970         }
971 
972         if (partner == null || !partner.hideDefaultWallpaper()) {
973             // Add an entry for the default wallpaper (stored in system resources)
974             WallpaperTileInfo defaultWallpaperInfo =
975                     (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
976                     ? getPreKKDefaultWallpaperInfo()
977                     : getDefaultWallpaper();
978             if (defaultWallpaperInfo != null) {
979                 bundled.add(0, defaultWallpaperInfo);
980             }
981         }
982         return bundled;
983     }
984 
writeImageToFileAsJpeg(File f, Bitmap b)985     private boolean writeImageToFileAsJpeg(File f, Bitmap b) {
986         try {
987             f.createNewFile();
988             FileOutputStream thumbFileStream =
989                     openFileOutput(f.getName(), Context.MODE_PRIVATE);
990             b.compress(Bitmap.CompressFormat.JPEG, 95, thumbFileStream);
991             thumbFileStream.close();
992             return true;
993         } catch (IOException e) {
994             Log.e(TAG, "Error while writing bitmap to file " + e);
995             f.delete();
996         }
997         return false;
998     }
999 
getDefaultThumbFile()1000     private File getDefaultThumbFile() {
1001         return new File(getFilesDir(), Build.VERSION.SDK_INT
1002                 + "_" + DEFAULT_WALLPAPER_THUMBNAIL_FILENAME);
1003     }
1004 
saveDefaultWallpaperThumb(Bitmap b)1005     private boolean saveDefaultWallpaperThumb(Bitmap b) {
1006         // Delete old thumbnails.
1007         new File(getFilesDir(), OLD_DEFAULT_WALLPAPER_THUMBNAIL_FILENAME).delete();
1008         new File(getFilesDir(), DEFAULT_WALLPAPER_THUMBNAIL_FILENAME).delete();
1009 
1010         for (int i = Build.VERSION_CODES.JELLY_BEAN; i < Build.VERSION.SDK_INT; i++) {
1011             new File(getFilesDir(), i + "_" + DEFAULT_WALLPAPER_THUMBNAIL_FILENAME).delete();
1012         }
1013         return writeImageToFileAsJpeg(getDefaultThumbFile(), b);
1014     }
1015 
getPreKKDefaultWallpaperInfo()1016     private ResourceWallpaperInfo getPreKKDefaultWallpaperInfo() {
1017         Resources sysRes = Resources.getSystem();
1018         int resId = sysRes.getIdentifier("default_wallpaper", "drawable", "android");
1019 
1020         File defaultThumbFile = getDefaultThumbFile();
1021         Bitmap thumb = null;
1022         boolean defaultWallpaperExists = false;
1023         if (defaultThumbFile.exists()) {
1024             thumb = BitmapFactory.decodeFile(defaultThumbFile.getAbsolutePath());
1025             defaultWallpaperExists = true;
1026         } else {
1027             Resources res = getResources();
1028             Point defaultThumbSize = getDefaultThumbnailSize(res);
1029             int rotation = WallpaperCropActivity.getRotationFromExif(res, resId);
1030             thumb = createThumbnail(
1031                     defaultThumbSize, this, null, null, sysRes, resId, rotation, false);
1032             if (thumb != null) {
1033                 defaultWallpaperExists = saveDefaultWallpaperThumb(thumb);
1034             }
1035         }
1036         if (defaultWallpaperExists) {
1037             return new ResourceWallpaperInfo(sysRes, resId, new BitmapDrawable(thumb));
1038         }
1039         return null;
1040     }
1041 
1042     @TargetApi(Build.VERSION_CODES.KITKAT)
getDefaultWallpaper()1043     private DefaultWallpaperInfo getDefaultWallpaper() {
1044         File defaultThumbFile = getDefaultThumbFile();
1045         Bitmap thumb = null;
1046         boolean defaultWallpaperExists = false;
1047         if (defaultThumbFile.exists()) {
1048             thumb = BitmapFactory.decodeFile(defaultThumbFile.getAbsolutePath());
1049             defaultWallpaperExists = true;
1050         } else {
1051             Resources res = getResources();
1052             Point defaultThumbSize = getDefaultThumbnailSize(res);
1053             Drawable wallpaperDrawable = WallpaperManager.getInstance(this).getBuiltInDrawable(
1054                     defaultThumbSize.x, defaultThumbSize.y, true, 0.5f, 0.5f);
1055             if (wallpaperDrawable != null) {
1056                 thumb = Bitmap.createBitmap(
1057                         defaultThumbSize.x, defaultThumbSize.y, Bitmap.Config.ARGB_8888);
1058                 Canvas c = new Canvas(thumb);
1059                 wallpaperDrawable.setBounds(0, 0, defaultThumbSize.x, defaultThumbSize.y);
1060                 wallpaperDrawable.draw(c);
1061                 c.setBitmap(null);
1062             }
1063             if (thumb != null) {
1064                 defaultWallpaperExists = saveDefaultWallpaperThumb(thumb);
1065             }
1066         }
1067         if (defaultWallpaperExists) {
1068             return new DefaultWallpaperInfo(new BitmapDrawable(thumb));
1069         }
1070         return null;
1071     }
1072 
getWallpaperArrayResourceId()1073     public Pair<ApplicationInfo, Integer> getWallpaperArrayResourceId() {
1074         // Context.getPackageName() may return the "original" package name,
1075         // com.android.launcher3; Resources needs the real package name,
1076         // com.android.launcher3. So we ask Resources for what it thinks the
1077         // package name should be.
1078         final String packageName = getResources().getResourcePackageName(R.array.wallpapers);
1079         try {
1080             ApplicationInfo info = getPackageManager().getApplicationInfo(packageName, 0);
1081             return new Pair<ApplicationInfo, Integer>(info, R.array.wallpapers);
1082         } catch (PackageManager.NameNotFoundException e) {
1083             return null;
1084         }
1085     }
1086 
addWallpapers(ArrayList<WallpaperTileInfo> known, Resources res, String packageName, int listResId)1087     private void addWallpapers(ArrayList<WallpaperTileInfo> known, Resources res,
1088             String packageName, int listResId) {
1089         final String[] extras = res.getStringArray(listResId);
1090         for (String extra : extras) {
1091             int resId = res.getIdentifier(extra, "drawable", packageName);
1092             if (resId != 0) {
1093                 final int thumbRes = res.getIdentifier(extra + "_small", "drawable", packageName);
1094 
1095                 if (thumbRes != 0) {
1096                     ResourceWallpaperInfo wallpaperInfo =
1097                             new ResourceWallpaperInfo(res, resId, res.getDrawable(thumbRes));
1098                     known.add(wallpaperInfo);
1099                     // Log.d(TAG, "add: [" + packageName + "]: " + extra + " (" + res + ")");
1100                 }
1101             } else {
1102                 Log.e(TAG, "Couldn't find wallpaper " + extra);
1103             }
1104         }
1105     }
1106 
getCropView()1107     public CropView getCropView() {
1108         return mCropView;
1109     }
1110 
getSavedImages()1111     public SavedWallpaperImages getSavedImages() {
1112         return mSavedImages;
1113     }
1114 
onLiveWallpaperPickerLaunch(WallpaperInfo info)1115     public void onLiveWallpaperPickerLaunch(WallpaperInfo info) {
1116         mLastClickedLiveWallpaperInfo = info;
1117         mLiveWallpaperInfoOnPickerLaunch = WallpaperManager.getInstance(this).getWallpaperInfo();
1118     }
1119 
1120     static class ZeroPaddingDrawable extends LevelListDrawable {
ZeroPaddingDrawable(Drawable d)1121         public ZeroPaddingDrawable(Drawable d) {
1122             super();
1123             addLevel(0, 0, d);
1124             setLevel(0);
1125         }
1126 
1127         @Override
getPadding(Rect padding)1128         public boolean getPadding(Rect padding) {
1129             padding.set(0, 0, 0, 0);
1130             return true;
1131         }
1132     }
1133 
1134     private static class SimpleWallpapersAdapter extends ArrayAdapter<WallpaperTileInfo> {
1135         private final LayoutInflater mLayoutInflater;
1136 
SimpleWallpapersAdapter(Activity activity, ArrayList<WallpaperTileInfo> wallpapers)1137         SimpleWallpapersAdapter(Activity activity, ArrayList<WallpaperTileInfo> wallpapers) {
1138             super(activity, R.layout.wallpaper_picker_item, wallpapers);
1139             mLayoutInflater = activity.getLayoutInflater();
1140         }
1141 
getView(int position, View convertView, ViewGroup parent)1142         public View getView(int position, View convertView, ViewGroup parent) {
1143             Drawable thumb = getItem(position).mThumb;
1144             if (thumb == null) {
1145                 Log.e(TAG, "Error decoding thumbnail for wallpaper #" + position);
1146             }
1147             return createImageTileView(mLayoutInflater, convertView, parent, thumb);
1148         }
1149     }
1150 
createImageTileView(LayoutInflater layoutInflater, View convertView, ViewGroup parent, Drawable thumb)1151     public static View createImageTileView(LayoutInflater layoutInflater,
1152             View convertView, ViewGroup parent, Drawable thumb) {
1153         View view;
1154 
1155         if (convertView == null) {
1156             view = layoutInflater.inflate(R.layout.wallpaper_picker_item, parent, false);
1157         } else {
1158             view = convertView;
1159         }
1160 
1161         setWallpaperItemPaddingToZero((FrameLayout) view);
1162 
1163         ImageView image = (ImageView) view.findViewById(R.id.wallpaper_image);
1164 
1165         if (thumb != null) {
1166             image.setImageDrawable(thumb);
1167             thumb.setDither(true);
1168         }
1169 
1170         return view;
1171     }
1172 
1173     // In Launcher3, we override this with a method that catches exceptions
1174     // from starting activities; didn't want to copy and paste code into here
startActivityForResultSafely(Intent intent, int requestCode)1175     public void startActivityForResultSafely(Intent intent, int requestCode) {
1176         startActivityForResult(intent, requestCode);
1177     }
1178 }
1179