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.Animator; 20 import android.animation.LayoutTransition; 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.Matrix; 35 import android.graphics.Point; 36 import android.graphics.PorterDuff; 37 import android.graphics.Rect; 38 import android.graphics.RectF; 39 import android.graphics.drawable.BitmapDrawable; 40 import android.graphics.drawable.Drawable; 41 import android.graphics.drawable.LevelListDrawable; 42 import android.net.Uri; 43 import android.os.Bundle; 44 import android.provider.MediaStore; 45 import android.util.Log; 46 import android.util.Pair; 47 import android.view.ActionMode; 48 import android.view.LayoutInflater; 49 import android.view.Menu; 50 import android.view.MenuInflater; 51 import android.view.MenuItem; 52 import android.view.View; 53 import android.view.View.OnClickListener; 54 import android.view.ViewGroup; 55 import android.view.ViewTreeObserver; 56 import android.view.ViewTreeObserver.OnGlobalLayoutListener; 57 import android.view.accessibility.AccessibilityEvent; 58 import android.view.animation.AccelerateInterpolator; 59 import android.view.animation.DecelerateInterpolator; 60 import android.widget.BaseAdapter; 61 import android.widget.FrameLayout; 62 import android.widget.HorizontalScrollView; 63 import android.widget.ImageView; 64 import android.widget.LinearLayout; 65 import android.widget.ListAdapter; 66 67 import com.android.gallery3d.exif.ExifInterface; 68 import com.android.photos.BitmapRegionTileSource; 69 70 import java.io.BufferedInputStream; 71 import java.io.File; 72 import java.io.FileOutputStream; 73 import java.io.IOException; 74 import java.io.InputStream; 75 import java.util.ArrayList; 76 77 public class WallpaperPickerActivity extends WallpaperCropActivity { 78 static final String TAG = "Launcher.WallpaperPickerActivity"; 79 80 public static final int IMAGE_PICK = 5; 81 public static final int PICK_WALLPAPER_THIRD_PARTY_ACTIVITY = 6; 82 public static final int PICK_LIVE_WALLPAPER = 7; 83 private static final String TEMP_WALLPAPER_TILES = "TEMP_WALLPAPER_TILES"; 84 85 private View mSelectedThumb; 86 private boolean mIgnoreNextTap; 87 private OnClickListener mThumbnailOnClickListener; 88 89 private LinearLayout mWallpapersView; 90 private View mWallpaperStrip; 91 92 private ActionMode.Callback mActionModeCallback; 93 private ActionMode mActionMode; 94 95 private View.OnLongClickListener mLongClickListener; 96 97 ArrayList<Uri> mTempWallpaperTiles = new ArrayList<Uri>(); 98 private SavedWallpaperImages mSavedImages; 99 private WallpaperInfo mLiveWallpaperInfoOnPickerLaunch; 100 101 public static abstract class WallpaperTileInfo { 102 protected View mView; 103 public void setView(View v) { 104 mView = v; 105 } 106 public void onClick(WallpaperPickerActivity a) {} 107 public void onSave(WallpaperPickerActivity a) {} 108 public void onDelete(WallpaperPickerActivity a) {} 109 public boolean isSelectable() { return false; } 110 public boolean isNamelessWallpaper() { return false; } 111 public void onIndexUpdated(CharSequence label) { 112 if (isNamelessWallpaper()) { 113 mView.setContentDescription(label); 114 } 115 } 116 } 117 118 public static class PickImageInfo extends WallpaperTileInfo { 119 @Override 120 public void onClick(WallpaperPickerActivity a) { 121 Intent intent = new Intent(Intent.ACTION_GET_CONTENT); 122 intent.setType("image/*"); 123 Utilities.startActivityForResultSafely(a, intent, IMAGE_PICK); 124 } 125 } 126 127 public static class UriWallpaperInfo extends WallpaperTileInfo { 128 private Uri mUri; 129 public UriWallpaperInfo(Uri uri) { 130 mUri = uri; 131 } 132 @Override 133 public void onClick(WallpaperPickerActivity a) { 134 CropView v = a.getCropView(); 135 int rotation = WallpaperCropActivity.getRotationFromExif(a, mUri); 136 v.setTileSource(new BitmapRegionTileSource(a, mUri, 1024, rotation), null); 137 v.setTouchEnabled(true); 138 } 139 @Override 140 public void onSave(final WallpaperPickerActivity a) { 141 boolean finishActivityWhenDone = true; 142 OnBitmapCroppedHandler h = new OnBitmapCroppedHandler() { 143 public void onBitmapCropped(byte[] imageBytes) { 144 Point thumbSize = getDefaultThumbnailSize(a.getResources()); 145 // rotation is set to 0 since imageBytes has already been correctly rotated 146 Bitmap thumb = createThumbnail( 147 thumbSize, null, null, imageBytes, null, 0, 0, true); 148 a.getSavedImages().writeImage(thumb, imageBytes); 149 } 150 }; 151 a.cropImageAndSetWallpaper(mUri, h, finishActivityWhenDone); 152 } 153 @Override 154 public boolean isSelectable() { 155 return true; 156 } 157 @Override 158 public boolean isNamelessWallpaper() { 159 return true; 160 } 161 } 162 163 public static class ResourceWallpaperInfo extends WallpaperTileInfo { 164 private Resources mResources; 165 private int mResId; 166 private Drawable mThumb; 167 168 public ResourceWallpaperInfo(Resources res, int resId, Drawable thumb) { 169 mResources = res; 170 mResId = resId; 171 mThumb = thumb; 172 } 173 @Override 174 public void onClick(WallpaperPickerActivity a) { 175 int rotation = WallpaperCropActivity.getRotationFromExif(mResources, mResId); 176 BitmapRegionTileSource source = new BitmapRegionTileSource( 177 mResources, a, mResId, 1024, rotation); 178 CropView v = a.getCropView(); 179 v.setTileSource(source, null); 180 Point wallpaperSize = WallpaperCropActivity.getDefaultWallpaperSize( 181 a.getResources(), a.getWindowManager()); 182 RectF crop = WallpaperCropActivity.getMaxCropRect( 183 source.getImageWidth(), source.getImageHeight(), 184 wallpaperSize.x, wallpaperSize.y, false); 185 v.setScale(wallpaperSize.x / crop.width()); 186 v.setTouchEnabled(false); 187 } 188 @Override 189 public void onSave(WallpaperPickerActivity a) { 190 boolean finishActivityWhenDone = true; 191 a.cropImageAndSetWallpaper(mResources, mResId, finishActivityWhenDone); 192 } 193 @Override 194 public boolean isSelectable() { 195 return true; 196 } 197 @Override 198 public boolean isNamelessWallpaper() { 199 return true; 200 } 201 } 202 203 public void setWallpaperStripYOffset(float offset) { 204 mWallpaperStrip.setPadding(0, 0, 0, (int) offset); 205 } 206 207 // called by onCreate; this is subclassed to overwrite WallpaperCropActivity 208 protected void init() { 209 setContentView(R.layout.wallpaper_picker); 210 211 mCropView = (CropView) findViewById(R.id.cropView); 212 mWallpaperStrip = findViewById(R.id.wallpaper_strip); 213 mCropView.setTouchCallback(new CropView.TouchCallback() { 214 LauncherViewPropertyAnimator mAnim; 215 @Override 216 public void onTouchDown() { 217 if (mAnim != null) { 218 mAnim.cancel(); 219 } 220 if (mWallpaperStrip.getAlpha() == 1f) { 221 mIgnoreNextTap = true; 222 } 223 mAnim = new LauncherViewPropertyAnimator(mWallpaperStrip); 224 mAnim.alpha(0f) 225 .setDuration(150) 226 .addListener(new Animator.AnimatorListener() { 227 public void onAnimationStart(Animator animator) { } 228 public void onAnimationEnd(Animator animator) { 229 mWallpaperStrip.setVisibility(View.INVISIBLE); 230 } 231 public void onAnimationCancel(Animator animator) { } 232 public void onAnimationRepeat(Animator animator) { } 233 }); 234 mAnim.setInterpolator(new AccelerateInterpolator(0.75f)); 235 mAnim.start(); 236 } 237 @Override 238 public void onTouchUp() { 239 mIgnoreNextTap = false; 240 } 241 @Override 242 public void onTap() { 243 boolean ignoreTap = mIgnoreNextTap; 244 mIgnoreNextTap = false; 245 if (!ignoreTap) { 246 if (mAnim != null) { 247 mAnim.cancel(); 248 } 249 mWallpaperStrip.setVisibility(View.VISIBLE); 250 mAnim = new LauncherViewPropertyAnimator(mWallpaperStrip); 251 mAnim.alpha(1f) 252 .setDuration(150) 253 .setInterpolator(new DecelerateInterpolator(0.75f)); 254 mAnim.start(); 255 } 256 } 257 }); 258 259 mThumbnailOnClickListener = new OnClickListener() { 260 public void onClick(View v) { 261 if (mActionMode != null) { 262 // When CAB is up, clicking toggles the item instead 263 if (v.isLongClickable()) { 264 mLongClickListener.onLongClick(v); 265 } 266 return; 267 } 268 WallpaperTileInfo info = (WallpaperTileInfo) v.getTag(); 269 if (info.isSelectable()) { 270 if (mSelectedThumb != null) { 271 mSelectedThumb.setSelected(false); 272 mSelectedThumb = null; 273 } 274 mSelectedThumb = v; 275 v.setSelected(true); 276 // TODO: Remove this once the accessibility framework and 277 // services have better support for selection state. 278 v.announceForAccessibility( 279 getString(R.string.announce_selection, v.getContentDescription())); 280 } 281 info.onClick(WallpaperPickerActivity.this); 282 } 283 }; 284 mLongClickListener = new View.OnLongClickListener() { 285 // Called when the user long-clicks on someView 286 public boolean onLongClick(View view) { 287 CheckableFrameLayout c = (CheckableFrameLayout) view; 288 c.toggle(); 289 290 if (mActionMode != null) { 291 mActionMode.invalidate(); 292 } else { 293 // Start the CAB using the ActionMode.Callback defined below 294 mActionMode = startActionMode(mActionModeCallback); 295 int childCount = mWallpapersView.getChildCount(); 296 for (int i = 0; i < childCount; i++) { 297 mWallpapersView.getChildAt(i).setSelected(false); 298 } 299 } 300 return true; 301 } 302 }; 303 304 // Populate the built-in wallpapers 305 ArrayList<ResourceWallpaperInfo> wallpapers = findBundledWallpapers(); 306 mWallpapersView = (LinearLayout) findViewById(R.id.wallpaper_list); 307 BuiltInWallpapersAdapter ia = new BuiltInWallpapersAdapter(this, wallpapers); 308 populateWallpapersFromAdapter(mWallpapersView, ia, false, true); 309 310 // Populate the saved wallpapers 311 mSavedImages = new SavedWallpaperImages(this); 312 mSavedImages.loadThumbnailsAndImageIdList(); 313 populateWallpapersFromAdapter(mWallpapersView, mSavedImages, true, true); 314 315 // Populate the live wallpapers 316 final LinearLayout liveWallpapersView = 317 (LinearLayout) findViewById(R.id.live_wallpaper_list); 318 final LiveWallpaperListAdapter a = new LiveWallpaperListAdapter(this); 319 a.registerDataSetObserver(new DataSetObserver() { 320 public void onChanged() { 321 liveWallpapersView.removeAllViews(); 322 populateWallpapersFromAdapter(liveWallpapersView, a, false, false); 323 initializeScrollForRtl(); 324 updateTileIndices(); 325 } 326 }); 327 328 // Populate the third-party wallpaper pickers 329 final LinearLayout thirdPartyWallpapersView = 330 (LinearLayout) findViewById(R.id.third_party_wallpaper_list); 331 final ThirdPartyWallpaperPickerListAdapter ta = 332 new ThirdPartyWallpaperPickerListAdapter(this); 333 populateWallpapersFromAdapter(thirdPartyWallpapersView, ta, false, false); 334 335 // Add a tile for the Gallery 336 LinearLayout masterWallpaperList = (LinearLayout) findViewById(R.id.master_wallpaper_list); 337 FrameLayout pickImageTile = (FrameLayout) getLayoutInflater(). 338 inflate(R.layout.wallpaper_picker_image_picker_item, masterWallpaperList, false); 339 setWallpaperItemPaddingToZero(pickImageTile); 340 masterWallpaperList.addView(pickImageTile, 0); 341 342 // Make its background the last photo taken on external storage 343 Bitmap lastPhoto = getThumbnailOfLastPhoto(); 344 if (lastPhoto != null) { 345 ImageView galleryThumbnailBg = 346 (ImageView) pickImageTile.findViewById(R.id.wallpaper_image); 347 galleryThumbnailBg.setImageBitmap(getThumbnailOfLastPhoto()); 348 int colorOverlay = getResources().getColor(R.color.wallpaper_picker_translucent_gray); 349 galleryThumbnailBg.setColorFilter(colorOverlay, PorterDuff.Mode.SRC_ATOP); 350 351 } 352 353 PickImageInfo pickImageInfo = new PickImageInfo(); 354 pickImageTile.setTag(pickImageInfo); 355 pickImageInfo.setView(pickImageTile); 356 pickImageTile.setOnClickListener(mThumbnailOnClickListener); 357 pickImageInfo.setView(pickImageTile); 358 359 updateTileIndices(); 360 361 // Update the scroll for RTL 362 initializeScrollForRtl(); 363 364 // Create smooth layout transitions for when items are deleted 365 final LayoutTransition transitioner = new LayoutTransition(); 366 transitioner.setDuration(200); 367 transitioner.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 0); 368 transitioner.setAnimator(LayoutTransition.DISAPPEARING, null); 369 mWallpapersView.setLayoutTransition(transitioner); 370 371 // Action bar 372 // Show the custom action bar view 373 final ActionBar actionBar = getActionBar(); 374 actionBar.setCustomView(R.layout.actionbar_set_wallpaper); 375 actionBar.getCustomView().setOnClickListener( 376 new View.OnClickListener() { 377 @Override 378 public void onClick(View v) { 379 if (mSelectedThumb != null) { 380 WallpaperTileInfo info = (WallpaperTileInfo) mSelectedThumb.getTag(); 381 info.onSave(WallpaperPickerActivity.this); 382 } 383 } 384 }); 385 386 // CAB for deleting items 387 mActionModeCallback = new ActionMode.Callback() { 388 // Called when the action mode is created; startActionMode() was called 389 @Override 390 public boolean onCreateActionMode(ActionMode mode, Menu menu) { 391 // Inflate a menu resource providing context menu items 392 MenuInflater inflater = mode.getMenuInflater(); 393 inflater.inflate(R.menu.cab_delete_wallpapers, menu); 394 return true; 395 } 396 397 private int numCheckedItems() { 398 int childCount = mWallpapersView.getChildCount(); 399 int numCheckedItems = 0; 400 for (int i = 0; i < childCount; i++) { 401 CheckableFrameLayout c = (CheckableFrameLayout) mWallpapersView.getChildAt(i); 402 if (c.isChecked()) { 403 numCheckedItems++; 404 } 405 } 406 return numCheckedItems; 407 } 408 409 // Called each time the action mode is shown. Always called after onCreateActionMode, 410 // but may be called multiple times if the mode is invalidated. 411 @Override 412 public boolean onPrepareActionMode(ActionMode mode, Menu menu) { 413 int numCheckedItems = numCheckedItems(); 414 if (numCheckedItems == 0) { 415 mode.finish(); 416 return true; 417 } else { 418 mode.setTitle(getResources().getQuantityString( 419 R.plurals.number_of_items_selected, numCheckedItems, numCheckedItems)); 420 return true; 421 } 422 } 423 424 // Called when the user selects a contextual menu item 425 @Override 426 public boolean onActionItemClicked(ActionMode mode, MenuItem item) { 427 int itemId = item.getItemId(); 428 if (itemId == R.id.menu_delete) { 429 int childCount = mWallpapersView.getChildCount(); 430 ArrayList<View> viewsToRemove = new ArrayList<View>(); 431 for (int i = 0; i < childCount; i++) { 432 CheckableFrameLayout c = 433 (CheckableFrameLayout) mWallpapersView.getChildAt(i); 434 if (c.isChecked()) { 435 WallpaperTileInfo info = (WallpaperTileInfo) c.getTag(); 436 info.onDelete(WallpaperPickerActivity.this); 437 viewsToRemove.add(c); 438 } 439 } 440 for (View v : viewsToRemove) { 441 mWallpapersView.removeView(v); 442 } 443 updateTileIndices(); 444 mode.finish(); // Action picked, so close the CAB 445 return true; 446 } else { 447 return false; 448 } 449 } 450 451 // Called when the user exits the action mode 452 @Override 453 public void onDestroyActionMode(ActionMode mode) { 454 int childCount = mWallpapersView.getChildCount(); 455 for (int i = 0; i < childCount; i++) { 456 CheckableFrameLayout c = (CheckableFrameLayout) mWallpapersView.getChildAt(i); 457 c.setChecked(false); 458 } 459 mSelectedThumb.setSelected(true); 460 mActionMode = null; 461 } 462 }; 463 } 464 465 private void initializeScrollForRtl() { 466 final HorizontalScrollView scroll = 467 (HorizontalScrollView) findViewById(R.id.wallpaper_scroll_container); 468 469 if (scroll.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) { 470 final ViewTreeObserver observer = scroll.getViewTreeObserver(); 471 observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { 472 public void onGlobalLayout() { 473 LinearLayout masterWallpaperList = 474 (LinearLayout) findViewById(R.id.master_wallpaper_list); 475 scroll.scrollTo(masterWallpaperList.getWidth(), 0); 476 scroll.getViewTreeObserver().removeOnGlobalLayoutListener(this); 477 } 478 }); 479 } 480 } 481 482 public boolean enableRotation() { 483 return super.enableRotation() || Launcher.sForceEnableRotation; 484 } 485 486 protected Bitmap getThumbnailOfLastPhoto() { 487 Cursor cursor = MediaStore.Images.Media.query(getContentResolver(), 488 MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 489 new String[] { MediaStore.Images.ImageColumns._ID, 490 MediaStore.Images.ImageColumns.DATE_TAKEN}, 491 null, null, MediaStore.Images.ImageColumns.DATE_TAKEN + " DESC LIMIT 1"); 492 Bitmap thumb = null; 493 if (cursor.moveToNext()) { 494 int id = cursor.getInt(0); 495 thumb = MediaStore.Images.Thumbnails.getThumbnail(getContentResolver(), 496 id, MediaStore.Images.Thumbnails.MINI_KIND, null); 497 } 498 cursor.close(); 499 return thumb; 500 } 501 502 protected void onStop() { 503 super.onStop(); 504 mWallpaperStrip = findViewById(R.id.wallpaper_strip); 505 if (mWallpaperStrip.getAlpha() < 1f) { 506 mWallpaperStrip.setAlpha(1f); 507 mWallpaperStrip.setVisibility(View.VISIBLE); 508 } 509 } 510 511 protected void onSaveInstanceState(Bundle outState) { 512 outState.putParcelableArrayList(TEMP_WALLPAPER_TILES, mTempWallpaperTiles); 513 } 514 515 protected void onRestoreInstanceState(Bundle savedInstanceState) { 516 ArrayList<Uri> uris = savedInstanceState.getParcelableArrayList(TEMP_WALLPAPER_TILES); 517 for (Uri uri : uris) { 518 addTemporaryWallpaperTile(uri); 519 } 520 } 521 522 private void populateWallpapersFromAdapter(ViewGroup parent, BaseAdapter adapter, 523 boolean addLongPressHandler, boolean selectFirstTile) { 524 for (int i = 0; i < adapter.getCount(); i++) { 525 FrameLayout thumbnail = (FrameLayout) adapter.getView(i, null, parent); 526 parent.addView(thumbnail, i); 527 WallpaperTileInfo info = (WallpaperTileInfo) adapter.getItem(i); 528 thumbnail.setTag(info); 529 info.setView(thumbnail); 530 if (addLongPressHandler) { 531 addLongPressHandler(thumbnail); 532 } 533 thumbnail.setOnClickListener(mThumbnailOnClickListener); 534 if (i == 0 && selectFirstTile) { 535 mThumbnailOnClickListener.onClick(thumbnail); 536 } 537 } 538 } 539 540 private void updateTileIndices() { 541 LinearLayout masterWallpaperList = (LinearLayout) findViewById(R.id.master_wallpaper_list); 542 final int childCount = masterWallpaperList.getChildCount(); 543 final Resources res = getResources(); 544 545 // Do two passes; the first pass gets the total number of tiles 546 int numTiles = 0; 547 for (int passNum = 0; passNum < 2; passNum++) { 548 int tileIndex = 0; 549 for (int i = 0; i < childCount; i++) { 550 View child = masterWallpaperList.getChildAt(i); 551 LinearLayout subList; 552 553 int subListStart; 554 int subListEnd; 555 if (child.getTag() instanceof WallpaperTileInfo) { 556 subList = masterWallpaperList; 557 subListStart = i; 558 subListEnd = i + 1; 559 } else { // if (child instanceof LinearLayout) { 560 subList = (LinearLayout) child; 561 subListStart = 0; 562 subListEnd = subList.getChildCount(); 563 } 564 565 for (int j = subListStart; j < subListEnd; j++) { 566 WallpaperTileInfo info = (WallpaperTileInfo) subList.getChildAt(j).getTag(); 567 if (info.isNamelessWallpaper()) { 568 if (passNum == 0) { 569 numTiles++; 570 } else { 571 CharSequence label = res.getString( 572 R.string.wallpaper_accessibility_name, ++tileIndex, numTiles); 573 info.onIndexUpdated(label); 574 } 575 } 576 } 577 } 578 } 579 } 580 581 private static Point getDefaultThumbnailSize(Resources res) { 582 return new Point(res.getDimensionPixelSize(R.dimen.wallpaperThumbnailWidth), 583 res.getDimensionPixelSize(R.dimen.wallpaperThumbnailHeight)); 584 585 } 586 587 private static Bitmap createThumbnail(Point size, Context context, Uri uri, byte[] imageBytes, 588 Resources res, int resId, int rotation, boolean leftAligned) { 589 int width = size.x; 590 int height = size.y; 591 592 BitmapCropTask cropTask; 593 if (uri != null) { 594 cropTask = new BitmapCropTask( 595 context, uri, null, rotation, width, height, false, true, null); 596 } else if (imageBytes != null) { 597 cropTask = new BitmapCropTask( 598 imageBytes, null, rotation, width, height, false, true, null); 599 } else { 600 cropTask = new BitmapCropTask( 601 context, res, resId, null, rotation, width, height, false, true, null); 602 } 603 Point bounds = cropTask.getImageBounds(); 604 if (bounds == null || bounds.x == 0 || bounds.y == 0) { 605 return null; 606 } 607 608 Matrix rotateMatrix = new Matrix(); 609 rotateMatrix.setRotate(rotation); 610 float[] rotatedBounds = new float[] { bounds.x, bounds.y }; 611 rotateMatrix.mapPoints(rotatedBounds); 612 rotatedBounds[0] = Math.abs(rotatedBounds[0]); 613 rotatedBounds[1] = Math.abs(rotatedBounds[1]); 614 615 RectF cropRect = WallpaperCropActivity.getMaxCropRect( 616 (int) rotatedBounds[0], (int) rotatedBounds[1], width, height, leftAligned); 617 cropTask.setCropBounds(cropRect); 618 619 if (cropTask.cropBitmap()) { 620 return cropTask.getCroppedBitmap(); 621 } else { 622 return null; 623 } 624 } 625 626 private void addTemporaryWallpaperTile(Uri uri) { 627 mTempWallpaperTiles.add(uri); 628 // Add a tile for the image picked from Gallery 629 FrameLayout pickedImageThumbnail = (FrameLayout) getLayoutInflater(). 630 inflate(R.layout.wallpaper_picker_item, mWallpapersView, false); 631 setWallpaperItemPaddingToZero(pickedImageThumbnail); 632 633 // Load the thumbnail 634 ImageView image = (ImageView) pickedImageThumbnail.findViewById(R.id.wallpaper_image); 635 Point defaultSize = getDefaultThumbnailSize(this.getResources()); 636 int rotation = WallpaperCropActivity.getRotationFromExif(this, uri); 637 Bitmap thumb = createThumbnail(defaultSize, this, uri, null, null, 0, rotation, false); 638 if (thumb != null) { 639 image.setImageBitmap(thumb); 640 Drawable thumbDrawable = image.getDrawable(); 641 thumbDrawable.setDither(true); 642 } else { 643 Log.e(TAG, "Error loading thumbnail for uri=" + uri); 644 } 645 mWallpapersView.addView(pickedImageThumbnail, 0); 646 647 UriWallpaperInfo info = new UriWallpaperInfo(uri); 648 pickedImageThumbnail.setTag(info); 649 info.setView(pickedImageThumbnail); 650 addLongPressHandler(pickedImageThumbnail); 651 updateTileIndices(); 652 pickedImageThumbnail.setOnClickListener(mThumbnailOnClickListener); 653 mThumbnailOnClickListener.onClick(pickedImageThumbnail); 654 } 655 656 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 657 if (requestCode == IMAGE_PICK && resultCode == RESULT_OK) { 658 if (data != null && data.getData() != null) { 659 Uri uri = data.getData(); 660 addTemporaryWallpaperTile(uri); 661 } 662 } else if (requestCode == PICK_WALLPAPER_THIRD_PARTY_ACTIVITY) { 663 setResult(RESULT_OK); 664 finish(); 665 } else if (requestCode == PICK_LIVE_WALLPAPER) { 666 WallpaperManager wm = WallpaperManager.getInstance(this); 667 final WallpaperInfo oldLiveWallpaper = mLiveWallpaperInfoOnPickerLaunch; 668 WallpaperInfo newLiveWallpaper = wm.getWallpaperInfo(); 669 // Try to figure out if a live wallpaper was set; 670 if (newLiveWallpaper != null && 671 (oldLiveWallpaper == null || 672 !oldLiveWallpaper.getComponent().equals(newLiveWallpaper.getComponent()))) { 673 // Return if a live wallpaper was set 674 setResult(RESULT_OK); 675 finish(); 676 } 677 } 678 } 679 680 static void setWallpaperItemPaddingToZero(FrameLayout frameLayout) { 681 frameLayout.setPadding(0, 0, 0, 0); 682 frameLayout.setForeground(new ZeroPaddingDrawable(frameLayout.getForeground())); 683 } 684 685 private void addLongPressHandler(View v) { 686 v.setOnLongClickListener(mLongClickListener); 687 } 688 689 private ArrayList<ResourceWallpaperInfo> findBundledWallpapers() { 690 ArrayList<ResourceWallpaperInfo> bundledWallpapers = 691 new ArrayList<ResourceWallpaperInfo>(24); 692 693 Pair<ApplicationInfo, Integer> r = getWallpaperArrayResourceId(); 694 if (r != null) { 695 try { 696 Resources wallpaperRes = getPackageManager().getResourcesForApplication(r.first); 697 bundledWallpapers = addWallpapers(wallpaperRes, r.first.packageName, r.second); 698 } catch (PackageManager.NameNotFoundException e) { 699 } 700 } 701 702 // Add an entry for the default wallpaper (stored in system resources) 703 ResourceWallpaperInfo defaultWallpaperInfo = getDefaultWallpaperInfo(); 704 if (defaultWallpaperInfo != null) { 705 bundledWallpapers.add(0, defaultWallpaperInfo); 706 } 707 return bundledWallpapers; 708 } 709 710 private ResourceWallpaperInfo getDefaultWallpaperInfo() { 711 Resources sysRes = Resources.getSystem(); 712 int resId = sysRes.getIdentifier("default_wallpaper", "drawable", "android"); 713 714 File defaultThumbFile = new File(getFilesDir(), "default_thumb.jpg"); 715 Bitmap thumb = null; 716 boolean defaultWallpaperExists = false; 717 if (defaultThumbFile.exists()) { 718 thumb = BitmapFactory.decodeFile(defaultThumbFile.getAbsolutePath()); 719 defaultWallpaperExists = true; 720 } else { 721 Resources res = getResources(); 722 Point defaultThumbSize = getDefaultThumbnailSize(res); 723 int rotation = WallpaperCropActivity.getRotationFromExif(res, resId); 724 thumb = createThumbnail( 725 defaultThumbSize, this, null, null, sysRes, resId, rotation, false); 726 if (thumb != null) { 727 try { 728 defaultThumbFile.createNewFile(); 729 FileOutputStream thumbFileStream = 730 openFileOutput(defaultThumbFile.getName(), Context.MODE_PRIVATE); 731 thumb.compress(Bitmap.CompressFormat.JPEG, 95, thumbFileStream); 732 thumbFileStream.close(); 733 defaultWallpaperExists = true; 734 } catch (IOException e) { 735 Log.e(TAG, "Error while writing default wallpaper thumbnail to file " + e); 736 defaultThumbFile.delete(); 737 } 738 } 739 } 740 if (defaultWallpaperExists) { 741 return new ResourceWallpaperInfo(sysRes, resId, new BitmapDrawable(thumb)); 742 } 743 return null; 744 } 745 746 public Pair<ApplicationInfo, Integer> getWallpaperArrayResourceId() { 747 // Context.getPackageName() may return the "original" package name, 748 // com.android.launcher3; Resources needs the real package name, 749 // com.android.launcher3. So we ask Resources for what it thinks the 750 // package name should be. 751 final String packageName = getResources().getResourcePackageName(R.array.wallpapers); 752 try { 753 ApplicationInfo info = getPackageManager().getApplicationInfo(packageName, 0); 754 return new Pair<ApplicationInfo, Integer>(info, R.array.wallpapers); 755 } catch (PackageManager.NameNotFoundException e) { 756 return null; 757 } 758 } 759 760 private ArrayList<ResourceWallpaperInfo> addWallpapers( 761 Resources res, String packageName, int listResId) { 762 ArrayList<ResourceWallpaperInfo> bundledWallpapers = 763 new ArrayList<ResourceWallpaperInfo>(24); 764 final String[] extras = res.getStringArray(listResId); 765 for (String extra : extras) { 766 int resId = res.getIdentifier(extra, "drawable", packageName); 767 if (resId != 0) { 768 final int thumbRes = res.getIdentifier(extra + "_small", "drawable", packageName); 769 770 if (thumbRes != 0) { 771 ResourceWallpaperInfo wallpaperInfo = 772 new ResourceWallpaperInfo(res, resId, res.getDrawable(thumbRes)); 773 bundledWallpapers.add(wallpaperInfo); 774 // Log.d(TAG, "add: [" + packageName + "]: " + extra + " (" + res + ")"); 775 } 776 } else { 777 Log.e(TAG, "Couldn't find wallpaper " + extra); 778 } 779 } 780 return bundledWallpapers; 781 } 782 783 public CropView getCropView() { 784 return mCropView; 785 } 786 787 public SavedWallpaperImages getSavedImages() { 788 return mSavedImages; 789 } 790 791 public void onLiveWallpaperPickerLaunch() { 792 mLiveWallpaperInfoOnPickerLaunch = WallpaperManager.getInstance(this).getWallpaperInfo(); 793 } 794 795 static class ZeroPaddingDrawable extends LevelListDrawable { 796 public ZeroPaddingDrawable(Drawable d) { 797 super(); 798 addLevel(0, 0, d); 799 setLevel(0); 800 } 801 802 @Override 803 public boolean getPadding(Rect padding) { 804 padding.set(0, 0, 0, 0); 805 return true; 806 } 807 } 808 809 private static class BuiltInWallpapersAdapter extends BaseAdapter implements ListAdapter { 810 private LayoutInflater mLayoutInflater; 811 private ArrayList<ResourceWallpaperInfo> mWallpapers; 812 813 BuiltInWallpapersAdapter(Activity activity, ArrayList<ResourceWallpaperInfo> wallpapers) { 814 mLayoutInflater = activity.getLayoutInflater(); 815 mWallpapers = wallpapers; 816 } 817 818 public int getCount() { 819 return mWallpapers.size(); 820 } 821 822 public ResourceWallpaperInfo getItem(int position) { 823 return mWallpapers.get(position); 824 } 825 826 public long getItemId(int position) { 827 return position; 828 } 829 830 public View getView(int position, View convertView, ViewGroup parent) { 831 Drawable thumb = mWallpapers.get(position).mThumb; 832 if (thumb == null) { 833 Log.e(TAG, "Error decoding thumbnail for wallpaper #" + position); 834 } 835 return createImageTileView(mLayoutInflater, position, convertView, parent, thumb); 836 } 837 } 838 839 public static View createImageTileView(LayoutInflater layoutInflater, int position, 840 View convertView, ViewGroup parent, Drawable thumb) { 841 View view; 842 843 if (convertView == null) { 844 view = layoutInflater.inflate(R.layout.wallpaper_picker_item, parent, false); 845 } else { 846 view = convertView; 847 } 848 849 setWallpaperItemPaddingToZero((FrameLayout) view); 850 851 ImageView image = (ImageView) view.findViewById(R.id.wallpaper_image); 852 853 if (thumb != null) { 854 image.setImageDrawable(thumb); 855 thumb.setDither(true); 856 } 857 858 return view; 859 } 860 } 861