1f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein/* 2f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * Copyright (C) 2011 Google Inc. 3f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * Licensed to The Android Open Source Project. 4f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * 5f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * Licensed under the Apache License, Version 2.0 (the "License"); 6f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * you may not use this file except in compliance with the License. 7f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * You may obtain a copy of the License at 8f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * 9f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * http://www.apache.org/licenses/LICENSE-2.0 10f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * 11f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * Unless required by applicable law or agreed to in writing, software 12f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * distributed under the License is distributed on an "AS IS" BASIS, 13f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * See the License for the specific language governing permissions and 15f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * limitations under the License. 16f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein */ 17f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 18f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinpackage com.android.ex.photo; 19f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 20112d29fe9f30d1237a1c8ac1ecc3740879c8c9cePaul Westbrookimport android.app.ActionBar; 21112d29fe9f30d1237a1c8ac1ecc3740879c8c9cePaul Westbrookimport android.app.ActionBar.OnMenuVisibilityListener; 22f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.app.Activity; 23f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.app.ActivityManager; 2499f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdonimport android.content.Context; 25f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.content.Intent; 2629e47d946fd19443c12ebad9f94e83741c7d9120Paul Westbrookimport android.content.res.Resources; 27f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.database.Cursor; 28ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport android.graphics.Bitmap; 29ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport android.graphics.drawable.BitmapDrawable; 30f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.net.Uri; 311abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sappersteinimport android.os.Build; 32f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.os.Bundle; 33f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.os.Handler; 348746927a945358bb9e515985a37cac7807261026Martin Hibdonimport android.support.v4.app.Fragment; 35112d29fe9f30d1237a1c8ac1ecc3740879c8c9cePaul Westbrookimport android.support.v4.app.FragmentActivity; 368746927a945358bb9e515985a37cac7807261026Martin Hibdonimport android.support.v4.app.LoaderManager; 378746927a945358bb9e515985a37cac7807261026Martin Hibdonimport android.support.v4.content.Loader; 38f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.support.v4.view.ViewPager.OnPageChangeListener; 39bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Coppimport android.view.MenuItem; 40112d29fe9f30d1237a1c8ac1ecc3740879c8c9cePaul Westbrook 41ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport android.text.TextUtils; 42ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport android.util.Log; 43f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.view.View; 44ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport android.view.ViewPropertyAnimator; 45ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport android.view.ViewTreeObserver.OnGlobalLayoutListener; 46ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport android.view.animation.AlphaAnimation; 47ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport android.view.animation.Animation; 48ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport android.view.animation.AnimationSet; 49ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport android.view.animation.ScaleAnimation; 50ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport android.view.animation.TranslateAnimation; 51ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport android.view.animation.Animation.AnimationListener; 52ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport android.widget.ImageView; 53ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 54f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.PhotoViewPager.InterceptType; 55f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.PhotoViewPager.OnInterceptTouchListener; 56f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.adapters.PhotoPagerAdapter; 570c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sappersteinimport com.android.ex.photo.fragments.PhotoViewFragment; 58ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport com.android.ex.photo.loaders.PhotoBitmapLoader; 59ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport com.android.ex.photo.loaders.PhotoBitmapLoaderInterface.BitmapResult; 60f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.loaders.PhotoPagerLoader; 61f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.provider.PhotoContract; 62f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 6379bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Weiimport java.util.HashMap; 64f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport java.util.HashSet; 6579bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Weiimport java.util.Map; 66f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport java.util.Set; 67f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 68f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein/** 69f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * Activity to view the contents of an album. 70f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein */ 71112d29fe9f30d1237a1c8ac1ecc3740879c8c9cePaul Westbrookpublic class PhotoViewActivity extends FragmentActivity implements 728746927a945358bb9e515985a37cac7807261026Martin Hibdon LoaderManager.LoaderCallbacks<Cursor>, OnPageChangeListener, OnInterceptTouchListener, 73399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon OnMenuVisibilityListener, PhotoViewCallbacks { 740c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein 75ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private final static String TAG = "PhotoViewActivity"; 76ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 77ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private final static String STATE_CURRENT_URI_KEY = 78ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon "com.google.android.apps.plus.PhotoViewFragment.CURRENT_URI"; 79ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private final static String STATE_CURRENT_INDEX_KEY = 80ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon "com.google.android.apps.plus.PhotoViewFragment.CURRENT_INDEX"; 81f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein private final static String STATE_FULLSCREEN_KEY = 82f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein "com.google.android.apps.plus.PhotoViewFragment.FULLSCREEN"; 837b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal private final static String STATE_ACTIONBARTITLE_KEY = 848670cefb043f865c7275876dcc94f65ce5bda041Martin Hibdon "com.google.android.apps.plus.PhotoViewFragment.ACTIONBARTITLE"; 857b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal private final static String STATE_ACTIONBARSUBTITLE_KEY = 868670cefb043f865c7275876dcc94f65ce5bda041Martin Hibdon "com.google.android.apps.plus.PhotoViewFragment.ACTIONBARTITLE"; 87ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private final static String STATE_ENTERANIMATIONFINISHED_KEY = 88ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon "com.google.android.apps.plus.PhotoViewFragment.SCALEANIMATIONFINISHED"; 89f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 90ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected final static String ARG_IMAGE_URI = "image_uri"; 91ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 92ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private static final int LOADER_PHOTO_LIST = 100; 93f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 94f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** Count used when the real photo count is unknown [but, may be determined] */ 95f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public static final int ALBUM_COUNT_UNKNOWN = -1; 96f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 97ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public static final int ENTER_ANIMATION_DURATION_MS = 250; 98ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public static final int EXIT_ANIMATION_DURATION_MS = 250; 99ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 100f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** Argument key for the dialog message */ 101f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public static final String KEY_MESSAGE = "dialog_message"; 102f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 103f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public static int sMemoryClass; 104f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 105f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** The URI of the photos we're viewing; may be {@code null} */ 106f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein private String mPhotosUri; 107f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** The index of the currently viewed photo */ 108ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private int mCurrentPhotoIndex; 109ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon /** The uri of the currently viewed photo */ 110ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private String mCurrentPhotoUri; 111f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** The query projection to use; may be {@code null} */ 112f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein private String[] mProjection; 113f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** The total number of photos; only valid if {@link #mIsEmpty} is {@code false}. */ 114ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected int mAlbumCount = ALBUM_COUNT_UNKNOWN; 115f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** {@code true} if the view is empty. Otherwise, {@code false}. */ 116ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected boolean mIsEmpty; 11799f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon /** the main root view */ 11899f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon protected View mRootView; 119ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon /** Background image that contains nothing, so it can be alpha faded from 120ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon * transparent to black without affecting any other views. */ 121ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected View mBackground; 122f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** The main pager; provides left/right swipe between photos */ 12399f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon protected PhotoViewPager mViewPager; 124ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon /** The temporary image so that we can quickly scale up the fullscreen thumbnail */ 125ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected ImageView mTemporaryImage; 126f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** Adapter to create pager views */ 12799f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon protected PhotoPagerAdapter mAdapter; 128f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** Whether or not we're in "full screen" mode */ 129ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected boolean mFullScreen; 13079bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei /** The listeners wanting full screen state for each screen position */ 131ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private final Map<Integer, OnScreenListener> 13279bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei mScreenListeners = new HashMap<Integer, OnScreenListener>(); 1330c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein /** The set of listeners wanting full screen state */ 134ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private final Set<CursorChangedListener> mCursorListeners = new HashSet<CursorChangedListener>(); 135f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** When {@code true}, restart the loader when the activity becomes active */ 136f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein private boolean mRestartLoader; 137f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** Whether or not this activity is paused */ 138ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected boolean mIsPaused = true; 13991dbfd25cc234de393ae22fc39a832a6335e1bc2Adam Copp /** The maximum scale factor applied to images when they are initially displayed */ 140ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected float mMaxInitialScale; 1417b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal /** The title in the actionbar */ 142ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected String mActionBarTitle; 1437b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal /** The subtitle in the actionbar */ 144ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected String mActionBarSubtitle; 145ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 146ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private boolean mEnterAnimationFinished; 147ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected boolean mScaleAnimationEnabled; 148ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected int mAnimationStartX; 149ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected int mAnimationStartY; 150ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected int mAnimationStartWidth; 151ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected int mAnimationStartHeight; 152ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 153ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected boolean mActionBarHiddenInitially; 154ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected boolean mDisplayThumbsFullScreen; 155ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 156ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected BitmapCallback mBitmapCallback; 157ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected final Handler mHandler = new Handler(); 1587b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal 159f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein // TODO Find a better way to do this. We basically want the activity to display the 160f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein // "loading..." progress until the fragment takes over and shows it's own "loading..." 161f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein // progress [located in photo_header_view.xml]. We could potentially have all status displayed 162f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein // by the activity, but, that gets tricky when it comes to screen rotation. For now, we 163f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein // track the loading by this variable which is fragile and may cause phantom "loading..." 164f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein // text. 16540a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook private long mEnterFullScreenDelayTime; 166f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 167ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 16899f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon protected PhotoPagerAdapter createPhotoPagerAdapter(Context context, 16999f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon android.support.v4.app.FragmentManager fm, Cursor c, float maxScale) { 170ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon PhotoPagerAdapter adapter = new PhotoPagerAdapter(context, fm, c, maxScale, 171ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mDisplayThumbsFullScreen); 172ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon return adapter; 17399f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon } 17499f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon 175f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein @Override 176f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein protected void onCreate(Bundle savedInstanceState) { 177f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein super.onCreate(savedInstanceState); 178f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 179f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein final ActivityManager mgr = (ActivityManager) getApplicationContext(). 180f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein getSystemService(Activity.ACTIVITY_SERVICE); 181f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein sMemoryClass = mgr.getMemoryClass(); 182f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 183ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final Intent intent = getIntent(); 184f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein // uri of the photos to view; optional 185ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (intent.hasExtra(Intents.EXTRA_PHOTOS_URI)) { 186ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mPhotosUri = intent.getStringExtra(Intents.EXTRA_PHOTOS_URI); 187ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 188ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (intent.getBooleanExtra(Intents.EXTRA_SCALE_UP_ANIMATION, false)) { 189ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mScaleAnimationEnabled = true; 190ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mAnimationStartX = intent.getIntExtra(Intents.EXTRA_ANIMATION_START_X, 0); 191ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mAnimationStartY = intent.getIntExtra(Intents.EXTRA_ANIMATION_START_Y, 0); 192ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mAnimationStartWidth = intent.getIntExtra(Intents.EXTRA_ANIMATION_START_WIDTH, 0); 193ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mAnimationStartHeight = intent.getIntExtra(Intents.EXTRA_ANIMATION_START_HEIGHT, 0); 194f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 195ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mActionBarHiddenInitially = intent.getBooleanExtra( 196ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon Intents.EXTRA_ACTION_BAR_HIDDEN_INITIALLY, false); 197ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mDisplayThumbsFullScreen = intent.getBooleanExtra( 198ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon Intents.EXTRA_DISPLAY_THUMBS_FULLSCREEN, false); 199f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 200f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein // projection for the query; optional 20141db3eb9741a222432b367409c67d2263856a0a7Vikram Aggarwal // If not set, the default projection is used. 202f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein // This projection must include the columns from the default projection. 203ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (intent.hasExtra(Intents.EXTRA_PROJECTION)) { 204ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mProjection = intent.getStringArrayExtra(Intents.EXTRA_PROJECTION); 205f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } else { 206f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein mProjection = null; 207f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 208f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 20991dbfd25cc234de393ae22fc39a832a6335e1bc2Adam Copp // Set the max initial scale, defaulting to 1x 210ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mMaxInitialScale = intent.getFloatExtra(Intents.EXTRA_MAX_INITIAL_SCALE, 1.0f); 211ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mCurrentPhotoUri = null; 212ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mCurrentPhotoIndex = -1; 213ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 214ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // We allow specifying the current photo by either index or uri. 215ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // This is because some users may have live datasets that can change, 216ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // adding new items to either the beginning or end of the set. For clients 217ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // that do not need that capability, ability to specify the current photo 218ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // by index is offered as a convenience. 219ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (intent.hasExtra(Intents.EXTRA_PHOTO_INDEX)) { 220ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mCurrentPhotoIndex = intent.getIntExtra(Intents.EXTRA_PHOTO_INDEX, -1); 221ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 222ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (intent.hasExtra(Intents.EXTRA_INITIAL_PHOTO_URI)) { 223ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mCurrentPhotoUri = intent.getStringExtra(Intents.EXTRA_INITIAL_PHOTO_URI); 224ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 22579bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei mIsEmpty = true; 226f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 227ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (savedInstanceState != null) { 228ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mCurrentPhotoUri = savedInstanceState.getString(STATE_CURRENT_URI_KEY); 229ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mCurrentPhotoIndex = savedInstanceState.getInt(STATE_CURRENT_INDEX_KEY); 230ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mFullScreen = savedInstanceState.getBoolean(STATE_FULLSCREEN_KEY, false); 231ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mActionBarTitle = savedInstanceState.getString(STATE_ACTIONBARTITLE_KEY); 232ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mActionBarSubtitle = savedInstanceState.getString(STATE_ACTIONBARSUBTITLE_KEY); 233ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mEnterAnimationFinished = savedInstanceState.getBoolean( 234ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon STATE_ENTERANIMATIONFINISHED_KEY, false); 235ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else { 236ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mFullScreen = mActionBarHiddenInitially; 237ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 238ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 239f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein setContentView(R.layout.photo_activity_view); 240f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 241f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein // Create the adapter and add the view pager 24241db3eb9741a222432b367409c67d2263856a0a7Vikram Aggarwal mAdapter = 24341db3eb9741a222432b367409c67d2263856a0a7Vikram Aggarwal createPhotoPagerAdapter(this, getSupportFragmentManager(), null, mMaxInitialScale); 244fd925449925f3eb6e2ab6e1c50203c4a4bc165b2Paul Westbrook final Resources resources = getResources(); 24599f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon mRootView = findViewById(R.id.photo_activity_root_view); 246ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mBackground = findViewById(R.id.photo_activity_background); 247ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mTemporaryImage = (ImageView) findViewById(R.id.photo_activity_temporary_image); 248f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein mViewPager = (PhotoViewPager) findViewById(R.id.photo_view_pager); 249efd51fc103301ca5e6e6eb3825623f50d0497b62Adam Copp mViewPager.setAdapter(mAdapter); 250f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein mViewPager.setOnPageChangeListener(this); 251f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein mViewPager.setOnInterceptTouchListener(this); 252fd925449925f3eb6e2ab6e1c50203c4a4bc165b2Paul Westbrook mViewPager.setPageMargin(resources.getDimensionPixelSize(R.dimen.photo_page_margin)); 253f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 254ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mBitmapCallback = new BitmapCallback(); 255ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (!mScaleAnimationEnabled || mEnterAnimationFinished) { 256ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // We are not running the scale up animation. Just let the fragments 257ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // display and handle the animation. 258ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon getSupportLoaderManager().initLoader(LOADER_PHOTO_LIST, null, this); 2591fabec882499ed0dd14d8dc7458445fa986ef14dMartin Hibdon // Make the background opaque immediately so that we don't see the activity 2601fabec882499ed0dd14d8dc7458445fa986ef14dMartin Hibdon // behind this one. 2611fabec882499ed0dd14d8dc7458445fa986ef14dMartin Hibdon mBackground.setVisibility(View.VISIBLE); 262ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else { 263ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // Attempt to load the initial image thumbnail. Once we have the 264ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // image, animate it up. Once the animation is complete, we can kick off 26518c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon // loading the ViewPager. After the primary fullres image is loaded, we will 26618c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon // make our temporary image invisible and display the ViewPager. 267ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mViewPager.setVisibility(View.GONE); 268ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon Bundle args = new Bundle(); 269ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon args.putString(ARG_IMAGE_URI, mCurrentPhotoUri); 270ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon getSupportLoaderManager().initLoader(BITMAP_LOADER_THUMBNAIL, args, mBitmapCallback); 271ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 272f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 27340a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook mEnterFullScreenDelayTime = 27440a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook resources.getInteger(R.integer.reenter_fullscreen_delay_time_in_millis); 27540a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook 276112d29fe9f30d1237a1c8ac1ecc3740879c8c9cePaul Westbrook final ActionBar actionBar = getActionBar(); 27799f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon if (actionBar != null) { 27899f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon actionBar.setDisplayHomeAsUpEnabled(true); 27999f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon actionBar.addOnMenuVisibilityListener(this); 2807b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal final int showTitle = ActionBar.DISPLAY_SHOW_TITLE; 2817b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal actionBar.setDisplayOptions(showTitle, showTitle); 282ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // Set the title and subtitle immediately here, rather than waiting 283ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // for the fragment to be initialized. 2847b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal setActionBarTitles(actionBar); 28599f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon } 286ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 287ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon setLightsOutMode(mFullScreen); 288f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 289f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 290f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein @Override 291f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein protected void onResume() { 292f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein super.onResume(); 293f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein setFullScreen(mFullScreen, false); 294f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 295f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein mIsPaused = false; 296f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (mRestartLoader) { 297f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein mRestartLoader = false; 2988746927a945358bb9e515985a37cac7807261026Martin Hibdon getSupportLoaderManager().restartLoader(LOADER_PHOTO_LIST, null, this); 299f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 300f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 301f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 302f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein @Override 303f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein protected void onPause() { 304f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein mIsPaused = true; 305f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein super.onPause(); 306f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 307f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 308f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein @Override 309f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public void onBackPressed() { 310ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // If we are in fullscreen mode, and the default is not full screen, then 311ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // switch back to actionBar display mode. 312ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (mFullScreen && !mActionBarHiddenInitially) { 313f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein toggleFullScreen(); 314f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } else { 315ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (mScaleAnimationEnabled) { 316ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon runExitAnimation(); 317ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else { 318ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon super.onBackPressed(); 319ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 320f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 321f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 322f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 323f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein @Override 324f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public void onSaveInstanceState(Bundle outState) { 325f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein super.onSaveInstanceState(outState); 326f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 327ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon outState.putString(STATE_CURRENT_URI_KEY, mCurrentPhotoUri); 328ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon outState.putInt(STATE_CURRENT_INDEX_KEY, mCurrentPhotoIndex); 329f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein outState.putBoolean(STATE_FULLSCREEN_KEY, mFullScreen); 3307b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal outState.putString(STATE_ACTIONBARTITLE_KEY, mActionBarTitle); 3317b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal outState.putString(STATE_ACTIONBARSUBTITLE_KEY, mActionBarSubtitle); 3321fabec882499ed0dd14d8dc7458445fa986ef14dMartin Hibdon outState.putBoolean(STATE_ENTERANIMATIONFINISHED_KEY, mEnterAnimationFinished); 333f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 334f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 335bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp @Override 336bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp public boolean onOptionsItemSelected(MenuItem item) { 337bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp switch (item.getItemId()) { 338bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp case android.R.id.home: 339bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp finish(); 340ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon return true; 341bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp default: 342bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp return super.onOptionsItemSelected(item); 343bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } 344bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } 345bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp 346399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon @Override 34779bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei public void addScreenListener(int position, OnScreenListener listener) { 34879bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei mScreenListeners.put(position, listener); 349f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 350f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 351399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon @Override 35279bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei public void removeScreenListener(int position) { 35379bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei mScreenListeners.remove(position); 354f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 355f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 356399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon @Override 3570c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein public synchronized void addCursorListener(CursorChangedListener listener) { 3580c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein mCursorListeners.add(listener); 3590c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein } 3600c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein 361399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon @Override 3620c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein public synchronized void removeCursorListener(CursorChangedListener listener) { 3630c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein mCursorListeners.remove(listener); 3640c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein } 3650c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein 366399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon @Override 367f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public boolean isFragmentFullScreen(Fragment fragment) { 368f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (mViewPager == null || mAdapter == null || mAdapter.getCount() == 0) { 369f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return mFullScreen; 370f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 371f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return mFullScreen || (mViewPager.getCurrentItem() != mAdapter.getItemPosition(fragment)); 372f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 373f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 374399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon @Override 375f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public void toggleFullScreen() { 376f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein setFullScreen(!mFullScreen, true); 377f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 378f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 379f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public void onPhotoRemoved(long photoId) { 380f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein final Cursor data = mAdapter.getCursor(); 381f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (data == null) { 382f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein // Huh?! How would this happen? 383f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return; 384f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 385f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 386f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein final int dataCount = data.getCount(); 387f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (dataCount <= 1) { 388f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein finish(); 389f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return; 390f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 391f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 3928746927a945358bb9e515985a37cac7807261026Martin Hibdon getSupportLoaderManager().restartLoader(LOADER_PHOTO_LIST, null, this); 393f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 394f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 395f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein @Override 396f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public Loader<Cursor> onCreateLoader(int id, Bundle args) { 397f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (id == LOADER_PHOTO_LIST) { 398f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return new PhotoPagerLoader(this, Uri.parse(mPhotosUri), mProjection); 399f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 400f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return null; 401f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 402f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 403f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein @Override 404ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public Loader<BitmapResult> onCreateBitmapLoader(int id, Bundle args, String uri) { 405ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon switch (id) { 406ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon case BITMAP_LOADER_AVATAR: 407ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon case BITMAP_LOADER_THUMBNAIL: 408ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon case BITMAP_LOADER_PHOTO: 409ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon return new PhotoBitmapLoader(this, uri); 410ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon default: 411ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon return null; 412ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 413ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 414ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 415ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon @Override 416ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 417ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 418f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein final int id = loader.getId(); 419f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (id == LOADER_PHOTO_LIST) { 420f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (data == null || data.getCount() == 0) { 421f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein mIsEmpty = true; 422f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } else { 423f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein mAlbumCount = data.getCount(); 424ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (mCurrentPhotoUri != null) { 42599f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon int index = 0; 426ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // Clear query params. Compare only the path. 4271ccbed89981c3bda94d7ee301c1053b3bb747e15Martin Hibdon final int uriIndex = data.getColumnIndex(PhotoContract.PhotoViewColumns.URI); 428fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat final Uri currentPhotoUri; 429fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { 430fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat currentPhotoUri = Uri.parse(mCurrentPhotoUri).buildUpon() 431fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat .clearQuery().build(); 432fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat } else { 433fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat currentPhotoUri = Uri.parse(mCurrentPhotoUri).buildUpon() 434fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat .query(null).build(); 435fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat } 43699f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon while (data.moveToNext()) { 437fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat final String uriString = data.getString(uriIndex); 438fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat final Uri uri; 439fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { 440fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat uri = Uri.parse(uriString).buildUpon().clearQuery().build(); 441fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat } else { 442fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat uri = Uri.parse(uriString).buildUpon().query(null).build(); 443fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat } 444ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (currentPhotoUri != null && currentPhotoUri.equals(uri)) { 445ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mCurrentPhotoIndex = index; 44699f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon break; 44799f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon } 44899f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon index++; 44999f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon } 45099f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon } 45199f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon 452e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook // We're paused; don't do anything now, we'll get re-invoked 453e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook // when the activity becomes active again 454e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook // TODO(pwestbro): This shouldn't be necessary, as the loader manager should 455e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook // restart the loader 456e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook if (mIsPaused) { 457e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook mRestartLoader = true; 458e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook return; 459e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook } 46079bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei boolean wasEmpty = mIsEmpty; 461e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook mIsEmpty = false; 462e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook 4634a6a7183e0740dfb305a16676c867e182aced7aaAdam Copp mAdapter.swapCursor(data); 46499f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon if (mViewPager.getAdapter() == null) { 46599f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon mViewPager.setAdapter(mAdapter); 46699f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon } 4674a6a7183e0740dfb305a16676c867e182aced7aaAdam Copp notifyCursorListeners(data); 4684a6a7183e0740dfb305a16676c867e182aced7aaAdam Copp 469e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook // Use an index of 0 if the index wasn't specified or couldn't be found 470ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (mCurrentPhotoIndex < 0) { 471ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mCurrentPhotoIndex = 0; 472e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook } 473e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook 474ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mViewPager.setCurrentItem(mCurrentPhotoIndex, false); 47579bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei if (wasEmpty) { 476ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon setViewActivated(mCurrentPhotoIndex); 47779bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei } 478f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 4792989cf0c8e4b0aee4c9ac2b5384a392fd74cd6a9Paul Westbrook // Update the any action items 4802989cf0c8e4b0aee4c9ac2b5384a392fd74cd6a9Paul Westbrook updateActionItems(); 481f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 482f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 483f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 4848746927a945358bb9e515985a37cac7807261026Martin Hibdon @Override 4858746927a945358bb9e515985a37cac7807261026Martin Hibdon public void onLoaderReset(android.support.v4.content.Loader<Cursor> loader) { 4868746927a945358bb9e515985a37cac7807261026Martin Hibdon // If the loader is reset, remove the reference in the adapter to this cursor 4878746927a945358bb9e515985a37cac7807261026Martin Hibdon // TODO(pwestbro): reenable this when b/7075236 is fixed 4888746927a945358bb9e515985a37cac7807261026Martin Hibdon // mAdapter.swapCursor(null); 4898746927a945358bb9e515985a37cac7807261026Martin Hibdon } 4908746927a945358bb9e515985a37cac7807261026Martin Hibdon 4912989cf0c8e4b0aee4c9ac2b5384a392fd74cd6a9Paul Westbrook protected void updateActionItems() { 4922989cf0c8e4b0aee4c9ac2b5384a392fd74cd6a9Paul Westbrook // Do nothing, but allow extending classes to do work 4932989cf0c8e4b0aee4c9ac2b5384a392fd74cd6a9Paul Westbrook } 4942989cf0c8e4b0aee4c9ac2b5384a392fd74cd6a9Paul Westbrook 4950c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein private synchronized void notifyCursorListeners(Cursor data) { 4960c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein // tell all of the objects listening for cursor changes 4970c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein // that the cursor has changed 4980c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein for (CursorChangedListener listener : mCursorListeners) { 4990c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein listener.onCursorChanged(data); 5000c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein } 5010c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein } 5020c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein 503f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein @Override 504f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 505f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 506f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 507f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein @Override 508f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public void onPageSelected(int position) { 509ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mCurrentPhotoIndex = position; 51079bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei setViewActivated(position); 511f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 512f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 513f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein @Override 514f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public void onPageScrollStateChanged(int state) { 515f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 516f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 517399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon @Override 518f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public boolean isFragmentActive(Fragment fragment) { 519f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (mViewPager == null || mAdapter == null) { 520f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return false; 521f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 522f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return mViewPager.getCurrentItem() == mAdapter.getItemPosition(fragment); 523f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 524f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 52599f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon @Override 526ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void onFragmentVisible(PhotoViewFragment fragment) { 527ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // Do nothing, we handle this in setViewActivated 528f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 529f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 530f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein @Override 531f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public InterceptType onTouchIntercept(float origX, float origY) { 532f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein boolean interceptLeft = false; 533f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein boolean interceptRight = false; 534f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 53579bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei for (OnScreenListener listener : mScreenListeners.values()) { 536f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (!interceptLeft) { 537f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein interceptLeft = listener.onInterceptMoveLeft(origX, origY); 538f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 539f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (!interceptRight) { 540f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein interceptRight = listener.onInterceptMoveRight(origX, origY); 541f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 542f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 543f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 544f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (interceptLeft) { 545f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (interceptRight) { 546f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return InterceptType.BOTH; 547f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 548f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return InterceptType.LEFT; 549f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } else if (interceptRight) { 550f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return InterceptType.RIGHT; 551f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 552f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return InterceptType.NONE; 553f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 554f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 555f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** 556f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * Updates the title bar according to the value of {@link #mFullScreen}. 557f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein */ 5580ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp protected void setFullScreen(boolean fullScreen, boolean setDelayedRunnable) { 559f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein final boolean fullScreenChanged = (fullScreen != mFullScreen); 560f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein mFullScreen = fullScreen; 561f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 562f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (mFullScreen) { 5631abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein setLightsOutMode(true); 56440a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook cancelEnterFullScreenRunnable(); 565f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } else { 5661abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein setLightsOutMode(false); 5671abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein if (setDelayedRunnable) { 56840a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook postEnterFullScreenRunnableWithDelay(); 5691abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein } 570f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 571f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 572f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (fullScreenChanged) { 57379bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei for (OnScreenListener listener : mScreenListeners.values()) { 5741abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein listener.onFullScreenChanged(mFullScreen); 5751abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein } 5761abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein } 5771abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein } 5781abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein 57940a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook private void postEnterFullScreenRunnableWithDelay() { 58040a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook mHandler.postDelayed(mEnterFullScreenRunnable, mEnterFullScreenDelayTime); 581150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein } 582150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein 58340a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook private void cancelEnterFullScreenRunnable() { 58440a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook mHandler.removeCallbacks(mEnterFullScreenRunnable); 585150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein } 586150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein 5877e6995626b551c215bc3064c95b9996af940746aAdam Copp protected void setLightsOutMode(boolean enabled) { 588ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon int flags = 0; 589ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final int version = Build.VERSION.SDK_INT; 590112d29fe9f30d1237a1c8ac1ecc3740879c8c9cePaul Westbrook final ActionBar actionBar = getActionBar(); 591ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (enabled) { 592ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (version >= android.os.Build.VERSION_CODES.JELLY_BEAN) { 593ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon flags = View.SYSTEM_UI_FLAG_LOW_PROFILE 594ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 595ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon | View.SYSTEM_UI_FLAG_LAYOUT_STABLE; 596ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (!mScaleAnimationEnabled) { 597ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // If we are using the scale animation for intro and exit, 598ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // we can't go into fullscreen mode. The issue is that the 599ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // activity that invoked this will not be in fullscreen, so 600ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // as we transition out, the background activity will be 601ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // temporarily rendered without an actionbar, and the shrinking 602ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // photo will not line up properly. After that it redraws 603ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // in the correct location, but it still looks janks. 604ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // FLAG: there may be a better way to fix this, but I don't 605ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // yet know what it is. 606ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon flags |= View.SYSTEM_UI_FLAG_FULLSCREEN; 607ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 608ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else if (version >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 609ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon flags = View.SYSTEM_UI_FLAG_LOW_PROFILE; 610ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else if (version >= android.os.Build.VERSION_CODES.HONEYCOMB) { 611ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon flags = View.STATUS_BAR_HIDDEN; 612ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 613ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon actionBar.hide(); 6141abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein } else { 615ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (version >= android.os.Build.VERSION_CODES.JELLY_BEAN) { 616ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon flags = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 617ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon | View.SYSTEM_UI_FLAG_LAYOUT_STABLE; 618ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else if (version >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 619ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon flags = View.SYSTEM_UI_FLAG_VISIBLE; 620ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else if (version >= android.os.Build.VERSION_CODES.HONEYCOMB) { 621ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon flags = View.STATUS_BAR_VISIBLE; 622f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 623ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon actionBar.show(); 624ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 625ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 626ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (version >= Build.VERSION_CODES.HONEYCOMB) { 627ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mRootView.setSystemUiVisibility(flags); 628f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 629f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 630f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 631ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private final Runnable mEnterFullScreenRunnable = new Runnable() { 6321abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein @Override 6331abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein public void run() { 634b462d1bf5d3833fabbdc38d13f66dadcf6ceda54Adam Copp setFullScreen(true, true); 6351abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein } 6361abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein }; 6371abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein 638399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon @Override 63979bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei public void setViewActivated(int position) { 64079bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei OnScreenListener listener = mScreenListeners.get(position); 64179bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei if (listener != null) { 642f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein listener.onViewActivated(); 643f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 644ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final Cursor cursor = getCursorAtProperPosition(); 645ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mCurrentPhotoIndex = position; 646ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // FLAG: get the column indexes once in onLoadFinished(). 647ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // That would make this more efficient, instead of looking these up 648ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // repeatedly whenever we want them. 649ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon int uriIndex = cursor.getColumnIndex(PhotoContract.PhotoViewColumns.URI); 650ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mCurrentPhotoUri = cursor.getString(uriIndex); 651ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon updateActionBar(); 652ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 653ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // Restart the timer to return to fullscreen. 654ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon cancelEnterFullScreenRunnable(); 655ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon postEnterFullScreenRunnableWithDelay(); 656f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 657f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 658f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** 659f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * Adjusts the activity title and subtitle to reflect the photo name and count. 660f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein */ 6617b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal protected void updateActionBar() { 662f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein final int position = mViewPager.getCurrentItem() + 1; 663f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein final boolean hasAlbumCount = mAlbumCount >= 0; 664f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 665f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein final Cursor cursor = getCursorAtProperPosition(); 666f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (cursor != null) { 667ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // FLAG: We should grab the indexes when we first get the cursor 668ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // and store them so we don't need to do it each time. 669f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein final int photoNameIndex = cursor.getColumnIndex(PhotoContract.PhotoViewColumns.NAME); 6707b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal mActionBarTitle = cursor.getString(photoNameIndex); 67168a16aa04f9b98868f4412e7324b0fc292c9d858Andrew Sapperstein } else { 6727b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal mActionBarTitle = null; 673f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 674f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 675f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (mIsEmpty || !hasAlbumCount || position <= 0) { 6767b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal mActionBarSubtitle = null; 677f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } else { 6787b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal mActionBarSubtitle = 6797b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal getResources().getString(R.string.photo_view_count, position, mAlbumCount); 680f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 681ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 682112d29fe9f30d1237a1c8ac1ecc3740879c8c9cePaul Westbrook setActionBarTitles(getActionBar()); 6837b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal } 684f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 6857b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal /** 6867b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal * Sets the Action Bar title to {@link #mActionBarTitle} and the subtitle to 6877b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal * {@link #mActionBarSubtitle} 6887b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal */ 689ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected final void setActionBarTitles(ActionBar actionBar) { 6907b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal if (actionBar == null) { 6917b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal return; 6927b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal } 6937b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal actionBar.setTitle(getInputOrEmpty(mActionBarTitle)); 6947b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal actionBar.setSubtitle(getInputOrEmpty(mActionBarSubtitle)); 6957b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal } 6967b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal 6977b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal /** 6987b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal * If the input string is non-null, it is returned, otherwise an empty string is returned; 6997b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal * @param in 7007b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal * @return 7017b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal */ 7027b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal private static final String getInputOrEmpty(String in) { 7037b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal if (in == null) { 7047b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal return ""; 7057b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal } 7067b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal return in; 707f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 708f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 709f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** 710f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * Utility method that will return the cursor that contains the data 711f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * at the current position so that it refers to the current image on screen. 712f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * @return the cursor at the current position or 713f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * null if no cursor exists or if the {@link PhotoViewPager} is null. 714f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein */ 715f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public Cursor getCursorAtProperPosition() { 716f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (mViewPager == null) { 717f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return null; 718f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 719f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 720f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein final int position = mViewPager.getCurrentItem(); 721f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein final Cursor cursor = mAdapter.getCursor(); 722f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 723f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (cursor == null) { 724f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return null; 725f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 726f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 727f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein cursor.moveToPosition(position); 728f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 729f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return cursor; 730f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 7319007d640832f674a9d65058a3c2a484c078d239eAndrew Sapperstein 7329007d640832f674a9d65058a3c2a484c078d239eAndrew Sapperstein public Cursor getCursor() { 7339007d640832f674a9d65058a3c2a484c078d239eAndrew Sapperstein return (mAdapter == null) ? null : mAdapter.getCursor(); 7349007d640832f674a9d65058a3c2a484c078d239eAndrew Sapperstein } 735150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein 736150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein @Override 737150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein public void onMenuVisibilityChanged(boolean isVisible) { 738150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein if (isVisible) { 73940a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook cancelEnterFullScreenRunnable(); 740150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein } else { 74140a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook postEnterFullScreenRunnableWithDelay(); 742150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein } 743150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein } 7440ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp 7450bf849421d303e05c600cdcd7dab73cc84809a36Mark Wei @Override 74679bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei public void onNewPhotoLoaded(int position) { 74779bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei // do nothing 7488f359e98b9f18064a75c80b9c9ad8bda2713c612Paul Westbrook } 7498f359e98b9f18064a75c80b9c9ad8bda2713c612Paul Westbrook 75013ea5dd3a7a3ab4214c6c5dea72a14ccd434d4b1Martin Hibdon protected void setPhotoIndex(int index) { 75113ea5dd3a7a3ab4214c6c5dea72a14ccd434d4b1Martin Hibdon mCurrentPhotoIndex = index; 75213ea5dd3a7a3ab4214c6c5dea72a14ccd434d4b1Martin Hibdon } 75313ea5dd3a7a3ab4214c6c5dea72a14ccd434d4b1Martin Hibdon 754ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon @Override 755ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void onFragmentPhotoLoadComplete(PhotoViewFragment fragment, boolean success) { 756ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (mTemporaryImage.getVisibility() != View.GONE && 757ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon TextUtils.equals(fragment.getPhotoUri(), mCurrentPhotoUri)) { 758ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (success) { 759ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // The fragment for the current image is now ready for display. 760ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mTemporaryImage.setVisibility(View.GONE); 761ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mViewPager.setVisibility(View.VISIBLE); 762ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else { 763ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // This means that we are unable to load the fragment's photo. 764ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // I'm not sure what the best thing to do here is, but at least if 765ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // we display the viewPager, the fragment itself can decide how to 766ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // display the failure of its own image. 767ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon Log.w(TAG, "Failed to load fragment image"); 768ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mTemporaryImage.setVisibility(View.GONE); 769ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mViewPager.setVisibility(View.VISIBLE); 770ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 771ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 7720ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp } 7730ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp 774ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected boolean isFullScreen() { 775ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon return mFullScreen; 7760ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp } 7778746927a945358bb9e515985a37cac7807261026Martin Hibdon 7780bf849421d303e05c600cdcd7dab73cc84809a36Mark Wei @Override 7790bf849421d303e05c600cdcd7dab73cc84809a36Mark Wei public void onCursorChanged(PhotoViewFragment fragment, Cursor cursor) { 7800bf849421d303e05c600cdcd7dab73cc84809a36Mark Wei // do nothing 7810bf849421d303e05c600cdcd7dab73cc84809a36Mark Wei } 78241db3eb9741a222432b367409c67d2263856a0a7Vikram Aggarwal 78341db3eb9741a222432b367409c67d2263856a0a7Vikram Aggarwal @Override 78441db3eb9741a222432b367409c67d2263856a0a7Vikram Aggarwal public PhotoPagerAdapter getAdapter() { 78541db3eb9741a222432b367409c67d2263856a0a7Vikram Aggarwal return mAdapter; 78641db3eb9741a222432b367409c67d2263856a0a7Vikram Aggarwal } 787ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 788ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void onEnterAnimationComplete() { 789ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mEnterAnimationFinished = true; 790ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mViewPager.setVisibility(View.VISIBLE); 791ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 792ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 793ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private void onExitAnimationComplete() { 794ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon finish(); 795ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon overridePendingTransition(0, 0); 796ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 797ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 798ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private void runEnterAnimation() { 799ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final int totalWidth = mRootView.getMeasuredWidth(); 800ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final int totalHeight = mRootView.getMeasuredHeight(); 801ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 802ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // FLAG: Need to handle the aspect ratio of the bitmap. If it's a portrait 803ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // bitmap, then we need to position the view higher so that the middle 804ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // pixels line up. 805ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mTemporaryImage.setVisibility(View.VISIBLE); 806ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // We need to take a full screen image, and scale/translate it so that 807ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // it appears at exactly the same location onscreen as it is in the 808ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // prior activity. 809ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // The final image will take either the full screen width or height (or both). 810ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 811ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final float scaleW = (float) mAnimationStartWidth / totalWidth; 812ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final float scaleY = (float) mAnimationStartHeight / totalHeight; 813ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final float scale = Math.max(scaleW, scaleY); 814ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 815ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final int translateX = calculateTranslate(mAnimationStartX, mAnimationStartWidth, 816ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon totalWidth, scale); 817ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final int translateY = calculateTranslate(mAnimationStartY, mAnimationStartHeight, 818ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon totalHeight, scale); 819ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 820ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final int version = android.os.Build.VERSION.SDK_INT; 8216e7a042765456b4d5faa95d591735abc06c274aeAndrew Sapperstein if (version >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 822ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mBackground.setAlpha(0f); 823ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mBackground.animate().alpha(1f).setDuration(ENTER_ANIMATION_DURATION_MS).start(); 824ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mBackground.setVisibility(View.VISIBLE); 825ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 826ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mTemporaryImage.setScaleX(scale); 827ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mTemporaryImage.setScaleY(scale); 828ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mTemporaryImage.setTranslationX(translateX); 829ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mTemporaryImage.setTranslationY(translateY); 830ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 831ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon Runnable endRunnable = new Runnable() { 832ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon @Override 833ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void run() { 834ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon PhotoViewActivity.this.onEnterAnimationComplete(); 835ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 836ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon }; 837ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon ViewPropertyAnimator animator = mTemporaryImage.animate().scaleX(1f).scaleY(1f) 838ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon .translationX(0).translationY(0).setDuration(ENTER_ANIMATION_DURATION_MS); 8396e7a042765456b4d5faa95d591735abc06c274aeAndrew Sapperstein if (version >= Build.VERSION_CODES.JELLY_BEAN) { 840ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon animator.withEndAction(endRunnable); 841ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else { 842ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mHandler.postDelayed(endRunnable, ENTER_ANIMATION_DURATION_MS); 843ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 844ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon animator.start(); 845ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else { 846ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final Animation alphaAnimation = new AlphaAnimation(0f, 1f); 847ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon alphaAnimation.setDuration(ENTER_ANIMATION_DURATION_MS); 848ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mBackground.startAnimation(alphaAnimation); 849ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mBackground.setVisibility(View.VISIBLE); 850ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 851ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final Animation translateAnimation = new TranslateAnimation(translateX, 852ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon translateY, 0, 0); 853ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon translateAnimation.setDuration(ENTER_ANIMATION_DURATION_MS); 854ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon Animation scaleAnimation = new ScaleAnimation(scale, scale, 0, 0); 855ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon scaleAnimation.setDuration(ENTER_ANIMATION_DURATION_MS); 856ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 857ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon AnimationSet animationSet = new AnimationSet(true); 858ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon animationSet.addAnimation(translateAnimation); 859ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon animationSet.addAnimation(scaleAnimation); 860ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon AnimationListener listener = new AnimationListener() { 861ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon @Override 862ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void onAnimationEnd(Animation arg0) { 863ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon PhotoViewActivity.this.onEnterAnimationComplete(); 864ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 865ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 866ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon @Override 867ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void onAnimationRepeat(Animation arg0) { 868ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 869ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 870ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon @Override 871ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void onAnimationStart(Animation arg0) { 872ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 873ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon }; 874ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon animationSet.setAnimationListener(listener); 875ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mTemporaryImage.startAnimation(animationSet); 876ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 877ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 878ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 879ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private void runExitAnimation() { 880ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon Intent intent = getIntent(); 881ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // FLAG: should just fall back to a standard animation if either: 882ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // 1. images have been added or removed since we've been here, or 883ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // 2. we are currently looking at some image other than the one we 884ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // started on. 885ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 886ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final int totalWidth = mRootView.getMeasuredWidth(); 887ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final int totalHeight = mRootView.getMeasuredHeight(); 888ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 889ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // We need to take a full screen image, and scale/translate it so that 890ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // it appears at exactly the same location onscreen as it is in the 891ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // prior activity. 892ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // The final image will take either the full screen width or height (or both). 893ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final float scaleW = (float) mAnimationStartWidth / totalWidth; 894ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final float scaleY = (float) mAnimationStartHeight / totalHeight; 895ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final float scale = Math.max(scaleW, scaleY); 896ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 897ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final int translateX = calculateTranslate(mAnimationStartX, mAnimationStartWidth, 898ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon totalWidth, scale); 899ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final int translateY = calculateTranslate(mAnimationStartY, mAnimationStartHeight, 900ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon totalHeight, scale); 901ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final int version = android.os.Build.VERSION.SDK_INT; 9026e7a042765456b4d5faa95d591735abc06c274aeAndrew Sapperstein if (version >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 903ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mBackground.animate().alpha(0f).setDuration(EXIT_ANIMATION_DURATION_MS).start(); 904ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mBackground.setVisibility(View.VISIBLE); 905ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 906ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon Runnable endRunnable = new Runnable() { 907ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon @Override 908ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void run() { 909ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon PhotoViewActivity.this.onExitAnimationComplete(); 910ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 911ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon }; 912ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // If the temporary image is still visible it means that we have 913ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // not yet loaded the fullres image, so we need to animate 914ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // the temporary image out. 915ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon ViewPropertyAnimator animator = null; 916ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (mTemporaryImage.getVisibility() == View.VISIBLE) { 917ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon animator = mTemporaryImage.animate().scaleX(scale).scaleY(scale) 918ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon .translationX(translateX).translationY(translateY) 919ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon .setDuration(EXIT_ANIMATION_DURATION_MS); 920ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else { 921ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon animator = mViewPager.animate().scaleX(scale).scaleY(scale) 922ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon .translationX(translateX).translationY(translateY) 923ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon .setDuration(EXIT_ANIMATION_DURATION_MS); 924ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 925ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (version >= android.os.Build.VERSION_CODES.JELLY_BEAN) { 926ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon animator.withEndAction(endRunnable); 927ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else { 928ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mHandler.postDelayed(endRunnable, EXIT_ANIMATION_DURATION_MS); 929ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 930ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon animator.start(); 931ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else { 932ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final Animation alphaAnimation = new AlphaAnimation(1f, 0f); 933ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon alphaAnimation.setDuration(EXIT_ANIMATION_DURATION_MS); 934ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mBackground.startAnimation(alphaAnimation); 935ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mBackground.setVisibility(View.VISIBLE); 936ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 937ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final Animation scaleAnimation = new ScaleAnimation(1f, 1f, scale, scale); 938ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon scaleAnimation.setDuration(EXIT_ANIMATION_DURATION_MS); 939ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon AnimationListener listener = new AnimationListener() { 940ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon @Override 941ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void onAnimationEnd(Animation arg0) { 942ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon PhotoViewActivity.this.onExitAnimationComplete(); 943ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 944ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 945ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon @Override 946ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void onAnimationRepeat(Animation arg0) { 947ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 948ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 949ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon @Override 950ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void onAnimationStart(Animation arg0) { 951ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 952ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon }; 953ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon scaleAnimation.setAnimationListener(listener); 954ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // If the temporary image is still visible it means that we have 955ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // not yet loaded the fullres image, so we need to animate 956ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // the temporary image out. 957ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (mTemporaryImage.getVisibility() == View.VISIBLE) { 958ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mTemporaryImage.startAnimation(scaleAnimation); 959ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else { 960ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mViewPager.startAnimation(scaleAnimation); 961ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 962ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 963ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 964ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 965ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private int calculateTranslate(int start, int startSize, int totalSize, float scale) { 966ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // Translation takes precedence over scale. What this means is that if 967ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // we want an view's upper left corner to be a particular spot on screen, 968ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // but that view is scaled to something other than 1, we need to take into 969ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // account the pixels lost to scaling. 970ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // So if we have a view that is 200x300, and we want it's upper left corner 971ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // to be at 50x50, but it's scaled by 50%, we can't just translate it to 50x50. 972ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // If we were to do that, the view's *visible* upper left corner would be at 973ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // 100x200. We need to take into account the difference between the outside 974ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // size of the view (i.e. the size prior to scaling) and the scaled size. 975ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // scaleFromEdge is the difference between the visible left edge and the 976ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // actual left edge, due to scaling. 977ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // scaleFromTop is the difference between the visible top edge, and the 978ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // actual top edge, due to scaling. 979ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon int scaleFromEdge = Math.round((totalSize - totalSize * scale) / 2); 980ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 981ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // The imageView is fullscreen, regardless of the aspect ratio of the actual image. 982ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // This means that some portion of the imageView will be blank. We need to 983ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // take into account the size of the blank area so that the actual image 984ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // lines up with the starting image. 985ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon int blankSize = Math.round((totalSize * scale - startSize) / 2); 986ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 987ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon return start - scaleFromEdge - blankSize; 988ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 989ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 990ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private void initTemporaryImage(Bitmap bitmap) { 99118c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon if (mEnterAnimationFinished) { 99218c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon // Forget this, we've already run the animation. 99318c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon return; 99418c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon } 995ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mTemporaryImage.setImageBitmap(bitmap); 996ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (bitmap != null) { 99718c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon // We have not yet run the enter animation. Start it now. 99818c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon int totalWidth = mRootView.getMeasuredWidth(); 99918c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon if (totalWidth == 0) { 100018c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon // the measure pass has not yet finished. We can't properly 100118c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon // run out animation until that is done. Listen for the layout 100218c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon // to occur, then fire the animation. 100318c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon final View base = mRootView; 100418c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon base.getViewTreeObserver().addOnGlobalLayoutListener( 100518c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon new OnGlobalLayoutListener() { 100618c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon @Override 100718c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon public void onGlobalLayout() { 100818c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon int version = android.os.Build.VERSION.SDK_INT; 100918c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon if (version >= android.os.Build.VERSION_CODES.JELLY_BEAN) { 101018c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon base.getViewTreeObserver().removeOnGlobalLayoutListener(this); 101118c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon } else { 101218c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon base.getViewTreeObserver().removeGlobalOnLayoutListener(this); 1013ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 101418c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon runEnterAnimation(); 101518c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon } 101618c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon }); 101718c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon } else { 101818c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon // initiate the animation 101918c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon runEnterAnimation(); 1020ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 1021ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 1022ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // Kick off the photo list loader 1023ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon getSupportLoaderManager().initLoader(LOADER_PHOTO_LIST, null, this); 1024ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 1025ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 1026ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private class BitmapCallback implements LoaderManager.LoaderCallbacks<BitmapResult> { 1027ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 1028ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon @Override 1029ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public Loader<BitmapResult> onCreateLoader(int id, Bundle args) { 1030ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon String uri = args.getString(ARG_IMAGE_URI); 1031ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon switch (id) { 1032ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon case PhotoViewCallbacks.BITMAP_LOADER_THUMBNAIL: 1033ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon return onCreateBitmapLoader(PhotoViewCallbacks.BITMAP_LOADER_THUMBNAIL, 1034ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon args, uri); 1035ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon case PhotoViewCallbacks.BITMAP_LOADER_AVATAR: 1036ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon return onCreateBitmapLoader(PhotoViewCallbacks.BITMAP_LOADER_AVATAR, 1037ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon args, uri); 1038ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 1039ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon return null; 1040ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 1041ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 1042ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon @Override 1043ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void onLoadFinished(Loader<BitmapResult> loader, BitmapResult result) { 1044ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon Bitmap bitmap = result.bitmap; 1045112d29fe9f30d1237a1c8ac1ecc3740879c8c9cePaul Westbrook final ActionBar actionBar = getActionBar(); 1046ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon switch (loader.getId()) { 1047ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon case PhotoViewCallbacks.BITMAP_LOADER_THUMBNAIL: 1048ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // We just loaded the initial thumbnail that we can display 1049ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // while waiting for the full viewPager to get initialized. 1050ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon initTemporaryImage(bitmap); 105118c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon // Destroy the loader so we don't attempt to load the thumbnail 105218c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon // again on screen rotations. 105318c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon getSupportLoaderManager().destroyLoader( 105418c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon PhotoViewCallbacks.BITMAP_LOADER_THUMBNAIL); 1055ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon break; 1056ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon case PhotoViewCallbacks.BITMAP_LOADER_AVATAR: 1057ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (bitmap == null) { 1058ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon actionBar.setLogo(null); 1059ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else { 1060ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon BitmapDrawable drawable = new BitmapDrawable(getResources(), bitmap); 1061ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon actionBar.setLogo(drawable); 1062ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 1063ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon break; 1064ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 1065ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 1066ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 1067ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon @Override 1068ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void onLoaderReset(Loader<BitmapResult> loader) { 1069ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // Do nothing 1070ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 1071ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 1072f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein} 1073