1 /* 2 * Copyright (C) 2009 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.cooliris.media; 18 19 import java.util.ArrayList; 20 import java.util.List; 21 22 import javax.microedition.khronos.opengles.GL11; 23 24 import android.app.Activity; 25 import android.app.AlertDialog; 26 import android.content.ComponentName; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.pm.ActivityInfo; 30 import android.content.pm.PackageManager; 31 import android.content.pm.ResolveInfo; 32 import android.content.res.Resources; 33 import android.net.Uri; 34 import android.provider.MediaStore; 35 import android.util.FloatMath; 36 import android.view.MotionEvent; 37 38 import com.cooliris.app.App; 39 import com.cooliris.app.Res; 40 import com.cooliris.media.MenuBar.Menu; 41 import com.cooliris.media.PopupMenu.Option; 42 43 public final class HudLayer extends Layer { 44 public static final int MODE_NORMAL = 0; 45 public static final int MODE_SELECT = 1; 46 47 private Context mContext; 48 private GridLayer mGridLayer; 49 private final ImageButton mTopRightButton = new ImageButton(); 50 private final ImageButton mZoomInButton = new ImageButton(); 51 private final ImageButton mZoomOutButton = new ImageButton(); 52 private PathBarLayer mPathBar; 53 private TimeBar mTimeBar; 54 private MenuBar.Menu[] mNormalBottomMenu = null; 55 private MenuBar.Menu[] mSingleViewIntentBottomMenu = null; 56 private MenuBar.Menu[] mNormalBottomMenuNoShare = null; 57 private MenuBar.Menu[] mSingleViewIntentBottomMenuNoShare = null; 58 private final MenuBar mSelectionMenuBottom; 59 private final MenuBar mSelectionMenuTop; 60 private final MenuBar mFullscreenMenu; 61 private final LoadingLayer mLoadingLayer = new LoadingLayer(); 62 private RenderView mView = null; 63 64 private int mMode = MODE_NORMAL; 65 66 // Camera button - launches the camera intent when pressed. 67 private static final int CAMERA_BUTTON_ICON = Res.drawable.btn_camera; 68 private static final int CAMERA_BUTTON_ICON_PRESSED = Res.drawable.btn_camera_pressed; 69 private static final int ZOOM_IN_ICON = Res.drawable.gallery_zoom_in; 70 private static final int ZOOM_IN_ICON_PRESSED = Res.drawable.gallery_zoom_in_touch; 71 private static final int ZOOM_OUT_ICON = Res.drawable.gallery_zoom_out; 72 private static final int ZOOM_OUT_ICON_PRESSED = Res.drawable.gallery_zoom_out_touch; 73 74 private final Runnable mCameraButtonAction = new Runnable() { 75 public void run() { 76 // Launch the camera intent. 77 Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA); 78 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 79 mContext.startActivity(intent); 80 } 81 }; 82 83 // Grid mode button - switches the media browser to grid mode. 84 private static final int GRID_MODE_ICON = Res.drawable.mode_stack; 85 private static final int GRID_MODE_PRESSED_ICON = Res.drawable.mode_stack; 86 87 private final Runnable mZoomInButtonAction = new Runnable() { 88 public void run() { 89 mGridLayer.zoomInToSelectedItem(); 90 mGridLayer.markDirty(1); 91 } 92 }; 93 94 private final Runnable mZoomOutButtonAction = new Runnable() { 95 public void run() { 96 mGridLayer.zoomOutFromSelectedItem(); 97 mGridLayer.markDirty(1); 98 } 99 }; 100 101 private final Runnable mGridModeButtonAction = new Runnable() { 102 public void run() { 103 mGridLayer.setState(GridLayer.STATE_GRID_VIEW); 104 } 105 }; 106 107 /** 108 * Stack mode button - switches the media browser to grid mode. 109 */ 110 private static final int STACK_MODE_ICON = Res.drawable.mode_grid; 111 private static final int STACK_MODE_PRESSED_ICON = Res.drawable.mode_grid; 112 private final Runnable mStackModeButtonAction = new Runnable() { 113 public void run() { 114 mGridLayer.setState(GridLayer.STATE_TIMELINE); 115 } 116 }; 117 private float mAlpha; 118 private float mAnimAlpha; 119 private boolean mAutoHide; 120 private long mLastTimeFullOpacity; 121 private String mCachedCaption; 122 private String mCachedPosition; 123 private String mCachedCurrentLabel; 124 125 HudLayer(Context context) { 126 mAlpha = 1.0f; 127 if (mTimeBar == null) { 128 mTimeBar = new TimeBar(context); 129 mPathBar = new PathBarLayer(); 130 } 131 mTopRightButton.setSize((int) (100 * App.PIXEL_DENSITY), (int) (94 * App.PIXEL_DENSITY)); 132 133 mZoomInButton.setSize(66.666f * App.PIXEL_DENSITY, 42 * App.PIXEL_DENSITY); 134 mZoomOutButton.setSize(66.666f * App.PIXEL_DENSITY, 42 * App.PIXEL_DENSITY); 135 mZoomInButton.setImages(ZOOM_IN_ICON, ZOOM_IN_ICON_PRESSED); 136 mZoomInButton.setAction(mZoomInButtonAction); 137 mZoomOutButton.setImages(ZOOM_OUT_ICON, ZOOM_OUT_ICON_PRESSED); 138 mZoomOutButton.setAction(mZoomOutButtonAction); 139 140 // The Share submenu is populated dynamically when opened. 141 Resources resources = context.getResources(); 142 PopupMenu.Option[] deleteOptions = { 143 new PopupMenu.Option(context.getResources().getString(Res.string.confirm_delete), resources 144 .getDrawable(Res.drawable.icon_delete), new Runnable() { 145 public void run() { 146 deleteSelection(); 147 } 148 }), 149 new PopupMenu.Option(context.getResources().getString(Res.string.cancel), resources 150 .getDrawable(Res.drawable.icon_cancel), new Runnable() { 151 public void run() { 152 153 } 154 }), }; 155 mSelectionMenuBottom = new MenuBar(context); 156 157 MenuBar.Menu shareMenu = new MenuBar.Menu.Builder(context.getResources().getString(Res.string.share)).icon( 158 Res.drawable.icon_share).onSelect(new Runnable() { 159 public void run() { 160 updateShareMenu(); 161 } 162 }).build(); 163 164 MenuBar.Menu deleteMenu = new MenuBar.Menu.Builder(context.getResources().getString(Res.string.delete)).icon( 165 Res.drawable.icon_delete).options(deleteOptions).build(); 166 167 MenuBar.Menu moreMenu = new MenuBar.Menu.Builder(context.getResources().getString(Res.string.more)).icon( 168 Res.drawable.icon_more).onSelect(new Runnable() { 169 public void run() { 170 buildMoreOptions(); 171 } 172 }).build(); 173 174 mNormalBottomMenu = new MenuBar.Menu[] { shareMenu, deleteMenu, moreMenu }; 175 mSingleViewIntentBottomMenu = new MenuBar.Menu[] { shareMenu, moreMenu }; 176 177 mNormalBottomMenuNoShare = new MenuBar.Menu[] { deleteMenu, moreMenu }; 178 mSingleViewIntentBottomMenuNoShare = new MenuBar.Menu[] { moreMenu }; 179 180 mSelectionMenuBottom.setMenus(mNormalBottomMenu); 181 mSelectionMenuTop = new MenuBar(context); 182 mSelectionMenuTop.setMenus(new MenuBar.Menu[] { 183 new MenuBar.Menu.Builder(context.getResources().getString(Res.string.select_all)).onSelect(new Runnable() { 184 public void run() { 185 mGridLayer.selectAll(); 186 } 187 }).build(), new MenuBar.Menu.Builder("").build(), 188 new MenuBar.Menu.Builder(context.getResources().getString(Res.string.deselect_all)).onSelect(new Runnable() { 189 public void run() { 190 mGridLayer.deselectOrCancelSelectMode(); 191 } 192 }).build() }); 193 mFullscreenMenu = new MenuBar(context); 194 mFullscreenMenu.setMenus(new MenuBar.Menu[] { 195 new MenuBar.Menu.Builder(context.getResources().getString(Res.string.slideshow)).icon(Res.drawable.icon_play) 196 .onSingleTapUp(new Runnable() { 197 public void run() { 198 if (getAlpha() == 1.0f) 199 mGridLayer.startSlideshow(); 200 else 201 setAlpha(1.0f); 202 } 203 }).build(), /* new MenuBar.Menu.Builder("").build(), */ 204 new MenuBar.Menu.Builder(context.getResources().getString(Res.string.menu)).icon(Res.drawable.icon_more) 205 .onSingleTapUp(new Runnable() { 206 public void run() { 207 if (getAlpha() == 1.0f) 208 mGridLayer.enterSelectionMode(); 209 else 210 setAlpha(1.0f); 211 } 212 }).build() }); 213 } 214 215 public void setContext(Context context) { 216 if (mContext != context) { 217 mContext = context; 218 mTimeBar.regenerateStringsForContext(context); 219 } 220 } 221 222 private void buildMoreOptions() { 223 ArrayList<MediaBucket> buckets = mGridLayer.getSelectedBuckets(); 224 225 int numBuckets = buckets.size(); 226 boolean albumMode = false; 227 boolean singleItem = false; 228 boolean isPicasa = false; 229 int mediaType = MediaItem.MEDIA_TYPE_IMAGE; 230 if (numBuckets > 1) { 231 albumMode = true; 232 } 233 if (numBuckets == 1) { 234 MediaBucket bucket = buckets.get(0); 235 MediaSet mediaSet = bucket.mediaSet; 236 if (mediaSet == null) { 237 return; 238 } 239 isPicasa = mediaSet.mPicasaAlbumId != Shared.INVALID; 240 if (bucket.mediaItems == null || bucket.mediaItems.size() == 0) { 241 albumMode = true; 242 } else { 243 ArrayList<MediaItem> items = bucket.mediaItems; 244 int numItems = items.size(); 245 mediaType = items.get(0).getMediaType(); 246 if (numItems == 1) { 247 singleItem = true; 248 } else { 249 for (int i = 1; i < numItems; ++i) { 250 if (items.get(0).getMediaType() != mediaType) { 251 albumMode = true; 252 break; 253 } 254 } 255 } 256 } 257 } 258 259 Option[] optionAll = new Option[] { new PopupMenu.Option(mContext.getResources().getString(Res.string.details), mContext 260 .getResources().getDrawable(Res.drawable.ic_menu_view_details), new Runnable() { 261 public void run() { 262 ArrayList<MediaBucket> buckets = mGridLayer.getSelectedBuckets(); 263 final AlertDialog.Builder builder = new AlertDialog.Builder(mContext); 264 builder.setTitle(mContext.getResources().getString(Res.string.details)); 265 boolean foundDataToDisplay = true; 266 267 if (buckets == null) { 268 foundDataToDisplay = false; 269 } else { 270 CharSequence[] strings = DetailMode.populateDetailModeStrings(mContext, buckets); 271 if (strings == null) { 272 foundDataToDisplay = false; 273 } else { 274 builder.setItems(strings, null); 275 } 276 } 277 278 mGridLayer.deselectAll(); 279 if (foundDataToDisplay) { 280 builder.setNeutralButton(Res.string.details_ok, null); 281 App.get(mContext).getHandler().post(new Runnable() { 282 public void run() { 283 builder.show(); 284 } 285 }); 286 } 287 } 288 }) }; 289 290 Option[] optionSingle = new Option[] { new PopupMenu.Option(mContext.getResources().getString(Res.string.show_on_map), 291 mContext.getResources().getDrawable(Res.drawable.ic_menu_mapmode), new Runnable() { 292 public void run() { 293 ArrayList<MediaBucket> buckets = mGridLayer.getSelectedBuckets(); 294 MediaItem item = MediaBucketList.getFirstItemSelection(buckets); 295 if (item == null) { 296 return; 297 } 298 mGridLayer.deselectAll(); 299 Util.openMaps(mContext, item.mLatitude, item.mLongitude); 300 } 301 }), }; 302 303 Option[] optionImageMultiple = new Option[] { 304 new PopupMenu.Option(mContext.getResources().getString(Res.string.rotate_left), mContext.getResources() 305 .getDrawable(Res.drawable.ic_menu_rotate_left), new Runnable() { 306 public void run() { 307 mGridLayer.rotateSelectedItems(-90.0f); 308 } 309 }), 310 new PopupMenu.Option(mContext.getResources().getString(Res.string.rotate_right), mContext.getResources() 311 .getDrawable(Res.drawable.ic_menu_rotate_right), new Runnable() { 312 public void run() { 313 mGridLayer.rotateSelectedItems(90.0f); 314 } 315 }), }; 316 317 if (isPicasa) { 318 optionImageMultiple = new Option[] {}; 319 } 320 Option[] optionImageSingle; 321 if (isPicasa) { 322 optionImageSingle = new Option[] { new PopupMenu.Option(mContext.getResources().getString(Res.string.set_as_wallpaper), 323 mContext.getResources().getDrawable(Res.drawable.ic_menu_set_as), new Runnable() { 324 public void run() { 325 ArrayList<MediaBucket> buckets = mGridLayer.getSelectedBuckets(); 326 MediaItem item = MediaBucketList.getFirstItemSelection(buckets); 327 if (item == null) { 328 return; 329 } 330 mGridLayer.deselectAll(); 331 if (item.mParentMediaSet.mPicasaAlbumId != Shared.INVALID) { 332 final Intent intent = new Intent("android.intent.action.ATTACH_DATA"); 333 intent.setClass(mContext, Photographs.class); 334 intent.setData(Uri.parse(item.mContentUri)); 335 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 336 ((Activity) mContext).startActivityForResult(intent, 0); 337 } 338 } 339 }) }; 340 } else { 341 optionImageSingle = new Option[] { 342 new PopupMenu.Option((isPicasa) ? mContext.getResources().getString(Res.string.set_as_wallpaper) : mContext 343 .getResources().getString(Res.string.set_as), mContext.getResources().getDrawable( 344 Res.drawable.ic_menu_set_as), new Runnable() { 345 public void run() { 346 ArrayList<MediaBucket> buckets = mGridLayer.getSelectedBuckets(); 347 MediaItem item = MediaBucketList.getFirstItemSelection(buckets); 348 if (item == null) { 349 return; 350 } 351 mGridLayer.deselectAll(); 352 if (item.mParentMediaSet.mPicasaAlbumId != Shared.INVALID) { 353 final Intent intent = new Intent("android.intent.action.ATTACH_DATA"); 354 intent.setClass(mContext, Photographs.class); 355 intent.setData(Uri.parse(item.mContentUri)); 356 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 357 ((Activity) mContext).startActivityForResult(intent, 0); 358 } else { 359 Intent intent = Util.createSetAsIntent(Uri.parse(item.mContentUri), item.mMimeType); 360 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 361 ((Activity) mContext).startActivity(Intent.createChooser(intent, mContext 362 .getText(Res.string.set_image))); 363 } 364 } 365 }), 366 new PopupMenu.Option(mContext.getResources().getString(Res.string.crop), mContext.getResources().getDrawable( 367 Res.drawable.ic_menu_crop), new Runnable() { 368 public void run() { 369 ArrayList<MediaBucket> buckets = mGridLayer.getSelectedBuckets(); 370 MediaItem item = MediaBucketList.getFirstItemSelection(buckets); 371 if (item == null) { 372 return; 373 } 374 mGridLayer.deselectAll(); 375 final Intent intent = new Intent("com.android.camera.action.CROP"); 376 intent.setClass(mContext, CropImage.class); 377 intent.setData(Uri.parse(item.mContentUri)); 378 ((Activity) mContext).startActivityForResult(intent, CropImage.CROP_MSG_INTERNAL); 379 } 380 }) }; 381 } 382 Option[] options = optionAll; 383 if (!albumMode) { 384 if (!singleItem) { 385 if (mediaType == MediaItem.MEDIA_TYPE_IMAGE) 386 options = concat(options, optionImageMultiple); 387 } else { 388 MediaItem item = MediaBucketList.getFirstItemSelection(buckets); 389 if (item.mLatitude != 0.0f && item.mLongitude != 0.0f) { 390 options = concat(options, optionSingle); 391 } 392 if (mediaType == MediaItem.MEDIA_TYPE_IMAGE) { 393 options = concat(options, optionImageSingle); 394 options = concat(options, optionImageMultiple); 395 } 396 } 397 } 398 399 // We are assuming that the more menu is the last item in the menu 400 // array. 401 int lastIndex = mSelectionMenuBottom.getMenus().length - 1; 402 mSelectionMenuBottom.getMenus()[lastIndex].options = options; 403 } 404 405 private static final Option[] concat(Option[] A, Option[] B) { 406 Option[] C = (Option[]) new Option[A.length + B.length]; 407 System.arraycopy(A, 0, C, 0, A.length); 408 System.arraycopy(B, 0, C, A.length, B.length); 409 return C; 410 } 411 412 public void updateNumItemsSelected(int numItems) { 413 String items = " " + ((numItems == 1) ? mContext.getString(Res.string.item) : mContext.getString(Res.string.items)); 414 Menu menu = new MenuBar.Menu.Builder(numItems + items).config(MenuBar.MENU_TITLE_STYLE_TEXT).build(); 415 mSelectionMenuTop.updateMenu(menu, 1); 416 } 417 418 protected void deleteSelection() { 419 mGridLayer.deleteSelection(); 420 } 421 422 void setGridLayer(GridLayer layer) { 423 mGridLayer = layer; 424 updateViews(); 425 } 426 427 int getMode() { 428 return mMode; 429 } 430 431 void setMode(int mode) { 432 if (mMode != mode) { 433 mMode = mode; 434 updateViews(); 435 } 436 } 437 438 @Override 439 protected void onSizeChanged() { 440 final float width = mWidth; 441 final float height = mHeight; 442 closeSelectionMenu(); 443 444 mTimeBar.setPosition(0f, height - TimeBar.HEIGHT * App.PIXEL_DENSITY); 445 mTimeBar.setSize(width, TimeBar.HEIGHT * App.PIXEL_DENSITY); 446 mSelectionMenuTop.setPosition(0f, 0); 447 mSelectionMenuTop.setSize(width, MenuBar.HEIGHT * App.PIXEL_DENSITY); 448 mSelectionMenuBottom.setPosition(0f, height - MenuBar.HEIGHT * App.PIXEL_DENSITY); 449 mSelectionMenuBottom.setSize(width, MenuBar.HEIGHT * App.PIXEL_DENSITY); 450 451 mFullscreenMenu.setPosition(0f, height - MenuBar.HEIGHT * App.PIXEL_DENSITY); 452 mFullscreenMenu.setSize(width, MenuBar.HEIGHT * App.PIXEL_DENSITY); 453 454 mPathBar.setPosition(0f, -4f * App.PIXEL_DENSITY); 455 computeSizeForPathbar(); 456 457 mTopRightButton.setPosition(width - mTopRightButton.getWidth(), 0f); 458 float zoomY = height - MenuBar.HEIGHT * App.PIXEL_DENSITY - mZoomInButton.getHeight(); 459 mZoomInButton.setPosition(width - mZoomInButton.getWidth(), zoomY); 460 mZoomOutButton.setPosition(width - mZoomInButton.getWidth() * 2.0f, zoomY); 461 } 462 463 private void computeSizeForPathbar() { 464 float pathBarWidth = mWidth 465 - ((mGridLayer.getState() == GridLayer.STATE_FULL_SCREEN) ? 32 * App.PIXEL_DENSITY : 120 * App.PIXEL_DENSITY); 466 mPathBar.setSize(pathBarWidth, FloatMath.ceil(39 * App.PIXEL_DENSITY)); 467 mPathBar.recomputeComponents(); 468 } 469 470 public void setFeed(MediaFeed feed, int state, boolean needsLayout) { 471 mTimeBar.setFeed(feed, state, needsLayout); 472 } 473 474 public void onGridStateChanged() { 475 updateViews(); 476 } 477 478 private void updateViews() { 479 if (mGridLayer == null) 480 return; 481 final int state = mGridLayer.getState(); 482 // Show the selection menu in selection mode. 483 final boolean selectionMode = mMode == MODE_SELECT; 484 final boolean fullscreenMode = state == GridLayer.STATE_FULL_SCREEN; 485 final boolean stackMode = state == GridLayer.STATE_MEDIA_SETS || state == GridLayer.STATE_TIMELINE; 486 mSelectionMenuTop.setHidden(!selectionMode || fullscreenMode); 487 mSelectionMenuBottom.setHidden(!selectionMode); 488 mFullscreenMenu.setHidden(!fullscreenMode || selectionMode); 489 mZoomInButton.setHidden(mFullscreenMenu.isHidden()); 490 mZoomOutButton.setHidden(mFullscreenMenu.isHidden()); 491 492 // Show the time bar in stack and grid states, except in selection mode. 493 mTimeBar.setHidden(fullscreenMode || selectionMode || stackMode); 494 // mTimeBar.setHidden(selectionMode || (state != 495 // GridLayer.STATE_TIMELINE && state != GridLayer.STATE_GRID_VIEW)); 496 497 // Hide the path bar and top-right button in selection mode. 498 mPathBar.setHidden(selectionMode); 499 mTopRightButton.setHidden(selectionMode || fullscreenMode); 500 computeSizeForPathbar(); 501 502 // Configure the top-right button. 503 int image = 0; 504 int pressedImage = 0; 505 Runnable action = null; 506 final ImageButton topRightButton = mTopRightButton; 507 int height = (int) (94 * App.PIXEL_DENSITY); 508 switch (state) { 509 case GridLayer.STATE_MEDIA_SETS: 510 image = CAMERA_BUTTON_ICON; 511 pressedImage = CAMERA_BUTTON_ICON_PRESSED; 512 action = mCameraButtonAction; 513 break; 514 case GridLayer.STATE_GRID_VIEW: 515 height /= 2; 516 image = STACK_MODE_ICON; 517 pressedImage = STACK_MODE_PRESSED_ICON; 518 action = mStackModeButtonAction; 519 break; 520 case GridLayer.STATE_TIMELINE: 521 image = GRID_MODE_ICON; 522 pressedImage = GRID_MODE_PRESSED_ICON; 523 action = mGridModeButtonAction; 524 break; 525 case GridLayer.STATE_FULL_SCREEN: 526 if (getGridLayer() != null && getGridLayer().getFeed() != null 527 && getGridLayer().getFeed().getExpandedMediaSet() != null) { 528 if (getGridLayer().getFeed().getExpandedMediaSet().mId == LocalDataSource.CAMERA_BUCKET_ID) { 529 image = CAMERA_BUTTON_ICON; 530 pressedImage = CAMERA_BUTTON_ICON_PRESSED; 531 action = mCameraButtonAction; 532 topRightButton.setHidden(false); 533 } 534 } 535 break; 536 default: 537 break; 538 } 539 topRightButton.setSize((int) (100 * App.PIXEL_DENSITY), height); 540 topRightButton.setImages(image, pressedImage); 541 topRightButton.setAction(action); 542 } 543 544 public TimeBar getTimeBar() { 545 return mTimeBar; 546 } 547 548 public PathBarLayer getPathBar() { 549 return mPathBar; 550 } 551 552 public GridLayer getGridLayer() { 553 return mGridLayer; 554 } 555 556 @Override 557 public boolean update(RenderView view, float frameInterval) { 558 float factor = 1.0f; 559 if (mAlpha == 1.0f) { 560 // Speed up the animation when it becomes visible. 561 factor = 4.0f; 562 } 563 mAnimAlpha = FloatUtils.animate(mAnimAlpha, mAlpha, frameInterval * factor); 564 565 if (mAutoHide) { 566 if (mAlpha == 1.0f && mMode != MODE_SELECT) { 567 long now = System.currentTimeMillis(); 568 if (now - mLastTimeFullOpacity >= 5000) { 569 setAlpha(0); 570 } 571 } 572 } 573 574 return (mAnimAlpha != mAlpha); 575 } 576 577 public void renderOpaque(RenderView view, GL11 gl) { 578 579 } 580 581 public void renderBlended(RenderView view, GL11 gl) { 582 view.setAlpha(mAnimAlpha); 583 } 584 585 public void setAlpha(float alpha) { 586 float oldAlpha = mAlpha; 587 mAlpha = alpha; 588 if (oldAlpha != alpha) { 589 if (mView != null) 590 mView.requestRender(); 591 } 592 593 // We try to invoke update() again in 5 seconds to see if 594 // auto hide is needed. 595 if (alpha == 1.0f) { 596 mLastTimeFullOpacity = System.currentTimeMillis(); 597 App.get(mContext).getHandler().postDelayed(new Runnable() { 598 public void run() { 599 if (mView != null) { 600 mView.requestRender(); 601 } 602 } 603 }, 5000); 604 } 605 } 606 607 public float getAlpha() { 608 return mAlpha; 609 } 610 611 public void setTimeBarTime(long time) { 612 // mTimeBar.setTime(time); 613 } 614 615 @Override 616 public void generate(RenderView view, RenderView.Lists lists) { 617 lists.opaqueList.add(this); 618 lists.blendedList.add(this); 619 lists.hitTestList.add(this); 620 lists.updateList.add(this); 621 mTopRightButton.generate(view, lists); 622 mZoomInButton.generate(view, lists); 623 mZoomOutButton.generate(view, lists); 624 mTimeBar.generate(view, lists); 625 mSelectionMenuTop.generate(view, lists); 626 mSelectionMenuBottom.generate(view, lists); 627 mFullscreenMenu.generate(view, lists); 628 mPathBar.generate(view, lists); 629 // mLoadingLayer.generate(view, lists); 630 mView = view; 631 } 632 633 @Override 634 public boolean containsPoint(float x, float y) { 635 return false; 636 } 637 638 public void cancelSelection() { 639 mSelectionMenuBottom.close(); 640 closeSelectionMenu(); 641 setMode(MODE_NORMAL); 642 } 643 644 public void closeSelectionMenu() { 645 mSelectionMenuBottom.close(); 646 } 647 648 @Override 649 public boolean onTouchEvent(MotionEvent event) { 650 if (mMode == MODE_SELECT) { 651 /* 652 * setMode(MODE_NORMAL); ArrayList<MediaBucket> displayBuckets = 653 * mGridLayer.getSelectedBuckets(); // use this list, and then clear 654 * the items return true; 655 */ 656 return false; 657 } else { 658 return false; 659 } 660 } 661 662 public boolean isLoaded() { 663 return mLoadingLayer.isLoaded(); 664 } 665 666 void reset() { 667 mLoadingLayer.reset(); 668 mTimeBar.regenerateStringsForContext(mContext); 669 } 670 671 public void fullscreenSelectionChanged(MediaItem item, int index, int count) { 672 // request = new ReverseGeocoder.Request(); 673 // request.firstLatitude = request.secondLatitude = item.latitude; 674 // request.firstLongitude = request.secondLongitude = item.longitude; 675 // mGeo.enqueue(request); 676 if (item == null) 677 return; 678 String location = index + "/" + count; 679 mCachedCaption = item.mCaption; 680 mCachedPosition = location; 681 mCachedCurrentLabel = location; 682 mPathBar.changeLabel(location); 683 } 684 685 private void updateShareMenu() { 686 // Get the first selected item. Wire this up to multiple-item intents 687 // when we move 688 // to Eclair. 689 ArrayList<MediaBucket> selection = mGridLayer.getSelectedBuckets(); 690 ArrayList<Uri> uris = new ArrayList<Uri>(); 691 String mimeType = null; 692 if (!selection.isEmpty()) { 693 int mediaType = Shared.INVALID; 694 int numBuckets = selection.size(); 695 for (int j = 0; j < numBuckets; ++j) { 696 MediaBucket bucket = selection.get(j); 697 ArrayList<MediaItem> items = null; 698 int numItems = 0; 699 if (bucket.mediaItems != null && !bucket.mediaItems.isEmpty()) { 700 items = bucket.mediaItems; 701 numItems = items.size(); 702 } else if (bucket.mediaSet != null) { 703 // We need to delete the entire bucket. 704 items = bucket.mediaSet.getItems(); 705 numItems = bucket.mediaSet.getNumItems(); 706 } 707 for (int i = 0; i < numItems; ++i) { 708 MediaItem item = items.get(i); 709 if (mimeType == null) { 710 mimeType = item.mMimeType; 711 mediaType = item.getMediaType(); 712 MediaSet parentMediaSet = item.mParentMediaSet; 713 if (parentMediaSet != null && parentMediaSet.mPicasaAlbumId != Shared.INVALID) { 714 // This will go away once http uri's are supported 715 // for all media types. 716 // This ensures that just the link is shared as a 717 // text 718 mimeType = "text/plain"; 719 } 720 } 721 // Ensure that the media type remains the same 722 if (mediaType != item.getMediaType()) { 723 if (!mimeType.contains("text")) 724 mimeType = "*/*"; 725 } 726 // add this uri 727 if (item.mContentUri != null) { 728 Uri uri = Uri.parse(item.mContentUri); 729 uris.add(uri); 730 } 731 } 732 } 733 } 734 PopupMenu.Option[] options = null; 735 if (uris.size() != 0) { 736 final Intent intent = new Intent(); 737 if (mimeType == null) 738 mimeType = "image/jpeg"; 739 if (mimeType.contains("text")) { 740 // We need to share this as a text string. 741 intent.setAction(Intent.ACTION_SEND); 742 intent.setType(mimeType); 743 744 // Create a newline-separated list of URLs. 745 StringBuilder builder = new StringBuilder(); 746 for (int i = 0, size = uris.size(); i < size; ++i) { 747 builder.append(uris.get(i)); 748 if (i != size - 1) { 749 builder.append('\n'); 750 } 751 } 752 intent.putExtra(Intent.EXTRA_TEXT, builder.toString()); 753 } else { 754 if (uris.size() == 1) { 755 intent.setAction(Intent.ACTION_SEND); 756 intent.putExtra(Intent.EXTRA_STREAM, uris.get(0)); 757 } else { 758 intent.setAction(Intent.ACTION_SEND_MULTIPLE); 759 intent.putExtra(Intent.EXTRA_STREAM, uris); 760 } 761 intent.setType(mimeType); 762 } 763 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 764 765 // Query the system for matching activities. 766 PackageManager packageManager = mContext.getPackageManager(); 767 List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0); 768 int numActivities = activities.size(); 769 options = new PopupMenu.Option[numActivities]; 770 for (int i = 0; i != numActivities; ++i) { 771 final ResolveInfo info = activities.get(i); 772 String label = info.loadLabel(packageManager).toString(); 773 options[i] = new PopupMenu.Option(label, info.loadIcon(packageManager), new Runnable() { 774 public void run() { 775 startResolvedActivity(intent, info); 776 } 777 }); 778 } 779 } 780 mSelectionMenuBottom.getMenus()[0].options = options; 781 } 782 783 private void startResolvedActivity(Intent intent, ResolveInfo info) { 784 final Intent resolvedIntent = new Intent(intent); 785 ActivityInfo ai = info.activityInfo; 786 resolvedIntent.setComponent(new ComponentName(ai.applicationInfo.packageName, ai.name)); 787 App.get(mContext).getHandler().post(new Runnable() { 788 public void run() { 789 mContext.startActivity(resolvedIntent); 790 } 791 }); 792 } 793 794 public void autoHide(boolean hide) { 795 mAutoHide = hide; 796 } 797 798 public void swapFullscreenLabel() { 799 mCachedCurrentLabel = (mCachedCurrentLabel == mCachedCaption || mCachedCaption == null) ? mCachedPosition : mCachedCaption; 800 mPathBar.changeLabel(mCachedCurrentLabel); 801 } 802 803 public void clear() { 804 805 } 806 807 public void enterSelectionMode() { 808 // Do not enter selection mode if the feed is about to change. 809 if (mGridLayer.feedAboutToChange()) 810 return; 811 // Disable sharing if it is the pick intent. 812 if (mGridLayer.getPickIntent()) { 813 mSingleViewIntentBottomMenu = mSingleViewIntentBottomMenuNoShare; 814 mNormalBottomMenu = mNormalBottomMenuNoShare; 815 } 816 setAlpha(1.0f); 817 setMode(HudLayer.MODE_SELECT); 818 // if we are in single view mode, show the bottom menu without the 819 // delete button. 820 if (mGridLayer.noDeleteMode()) { 821 mSelectionMenuBottom.setMenus(mSingleViewIntentBottomMenu); 822 } else { 823 mSelectionMenuBottom.setMenus(mNormalBottomMenu); 824 } 825 } 826 827 public void computeBottomMenu() { 828 // we need to the same for picasa albums 829 ArrayList<MediaBucket> selection = mGridLayer.getSelectedBuckets(); 830 Menu[] menus = mSelectionMenuBottom.getMenus(); 831 if (menus == mSingleViewIntentBottomMenu) 832 return; 833 int numBuckets = selection.size(); 834 for (int i = 0; i < numBuckets; ++i) { 835 MediaBucket bucket = selection.get(i); 836 if (bucket == null || bucket.mediaSet == null) 837 continue; 838 if (bucket.mediaSet.mPicasaAlbumId != Shared.INVALID) { 839 mSelectionMenuBottom.setMenus(mSingleViewIntentBottomMenu); 840 break; 841 } 842 } 843 } 844 845 public Layer getMenuBar() { 846 return mFullscreenMenu; 847 } 848 849 public void hideZoomButtons(boolean hide) { 850 mZoomInButton.setHidden(hide); 851 mZoomOutButton.setHidden(hide); 852 } 853 } 854