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