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 20f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.app.Activity; 21f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.app.ActivityManager; 2299f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdonimport android.content.Context; 23f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.content.Intent; 2429e47d946fd19443c12ebad9f94e83741c7d9120Paul Westbrookimport android.content.res.Resources; 25f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.database.Cursor; 26ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport android.graphics.Bitmap; 27ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport android.graphics.drawable.BitmapDrawable; 28f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.net.Uri; 291abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sappersteinimport android.os.Build; 30f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.os.Bundle; 31f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.os.Handler; 328746927a945358bb9e515985a37cac7807261026Martin Hibdonimport android.support.v4.app.Fragment; 338746927a945358bb9e515985a37cac7807261026Martin Hibdonimport android.support.v4.app.LoaderManager; 348746927a945358bb9e515985a37cac7807261026Martin Hibdonimport android.support.v4.content.Loader; 35f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.support.v4.view.ViewPager.OnPageChangeListener; 36bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Coppimport android.view.MenuItem; 378670cefb043f865c7275876dcc94f65ce5bda041Martin Hibdonimport android.support.v7.app.ActionBar; 388670cefb043f865c7275876dcc94f65ce5bda041Martin Hibdonimport android.support.v7.app.ActionBar.OnMenuVisibilityListener; 398670cefb043f865c7275876dcc94f65ce5bda041Martin Hibdonimport android.support.v7.app.ActionBarActivity; 40ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport android.text.TextUtils; 41ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport android.util.Log; 42f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.view.View; 43ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport android.view.ViewPropertyAnimator; 44ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport android.view.ViewTreeObserver.OnGlobalLayoutListener; 45ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport android.view.animation.AlphaAnimation; 46ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport android.view.animation.Animation; 47ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport android.view.animation.AnimationSet; 48ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport android.view.animation.ScaleAnimation; 49ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport android.view.animation.TranslateAnimation; 50ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport android.view.animation.Animation.AnimationListener; 51ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport android.widget.ImageView; 52ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 53f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.PhotoViewPager.InterceptType; 54f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.PhotoViewPager.OnInterceptTouchListener; 55f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.adapters.PhotoPagerAdapter; 560c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sappersteinimport com.android.ex.photo.fragments.PhotoViewFragment; 57ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport com.android.ex.photo.loaders.PhotoBitmapLoader; 58ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport com.android.ex.photo.loaders.PhotoBitmapLoaderInterface.BitmapResult; 59f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.loaders.PhotoPagerLoader; 60f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.provider.PhotoContract; 61f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 6279bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Weiimport java.util.HashMap; 63f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport java.util.HashSet; 6479bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Weiimport java.util.Map; 65f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport java.util.Set; 66f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 67f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein/** 68f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * Activity to view the contents of an album. 69f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein */ 708670cefb043f865c7275876dcc94f65ce5bda041Martin Hibdonpublic class PhotoViewActivity extends ActionBarActivity implements 718746927a945358bb9e515985a37cac7807261026Martin Hibdon LoaderManager.LoaderCallbacks<Cursor>, OnPageChangeListener, OnInterceptTouchListener, 72399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon OnMenuVisibilityListener, PhotoViewCallbacks { 730c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein 74ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private final static String TAG = "PhotoViewActivity"; 75ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 76ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private final static String STATE_CURRENT_URI_KEY = 77ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon "com.google.android.apps.plus.PhotoViewFragment.CURRENT_URI"; 78ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private final static String STATE_CURRENT_INDEX_KEY = 79ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon "com.google.android.apps.plus.PhotoViewFragment.CURRENT_INDEX"; 80f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein private final static String STATE_FULLSCREEN_KEY = 81f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein "com.google.android.apps.plus.PhotoViewFragment.FULLSCREEN"; 827b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal private final static String STATE_ACTIONBARTITLE_KEY = 838670cefb043f865c7275876dcc94f65ce5bda041Martin Hibdon "com.google.android.apps.plus.PhotoViewFragment.ACTIONBARTITLE"; 847b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal private final static String STATE_ACTIONBARSUBTITLE_KEY = 858670cefb043f865c7275876dcc94f65ce5bda041Martin Hibdon "com.google.android.apps.plus.PhotoViewFragment.ACTIONBARTITLE"; 86ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private final static String STATE_ENTERANIMATIONFINISHED_KEY = 87ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon "com.google.android.apps.plus.PhotoViewFragment.SCALEANIMATIONFINISHED"; 88f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 89ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected final static String ARG_IMAGE_URI = "image_uri"; 90ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 91ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private static final int LOADER_PHOTO_LIST = 100; 92f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 93f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** Count used when the real photo count is unknown [but, may be determined] */ 94f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public static final int ALBUM_COUNT_UNKNOWN = -1; 95f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 96ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public static final int ENTER_ANIMATION_DURATION_MS = 250; 97ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public static final int EXIT_ANIMATION_DURATION_MS = 250; 98ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 99f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** Argument key for the dialog message */ 100f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public static final String KEY_MESSAGE = "dialog_message"; 101f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 102f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public static int sMemoryClass; 103f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 104f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** The URI of the photos we're viewing; may be {@code null} */ 105f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein private String mPhotosUri; 106f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** The index of the currently viewed photo */ 107ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private int mCurrentPhotoIndex; 108ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon /** The uri of the currently viewed photo */ 109ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private String mCurrentPhotoUri; 110f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** The query projection to use; may be {@code null} */ 111f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein private String[] mProjection; 112f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** The total number of photos; only valid if {@link #mIsEmpty} is {@code false}. */ 113ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected int mAlbumCount = ALBUM_COUNT_UNKNOWN; 114f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** {@code true} if the view is empty. Otherwise, {@code false}. */ 115ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected boolean mIsEmpty; 11699f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon /** the main root view */ 11799f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon protected View mRootView; 118ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon /** Background image that contains nothing, so it can be alpha faded from 119ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon * transparent to black without affecting any other views. */ 120ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected View mBackground; 121f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** The main pager; provides left/right swipe between photos */ 12299f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon protected PhotoViewPager mViewPager; 123ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon /** The temporary image so that we can quickly scale up the fullscreen thumbnail */ 124ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected ImageView mTemporaryImage; 125f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** Adapter to create pager views */ 12699f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon protected PhotoPagerAdapter mAdapter; 127f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** Whether or not we're in "full screen" mode */ 128ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected boolean mFullScreen; 12979bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei /** The listeners wanting full screen state for each screen position */ 130ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private final Map<Integer, OnScreenListener> 13179bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei mScreenListeners = new HashMap<Integer, OnScreenListener>(); 1320c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein /** The set of listeners wanting full screen state */ 133ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private final Set<CursorChangedListener> mCursorListeners = new HashSet<CursorChangedListener>(); 134f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** When {@code true}, restart the loader when the activity becomes active */ 135f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein private boolean mRestartLoader; 136f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** Whether or not this activity is paused */ 137ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected boolean mIsPaused = true; 13891dbfd25cc234de393ae22fc39a832a6335e1bc2Adam Copp /** The maximum scale factor applied to images when they are initially displayed */ 139ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected float mMaxInitialScale; 1407b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal /** The title in the actionbar */ 141ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected String mActionBarTitle; 1427b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal /** The subtitle in the actionbar */ 143ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected String mActionBarSubtitle; 144ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 145ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private boolean mEnterAnimationFinished; 146ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected boolean mScaleAnimationEnabled; 147ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected int mAnimationStartX; 148ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected int mAnimationStartY; 149ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected int mAnimationStartWidth; 150ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected int mAnimationStartHeight; 151ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 152ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected boolean mActionBarHiddenInitially; 153ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected boolean mDisplayThumbsFullScreen; 154ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 155ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected BitmapCallback mBitmapCallback; 156ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected final Handler mHandler = new Handler(); 1577b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal 158f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein // TODO Find a better way to do this. We basically want the activity to display the 159f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein // "loading..." progress until the fragment takes over and shows it's own "loading..." 160f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein // progress [located in photo_header_view.xml]. We could potentially have all status displayed 161f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein // by the activity, but, that gets tricky when it comes to screen rotation. For now, we 162f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein // track the loading by this variable which is fragile and may cause phantom "loading..." 163f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein // text. 16440a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook private long mEnterFullScreenDelayTime; 165f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 166ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 16799f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon protected PhotoPagerAdapter createPhotoPagerAdapter(Context context, 16899f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon android.support.v4.app.FragmentManager fm, Cursor c, float maxScale) { 169ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon PhotoPagerAdapter adapter = new PhotoPagerAdapter(context, fm, c, maxScale, 170ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mDisplayThumbsFullScreen); 171ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon return adapter; 17299f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon } 17399f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon 174f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein @Override 175f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein protected void onCreate(Bundle savedInstanceState) { 176f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein super.onCreate(savedInstanceState); 177f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 178f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein final ActivityManager mgr = (ActivityManager) getApplicationContext(). 179f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein getSystemService(Activity.ACTIVITY_SERVICE); 180f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein sMemoryClass = mgr.getMemoryClass(); 181f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 182ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final Intent intent = getIntent(); 183f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein // uri of the photos to view; optional 184ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (intent.hasExtra(Intents.EXTRA_PHOTOS_URI)) { 185ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mPhotosUri = intent.getStringExtra(Intents.EXTRA_PHOTOS_URI); 186ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 187ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (intent.getBooleanExtra(Intents.EXTRA_SCALE_UP_ANIMATION, false)) { 188ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mScaleAnimationEnabled = true; 189ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mAnimationStartX = intent.getIntExtra(Intents.EXTRA_ANIMATION_START_X, 0); 190ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mAnimationStartY = intent.getIntExtra(Intents.EXTRA_ANIMATION_START_Y, 0); 191ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mAnimationStartWidth = intent.getIntExtra(Intents.EXTRA_ANIMATION_START_WIDTH, 0); 192ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mAnimationStartHeight = intent.getIntExtra(Intents.EXTRA_ANIMATION_START_HEIGHT, 0); 193f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 194ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mActionBarHiddenInitially = intent.getBooleanExtra( 195ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon Intents.EXTRA_ACTION_BAR_HIDDEN_INITIALLY, false); 196ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mDisplayThumbsFullScreen = intent.getBooleanExtra( 197ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon Intents.EXTRA_DISPLAY_THUMBS_FULLSCREEN, false); 198f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 199f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein // projection for the query; optional 20041db3eb9741a222432b367409c67d2263856a0a7Vikram Aggarwal // If not set, the default projection is used. 201f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein // This projection must include the columns from the default projection. 202ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (intent.hasExtra(Intents.EXTRA_PROJECTION)) { 203ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mProjection = intent.getStringArrayExtra(Intents.EXTRA_PROJECTION); 204f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } else { 205f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein mProjection = null; 206f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 207f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 20891dbfd25cc234de393ae22fc39a832a6335e1bc2Adam Copp // Set the max initial scale, defaulting to 1x 209ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mMaxInitialScale = intent.getFloatExtra(Intents.EXTRA_MAX_INITIAL_SCALE, 1.0f); 210ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mCurrentPhotoUri = null; 211ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mCurrentPhotoIndex = -1; 212ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 213ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // We allow specifying the current photo by either index or uri. 214ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // This is because some users may have live datasets that can change, 215ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // adding new items to either the beginning or end of the set. For clients 216ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // that do not need that capability, ability to specify the current photo 217ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // by index is offered as a convenience. 218ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (intent.hasExtra(Intents.EXTRA_PHOTO_INDEX)) { 219ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mCurrentPhotoIndex = intent.getIntExtra(Intents.EXTRA_PHOTO_INDEX, -1); 220ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 221ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (intent.hasExtra(Intents.EXTRA_INITIAL_PHOTO_URI)) { 222ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mCurrentPhotoUri = intent.getStringExtra(Intents.EXTRA_INITIAL_PHOTO_URI); 223ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 22479bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei mIsEmpty = true; 225f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 226ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (savedInstanceState != null) { 227ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mCurrentPhotoUri = savedInstanceState.getString(STATE_CURRENT_URI_KEY); 228ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mCurrentPhotoIndex = savedInstanceState.getInt(STATE_CURRENT_INDEX_KEY); 229ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mFullScreen = savedInstanceState.getBoolean(STATE_FULLSCREEN_KEY, false); 230ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mActionBarTitle = savedInstanceState.getString(STATE_ACTIONBARTITLE_KEY); 231ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mActionBarSubtitle = savedInstanceState.getString(STATE_ACTIONBARSUBTITLE_KEY); 232ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mEnterAnimationFinished = savedInstanceState.getBoolean( 233ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon STATE_ENTERANIMATIONFINISHED_KEY, false); 234ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else { 235ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mFullScreen = mActionBarHiddenInitially; 236ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 237ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 238f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein setContentView(R.layout.photo_activity_view); 239f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 240f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein // Create the adapter and add the view pager 24141db3eb9741a222432b367409c67d2263856a0a7Vikram Aggarwal mAdapter = 24241db3eb9741a222432b367409c67d2263856a0a7Vikram Aggarwal createPhotoPagerAdapter(this, getSupportFragmentManager(), null, mMaxInitialScale); 243fd925449925f3eb6e2ab6e1c50203c4a4bc165b2Paul Westbrook final Resources resources = getResources(); 24499f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon mRootView = findViewById(R.id.photo_activity_root_view); 245ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mBackground = findViewById(R.id.photo_activity_background); 246ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mTemporaryImage = (ImageView) findViewById(R.id.photo_activity_temporary_image); 247f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein mViewPager = (PhotoViewPager) findViewById(R.id.photo_view_pager); 248efd51fc103301ca5e6e6eb3825623f50d0497b62Adam Copp mViewPager.setAdapter(mAdapter); 249f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein mViewPager.setOnPageChangeListener(this); 250f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein mViewPager.setOnInterceptTouchListener(this); 251fd925449925f3eb6e2ab6e1c50203c4a4bc165b2Paul Westbrook mViewPager.setPageMargin(resources.getDimensionPixelSize(R.dimen.photo_page_margin)); 252f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 253ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mBitmapCallback = new BitmapCallback(); 254ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (!mScaleAnimationEnabled || mEnterAnimationFinished) { 255ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // We are not running the scale up animation. Just let the fragments 256ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // display and handle the animation. 257ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon getSupportLoaderManager().initLoader(LOADER_PHOTO_LIST, null, this); 2581fabec882499ed0dd14d8dc7458445fa986ef14dMartin Hibdon // Make the background opaque immediately so that we don't see the activity 2591fabec882499ed0dd14d8dc7458445fa986ef14dMartin Hibdon // behind this one. 2601fabec882499ed0dd14d8dc7458445fa986ef14dMartin Hibdon mBackground.setVisibility(View.VISIBLE); 261ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else { 262ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // Attempt to load the initial image thumbnail. Once we have the 263ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // image, animate it up. Once the animation is complete, we can kick off 26418c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon // loading the ViewPager. After the primary fullres image is loaded, we will 26518c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon // make our temporary image invisible and display the ViewPager. 266ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mViewPager.setVisibility(View.GONE); 267ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon Bundle args = new Bundle(); 268ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon args.putString(ARG_IMAGE_URI, mCurrentPhotoUri); 269ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon getSupportLoaderManager().initLoader(BITMAP_LOADER_THUMBNAIL, args, mBitmapCallback); 270ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 271f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 27240a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook mEnterFullScreenDelayTime = 27340a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook resources.getInteger(R.integer.reenter_fullscreen_delay_time_in_millis); 27440a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook 275ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final ActionBar actionBar = getSupportActionBar(); 27699f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon if (actionBar != null) { 27799f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon actionBar.setDisplayHomeAsUpEnabled(true); 27899f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon actionBar.addOnMenuVisibilityListener(this); 2797b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal final int showTitle = ActionBar.DISPLAY_SHOW_TITLE; 2807b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal actionBar.setDisplayOptions(showTitle, showTitle); 281ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // Set the title and subtitle immediately here, rather than waiting 282ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // for the fragment to be initialized. 2837b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal setActionBarTitles(actionBar); 28499f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon } 285ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 286ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon setLightsOutMode(mFullScreen); 287f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 288f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 289f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein @Override 290f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein protected void onResume() { 291f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein super.onResume(); 292f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein setFullScreen(mFullScreen, false); 293f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 294f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein mIsPaused = false; 295f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (mRestartLoader) { 296f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein mRestartLoader = false; 2978746927a945358bb9e515985a37cac7807261026Martin Hibdon getSupportLoaderManager().restartLoader(LOADER_PHOTO_LIST, null, this); 298f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 299f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 300f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 301f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein @Override 302f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein protected void onPause() { 303f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein mIsPaused = true; 304f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein super.onPause(); 305f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 306f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 307f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein @Override 308f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public void onBackPressed() { 309ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // If we are in fullscreen mode, and the default is not full screen, then 310ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // switch back to actionBar display mode. 311ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (mFullScreen && !mActionBarHiddenInitially) { 312f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein toggleFullScreen(); 313f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } else { 314ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (mScaleAnimationEnabled) { 315ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon runExitAnimation(); 316ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else { 317ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon super.onBackPressed(); 318ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 319f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 320f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 321f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 322f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein @Override 323f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public void onSaveInstanceState(Bundle outState) { 324f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein super.onSaveInstanceState(outState); 325f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 326ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon outState.putString(STATE_CURRENT_URI_KEY, mCurrentPhotoUri); 327ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon outState.putInt(STATE_CURRENT_INDEX_KEY, mCurrentPhotoIndex); 328f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein outState.putBoolean(STATE_FULLSCREEN_KEY, mFullScreen); 3297b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal outState.putString(STATE_ACTIONBARTITLE_KEY, mActionBarTitle); 3307b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal outState.putString(STATE_ACTIONBARSUBTITLE_KEY, mActionBarSubtitle); 3311fabec882499ed0dd14d8dc7458445fa986ef14dMartin Hibdon outState.putBoolean(STATE_ENTERANIMATIONFINISHED_KEY, mEnterAnimationFinished); 332f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 333f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 334bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp @Override 335bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp public boolean onOptionsItemSelected(MenuItem item) { 336bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp switch (item.getItemId()) { 337bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp case android.R.id.home: 338bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp finish(); 339ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon return true; 340bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp default: 341bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp return super.onOptionsItemSelected(item); 342bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } 343bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } 344bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp 345399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon @Override 34679bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei public void addScreenListener(int position, OnScreenListener listener) { 34779bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei mScreenListeners.put(position, listener); 348f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 349f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 350399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon @Override 35179bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei public void removeScreenListener(int position) { 35279bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei mScreenListeners.remove(position); 353f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 354f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 355399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon @Override 3560c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein public synchronized void addCursorListener(CursorChangedListener listener) { 3570c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein mCursorListeners.add(listener); 3580c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein } 3590c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein 360399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon @Override 3610c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein public synchronized void removeCursorListener(CursorChangedListener listener) { 3620c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein mCursorListeners.remove(listener); 3630c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein } 3640c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein 365399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon @Override 366f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public boolean isFragmentFullScreen(Fragment fragment) { 367f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (mViewPager == null || mAdapter == null || mAdapter.getCount() == 0) { 368f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return mFullScreen; 369f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 370f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return mFullScreen || (mViewPager.getCurrentItem() != mAdapter.getItemPosition(fragment)); 371f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 372f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 373399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon @Override 374f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public void toggleFullScreen() { 375f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein setFullScreen(!mFullScreen, true); 376f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 377f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 378f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public void onPhotoRemoved(long photoId) { 379f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein final Cursor data = mAdapter.getCursor(); 380f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (data == null) { 381f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein // Huh?! How would this happen? 382f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return; 383f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 384f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 385f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein final int dataCount = data.getCount(); 386f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (dataCount <= 1) { 387f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein finish(); 388f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return; 389f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 390f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 3918746927a945358bb9e515985a37cac7807261026Martin Hibdon getSupportLoaderManager().restartLoader(LOADER_PHOTO_LIST, null, this); 392f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 393f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 394f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein @Override 395f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public Loader<Cursor> onCreateLoader(int id, Bundle args) { 396f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (id == LOADER_PHOTO_LIST) { 397f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return new PhotoPagerLoader(this, Uri.parse(mPhotosUri), mProjection); 398f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 399f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return null; 400f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 401f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 402f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein @Override 403ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public Loader<BitmapResult> onCreateBitmapLoader(int id, Bundle args, String uri) { 404ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon switch (id) { 405ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon case BITMAP_LOADER_AVATAR: 406ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon case BITMAP_LOADER_THUMBNAIL: 407ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon case BITMAP_LOADER_PHOTO: 408ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon return new PhotoBitmapLoader(this, uri); 409ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon default: 410ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon return null; 411ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 412ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 413ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 414ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon @Override 415ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 416ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 417f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein final int id = loader.getId(); 418f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (id == LOADER_PHOTO_LIST) { 419f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (data == null || data.getCount() == 0) { 420f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein mIsEmpty = true; 421f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } else { 422f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein mAlbumCount = data.getCount(); 423ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (mCurrentPhotoUri != null) { 42499f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon int index = 0; 425ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // Clear query params. Compare only the path. 4261ccbed89981c3bda94d7ee301c1053b3bb747e15Martin Hibdon final int uriIndex = data.getColumnIndex(PhotoContract.PhotoViewColumns.URI); 427fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat final Uri currentPhotoUri; 428fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { 429fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat currentPhotoUri = Uri.parse(mCurrentPhotoUri).buildUpon() 430fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat .clearQuery().build(); 431fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat } else { 432fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat currentPhotoUri = Uri.parse(mCurrentPhotoUri).buildUpon() 433fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat .query(null).build(); 434fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat } 43599f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon while (data.moveToNext()) { 436fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat final String uriString = data.getString(uriIndex); 437fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat final Uri uri; 438fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { 439fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat uri = Uri.parse(uriString).buildUpon().clearQuery().build(); 440fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat } else { 441fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat uri = Uri.parse(uriString).buildUpon().query(null).build(); 442fd1866743c530aa526fcd5880acd906f9dddb743Rasekh Rifaat } 443ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (currentPhotoUri != null && currentPhotoUri.equals(uri)) { 444ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mCurrentPhotoIndex = index; 44599f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon break; 44699f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon } 44799f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon index++; 44899f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon } 44999f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon } 45099f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon 451e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook // We're paused; don't do anything now, we'll get re-invoked 452e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook // when the activity becomes active again 453e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook // TODO(pwestbro): This shouldn't be necessary, as the loader manager should 454e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook // restart the loader 455e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook if (mIsPaused) { 456e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook mRestartLoader = true; 457e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook return; 458e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook } 45979bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei boolean wasEmpty = mIsEmpty; 460e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook mIsEmpty = false; 461e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook 4624a6a7183e0740dfb305a16676c867e182aced7aaAdam Copp mAdapter.swapCursor(data); 46399f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon if (mViewPager.getAdapter() == null) { 46499f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon mViewPager.setAdapter(mAdapter); 46599f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon } 4664a6a7183e0740dfb305a16676c867e182aced7aaAdam Copp notifyCursorListeners(data); 4674a6a7183e0740dfb305a16676c867e182aced7aaAdam Copp 468e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook // Use an index of 0 if the index wasn't specified or couldn't be found 469ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (mCurrentPhotoIndex < 0) { 470ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mCurrentPhotoIndex = 0; 471e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook } 472e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook 473ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mViewPager.setCurrentItem(mCurrentPhotoIndex, false); 47479bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei if (wasEmpty) { 475ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon setViewActivated(mCurrentPhotoIndex); 47679bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei } 477f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 4782989cf0c8e4b0aee4c9ac2b5384a392fd74cd6a9Paul Westbrook // Update the any action items 4792989cf0c8e4b0aee4c9ac2b5384a392fd74cd6a9Paul Westbrook updateActionItems(); 480f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 481f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 482f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 4838746927a945358bb9e515985a37cac7807261026Martin Hibdon @Override 4848746927a945358bb9e515985a37cac7807261026Martin Hibdon public void onLoaderReset(android.support.v4.content.Loader<Cursor> loader) { 4858746927a945358bb9e515985a37cac7807261026Martin Hibdon // If the loader is reset, remove the reference in the adapter to this cursor 4868746927a945358bb9e515985a37cac7807261026Martin Hibdon // TODO(pwestbro): reenable this when b/7075236 is fixed 4878746927a945358bb9e515985a37cac7807261026Martin Hibdon // mAdapter.swapCursor(null); 4888746927a945358bb9e515985a37cac7807261026Martin Hibdon } 4898746927a945358bb9e515985a37cac7807261026Martin Hibdon 4902989cf0c8e4b0aee4c9ac2b5384a392fd74cd6a9Paul Westbrook protected void updateActionItems() { 4912989cf0c8e4b0aee4c9ac2b5384a392fd74cd6a9Paul Westbrook // Do nothing, but allow extending classes to do work 4922989cf0c8e4b0aee4c9ac2b5384a392fd74cd6a9Paul Westbrook } 4932989cf0c8e4b0aee4c9ac2b5384a392fd74cd6a9Paul Westbrook 4940c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein private synchronized void notifyCursorListeners(Cursor data) { 4950c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein // tell all of the objects listening for cursor changes 4960c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein // that the cursor has changed 4970c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein for (CursorChangedListener listener : mCursorListeners) { 4980c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein listener.onCursorChanged(data); 4990c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein } 5000c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein } 5010c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein 502f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein @Override 503f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 504f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 505f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 506f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein @Override 507f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public void onPageSelected(int position) { 508ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mCurrentPhotoIndex = position; 50979bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei setViewActivated(position); 510f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 511f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 512f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein @Override 513f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public void onPageScrollStateChanged(int state) { 514f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 515f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 516399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon @Override 517f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public boolean isFragmentActive(Fragment fragment) { 518f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (mViewPager == null || mAdapter == null) { 519f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return false; 520f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 521f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return mViewPager.getCurrentItem() == mAdapter.getItemPosition(fragment); 522f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 523f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 52499f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon @Override 525ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void onFragmentVisible(PhotoViewFragment fragment) { 526ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // Do nothing, we handle this in setViewActivated 527f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 528f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 529f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein @Override 530f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public InterceptType onTouchIntercept(float origX, float origY) { 531f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein boolean interceptLeft = false; 532f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein boolean interceptRight = false; 533f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 53479bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei for (OnScreenListener listener : mScreenListeners.values()) { 535f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (!interceptLeft) { 536f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein interceptLeft = listener.onInterceptMoveLeft(origX, origY); 537f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 538f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (!interceptRight) { 539f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein interceptRight = listener.onInterceptMoveRight(origX, origY); 540f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 541f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 542f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 543f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (interceptLeft) { 544f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (interceptRight) { 545f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return InterceptType.BOTH; 546f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 547f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return InterceptType.LEFT; 548f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } else if (interceptRight) { 549f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return InterceptType.RIGHT; 550f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 551f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return InterceptType.NONE; 552f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 553f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 554f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** 555f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * Updates the title bar according to the value of {@link #mFullScreen}. 556f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein */ 5570ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp protected void setFullScreen(boolean fullScreen, boolean setDelayedRunnable) { 558f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein final boolean fullScreenChanged = (fullScreen != mFullScreen); 559f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein mFullScreen = fullScreen; 560f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 561f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (mFullScreen) { 5621abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein setLightsOutMode(true); 56340a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook cancelEnterFullScreenRunnable(); 564f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } else { 5651abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein setLightsOutMode(false); 5661abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein if (setDelayedRunnable) { 56740a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook postEnterFullScreenRunnableWithDelay(); 5681abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein } 569f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 570f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 571f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (fullScreenChanged) { 57279bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei for (OnScreenListener listener : mScreenListeners.values()) { 5731abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein listener.onFullScreenChanged(mFullScreen); 5741abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein } 5751abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein } 5761abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein } 5771abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein 57840a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook private void postEnterFullScreenRunnableWithDelay() { 57940a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook mHandler.postDelayed(mEnterFullScreenRunnable, mEnterFullScreenDelayTime); 580150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein } 581150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein 58240a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook private void cancelEnterFullScreenRunnable() { 58340a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook mHandler.removeCallbacks(mEnterFullScreenRunnable); 584150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein } 585150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein 5867e6995626b551c215bc3064c95b9996af940746aAdam Copp protected void setLightsOutMode(boolean enabled) { 587ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon int flags = 0; 588ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final int version = Build.VERSION.SDK_INT; 589ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final ActionBar actionBar = getSupportActionBar(); 590ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (enabled) { 591ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (version >= android.os.Build.VERSION_CODES.JELLY_BEAN) { 592ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon flags = View.SYSTEM_UI_FLAG_LOW_PROFILE 593ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 594ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon | View.SYSTEM_UI_FLAG_LAYOUT_STABLE; 595ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (!mScaleAnimationEnabled) { 596ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // If we are using the scale animation for intro and exit, 597ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // we can't go into fullscreen mode. The issue is that the 598ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // activity that invoked this will not be in fullscreen, so 599ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // as we transition out, the background activity will be 600ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // temporarily rendered without an actionbar, and the shrinking 601ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // photo will not line up properly. After that it redraws 602ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // in the correct location, but it still looks janks. 603ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // FLAG: there may be a better way to fix this, but I don't 604ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // yet know what it is. 605ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon flags |= View.SYSTEM_UI_FLAG_FULLSCREEN; 606ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 607ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else if (version >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 608ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon flags = View.SYSTEM_UI_FLAG_LOW_PROFILE; 609ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else if (version >= android.os.Build.VERSION_CODES.HONEYCOMB) { 610ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon flags = View.STATUS_BAR_HIDDEN; 611ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 612ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon actionBar.hide(); 6131abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein } else { 614ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (version >= android.os.Build.VERSION_CODES.JELLY_BEAN) { 615ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon flags = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 616ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon | View.SYSTEM_UI_FLAG_LAYOUT_STABLE; 617ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else if (version >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 618ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon flags = View.SYSTEM_UI_FLAG_VISIBLE; 619ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else if (version >= android.os.Build.VERSION_CODES.HONEYCOMB) { 620ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon flags = View.STATUS_BAR_VISIBLE; 621f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 622ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon actionBar.show(); 623ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 624ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 625ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (version >= Build.VERSION_CODES.HONEYCOMB) { 626ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mRootView.setSystemUiVisibility(flags); 627f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 628f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 629f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 630ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private final Runnable mEnterFullScreenRunnable = new Runnable() { 6311abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein @Override 6321abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein public void run() { 633b462d1bf5d3833fabbdc38d13f66dadcf6ceda54Adam Copp setFullScreen(true, true); 6341abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein } 6351abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein }; 6361abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein 637399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon @Override 63879bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei public void setViewActivated(int position) { 63979bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei OnScreenListener listener = mScreenListeners.get(position); 64079bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei if (listener != null) { 641f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein listener.onViewActivated(); 642f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 643ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final Cursor cursor = getCursorAtProperPosition(); 644ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mCurrentPhotoIndex = position; 645ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // FLAG: get the column indexes once in onLoadFinished(). 646ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // That would make this more efficient, instead of looking these up 647ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // repeatedly whenever we want them. 648ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon int uriIndex = cursor.getColumnIndex(PhotoContract.PhotoViewColumns.URI); 649ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mCurrentPhotoUri = cursor.getString(uriIndex); 650ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon updateActionBar(); 651ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 652ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // Restart the timer to return to fullscreen. 653ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon cancelEnterFullScreenRunnable(); 654ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon postEnterFullScreenRunnableWithDelay(); 655f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 656f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 657f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** 658f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * Adjusts the activity title and subtitle to reflect the photo name and count. 659f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein */ 6607b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal protected void updateActionBar() { 661f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein final int position = mViewPager.getCurrentItem() + 1; 662f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein final boolean hasAlbumCount = mAlbumCount >= 0; 663f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 664f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein final Cursor cursor = getCursorAtProperPosition(); 665f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (cursor != null) { 666ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // FLAG: We should grab the indexes when we first get the cursor 667ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // and store them so we don't need to do it each time. 668f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein final int photoNameIndex = cursor.getColumnIndex(PhotoContract.PhotoViewColumns.NAME); 6697b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal mActionBarTitle = cursor.getString(photoNameIndex); 67068a16aa04f9b98868f4412e7324b0fc292c9d858Andrew Sapperstein } else { 6717b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal mActionBarTitle = null; 672f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 673f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 674f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (mIsEmpty || !hasAlbumCount || position <= 0) { 6757b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal mActionBarSubtitle = null; 676f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } else { 6777b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal mActionBarSubtitle = 6787b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal getResources().getString(R.string.photo_view_count, position, mAlbumCount); 679f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 680ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 681ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon setActionBarTitles(getSupportActionBar()); 6827b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal } 683f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 6847b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal /** 6857b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal * Sets the Action Bar title to {@link #mActionBarTitle} and the subtitle to 6867b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal * {@link #mActionBarSubtitle} 6877b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal */ 688ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected final void setActionBarTitles(ActionBar actionBar) { 6897b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal if (actionBar == null) { 6907b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal return; 6917b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal } 6927b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal actionBar.setTitle(getInputOrEmpty(mActionBarTitle)); 6937b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal actionBar.setSubtitle(getInputOrEmpty(mActionBarSubtitle)); 6947b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal } 6957b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal 6967b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal /** 6977b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal * If the input string is non-null, it is returned, otherwise an empty string is returned; 6987b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal * @param in 6997b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal * @return 7007b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal */ 7017b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal private static final String getInputOrEmpty(String in) { 7027b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal if (in == null) { 7037b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal return ""; 7047b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal } 7057b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal return in; 706f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 707f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 708f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein /** 709f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * Utility method that will return the cursor that contains the data 710f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * at the current position so that it refers to the current image on screen. 711f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * @return the cursor at the current position or 712f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * null if no cursor exists or if the {@link PhotoViewPager} is null. 713f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein */ 714f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein public Cursor getCursorAtProperPosition() { 715f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (mViewPager == null) { 716f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return null; 717f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 718f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 719f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein final int position = mViewPager.getCurrentItem(); 720f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein final Cursor cursor = mAdapter.getCursor(); 721f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 722f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein if (cursor == null) { 723f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return null; 724f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 725f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 726f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein cursor.moveToPosition(position); 727f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein 728f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return cursor; 729f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein } 7309007d640832f674a9d65058a3c2a484c078d239eAndrew Sapperstein 7319007d640832f674a9d65058a3c2a484c078d239eAndrew Sapperstein public Cursor getCursor() { 7329007d640832f674a9d65058a3c2a484c078d239eAndrew Sapperstein return (mAdapter == null) ? null : mAdapter.getCursor(); 7339007d640832f674a9d65058a3c2a484c078d239eAndrew Sapperstein } 734150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein 735150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein @Override 736150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein public void onMenuVisibilityChanged(boolean isVisible) { 737150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein if (isVisible) { 73840a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook cancelEnterFullScreenRunnable(); 739150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein } else { 74040a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook postEnterFullScreenRunnableWithDelay(); 741150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein } 742150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein } 7430ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp 7440bf849421d303e05c600cdcd7dab73cc84809a36Mark Wei @Override 74579bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei public void onNewPhotoLoaded(int position) { 74679bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei // do nothing 7478f359e98b9f18064a75c80b9c9ad8bda2713c612Paul Westbrook } 7488f359e98b9f18064a75c80b9c9ad8bda2713c612Paul Westbrook 74913ea5dd3a7a3ab4214c6c5dea72a14ccd434d4b1Martin Hibdon protected void setPhotoIndex(int index) { 75013ea5dd3a7a3ab4214c6c5dea72a14ccd434d4b1Martin Hibdon mCurrentPhotoIndex = index; 75113ea5dd3a7a3ab4214c6c5dea72a14ccd434d4b1Martin Hibdon } 75213ea5dd3a7a3ab4214c6c5dea72a14ccd434d4b1Martin Hibdon 753ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon @Override 754ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void onFragmentPhotoLoadComplete(PhotoViewFragment fragment, boolean success) { 755ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (mTemporaryImage.getVisibility() != View.GONE && 756ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon TextUtils.equals(fragment.getPhotoUri(), mCurrentPhotoUri)) { 757ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (success) { 758ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // The fragment for the current image is now ready for display. 759ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mTemporaryImage.setVisibility(View.GONE); 760ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mViewPager.setVisibility(View.VISIBLE); 761ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else { 762ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // This means that we are unable to load the fragment's photo. 763ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // I'm not sure what the best thing to do here is, but at least if 764ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // we display the viewPager, the fragment itself can decide how to 765ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // display the failure of its own image. 766ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon Log.w(TAG, "Failed to load fragment image"); 767ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mTemporaryImage.setVisibility(View.GONE); 768ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mViewPager.setVisibility(View.VISIBLE); 769ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 770ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 7710ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp } 7720ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp 773ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon protected boolean isFullScreen() { 774ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon return mFullScreen; 7750ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp } 7768746927a945358bb9e515985a37cac7807261026Martin Hibdon 7770bf849421d303e05c600cdcd7dab73cc84809a36Mark Wei @Override 7780bf849421d303e05c600cdcd7dab73cc84809a36Mark Wei public void onCursorChanged(PhotoViewFragment fragment, Cursor cursor) { 7790bf849421d303e05c600cdcd7dab73cc84809a36Mark Wei // do nothing 7800bf849421d303e05c600cdcd7dab73cc84809a36Mark Wei } 78141db3eb9741a222432b367409c67d2263856a0a7Vikram Aggarwal 78241db3eb9741a222432b367409c67d2263856a0a7Vikram Aggarwal @Override 78341db3eb9741a222432b367409c67d2263856a0a7Vikram Aggarwal public PhotoPagerAdapter getAdapter() { 78441db3eb9741a222432b367409c67d2263856a0a7Vikram Aggarwal return mAdapter; 78541db3eb9741a222432b367409c67d2263856a0a7Vikram Aggarwal } 786ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 787ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void onEnterAnimationComplete() { 788ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mEnterAnimationFinished = true; 789ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mViewPager.setVisibility(View.VISIBLE); 790ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 791ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 792ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private void onExitAnimationComplete() { 793ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon finish(); 794ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon overridePendingTransition(0, 0); 795ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 796ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 797ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private void runEnterAnimation() { 798ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final int totalWidth = mRootView.getMeasuredWidth(); 799ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final int totalHeight = mRootView.getMeasuredHeight(); 800ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 801ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // FLAG: Need to handle the aspect ratio of the bitmap. If it's a portrait 802ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // bitmap, then we need to position the view higher so that the middle 803ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // pixels line up. 804ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mTemporaryImage.setVisibility(View.VISIBLE); 805ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // We need to take a full screen image, and scale/translate it so that 806ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // it appears at exactly the same location onscreen as it is in the 807ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // prior activity. 808ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // The final image will take either the full screen width or height (or both). 809ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 810ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final float scaleW = (float) mAnimationStartWidth / totalWidth; 811ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final float scaleY = (float) mAnimationStartHeight / totalHeight; 812ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final float scale = Math.max(scaleW, scaleY); 813ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 814ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final int translateX = calculateTranslate(mAnimationStartX, mAnimationStartWidth, 815ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon totalWidth, scale); 816ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final int translateY = calculateTranslate(mAnimationStartY, mAnimationStartHeight, 817ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon totalHeight, scale); 818ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 819ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final int version = android.os.Build.VERSION.SDK_INT; 8206e7a042765456b4d5faa95d591735abc06c274aeAndrew Sapperstein if (version >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 821ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mBackground.setAlpha(0f); 822ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mBackground.animate().alpha(1f).setDuration(ENTER_ANIMATION_DURATION_MS).start(); 823ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mBackground.setVisibility(View.VISIBLE); 824ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 825ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mTemporaryImage.setScaleX(scale); 826ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mTemporaryImage.setScaleY(scale); 827ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mTemporaryImage.setTranslationX(translateX); 828ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mTemporaryImage.setTranslationY(translateY); 829ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 830ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon Runnable endRunnable = new Runnable() { 831ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon @Override 832ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void run() { 833ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon PhotoViewActivity.this.onEnterAnimationComplete(); 834ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 835ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon }; 836ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon ViewPropertyAnimator animator = mTemporaryImage.animate().scaleX(1f).scaleY(1f) 837ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon .translationX(0).translationY(0).setDuration(ENTER_ANIMATION_DURATION_MS); 8386e7a042765456b4d5faa95d591735abc06c274aeAndrew Sapperstein if (version >= Build.VERSION_CODES.JELLY_BEAN) { 839ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon animator.withEndAction(endRunnable); 840ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else { 841ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mHandler.postDelayed(endRunnable, ENTER_ANIMATION_DURATION_MS); 842ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 843ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon animator.start(); 844ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else { 845ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final Animation alphaAnimation = new AlphaAnimation(0f, 1f); 846ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon alphaAnimation.setDuration(ENTER_ANIMATION_DURATION_MS); 847ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mBackground.startAnimation(alphaAnimation); 848ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mBackground.setVisibility(View.VISIBLE); 849ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 850ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final Animation translateAnimation = new TranslateAnimation(translateX, 851ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon translateY, 0, 0); 852ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon translateAnimation.setDuration(ENTER_ANIMATION_DURATION_MS); 853ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon Animation scaleAnimation = new ScaleAnimation(scale, scale, 0, 0); 854ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon scaleAnimation.setDuration(ENTER_ANIMATION_DURATION_MS); 855ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 856ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon AnimationSet animationSet = new AnimationSet(true); 857ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon animationSet.addAnimation(translateAnimation); 858ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon animationSet.addAnimation(scaleAnimation); 859ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon AnimationListener listener = new AnimationListener() { 860ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon @Override 861ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void onAnimationEnd(Animation arg0) { 862ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon PhotoViewActivity.this.onEnterAnimationComplete(); 863ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 864ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 865ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon @Override 866ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void onAnimationRepeat(Animation arg0) { 867ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 868ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 869ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon @Override 870ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void onAnimationStart(Animation arg0) { 871ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 872ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon }; 873ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon animationSet.setAnimationListener(listener); 874ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mTemporaryImage.startAnimation(animationSet); 875ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 876ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 877ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 878ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private void runExitAnimation() { 879ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon Intent intent = getIntent(); 880ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // FLAG: should just fall back to a standard animation if either: 881ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // 1. images have been added or removed since we've been here, or 882ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // 2. we are currently looking at some image other than the one we 883ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // started on. 884ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 885ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final int totalWidth = mRootView.getMeasuredWidth(); 886ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final int totalHeight = mRootView.getMeasuredHeight(); 887ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 888ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // We need to take a full screen image, and scale/translate it so that 889ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // it appears at exactly the same location onscreen as it is in the 890ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // prior activity. 891ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // The final image will take either the full screen width or height (or both). 892ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final float scaleW = (float) mAnimationStartWidth / totalWidth; 893ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final float scaleY = (float) mAnimationStartHeight / totalHeight; 894ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final float scale = Math.max(scaleW, scaleY); 895ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 896ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final int translateX = calculateTranslate(mAnimationStartX, mAnimationStartWidth, 897ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon totalWidth, scale); 898ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final int translateY = calculateTranslate(mAnimationStartY, mAnimationStartHeight, 899ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon totalHeight, scale); 900ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final int version = android.os.Build.VERSION.SDK_INT; 9016e7a042765456b4d5faa95d591735abc06c274aeAndrew Sapperstein if (version >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 902ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mBackground.animate().alpha(0f).setDuration(EXIT_ANIMATION_DURATION_MS).start(); 903ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mBackground.setVisibility(View.VISIBLE); 904ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 905ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon Runnable endRunnable = new Runnable() { 906ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon @Override 907ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void run() { 908ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon PhotoViewActivity.this.onExitAnimationComplete(); 909ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 910ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon }; 911ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // If the temporary image is still visible it means that we have 912ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // not yet loaded the fullres image, so we need to animate 913ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // the temporary image out. 914ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon ViewPropertyAnimator animator = null; 915ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (mTemporaryImage.getVisibility() == View.VISIBLE) { 916ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon animator = mTemporaryImage.animate().scaleX(scale).scaleY(scale) 917ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon .translationX(translateX).translationY(translateY) 918ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon .setDuration(EXIT_ANIMATION_DURATION_MS); 919ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else { 920ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon animator = mViewPager.animate().scaleX(scale).scaleY(scale) 921ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon .translationX(translateX).translationY(translateY) 922ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon .setDuration(EXIT_ANIMATION_DURATION_MS); 923ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 924ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (version >= android.os.Build.VERSION_CODES.JELLY_BEAN) { 925ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon animator.withEndAction(endRunnable); 926ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else { 927ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mHandler.postDelayed(endRunnable, EXIT_ANIMATION_DURATION_MS); 928ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 929ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon animator.start(); 930ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else { 931ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final Animation alphaAnimation = new AlphaAnimation(1f, 0f); 932ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon alphaAnimation.setDuration(EXIT_ANIMATION_DURATION_MS); 933ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mBackground.startAnimation(alphaAnimation); 934ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mBackground.setVisibility(View.VISIBLE); 935ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 936ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final Animation scaleAnimation = new ScaleAnimation(1f, 1f, scale, scale); 937ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon scaleAnimation.setDuration(EXIT_ANIMATION_DURATION_MS); 938ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon AnimationListener listener = new AnimationListener() { 939ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon @Override 940ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void onAnimationEnd(Animation arg0) { 941ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon PhotoViewActivity.this.onExitAnimationComplete(); 942ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 943ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 944ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon @Override 945ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void onAnimationRepeat(Animation arg0) { 946ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 947ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 948ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon @Override 949ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void onAnimationStart(Animation arg0) { 950ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 951ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon }; 952ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon scaleAnimation.setAnimationListener(listener); 953ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // If the temporary image is still visible it means that we have 954ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // not yet loaded the fullres image, so we need to animate 955ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // the temporary image out. 956ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (mTemporaryImage.getVisibility() == View.VISIBLE) { 957ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mTemporaryImage.startAnimation(scaleAnimation); 958ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else { 959ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mViewPager.startAnimation(scaleAnimation); 960ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 961ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 962ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 963ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 964ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private int calculateTranslate(int start, int startSize, int totalSize, float scale) { 965ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // Translation takes precedence over scale. What this means is that if 966ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // we want an view's upper left corner to be a particular spot on screen, 967ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // but that view is scaled to something other than 1, we need to take into 968ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // account the pixels lost to scaling. 969ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // So if we have a view that is 200x300, and we want it's upper left corner 970ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // to be at 50x50, but it's scaled by 50%, we can't just translate it to 50x50. 971ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // If we were to do that, the view's *visible* upper left corner would be at 972ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // 100x200. We need to take into account the difference between the outside 973ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // size of the view (i.e. the size prior to scaling) and the scaled size. 974ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // scaleFromEdge is the difference between the visible left edge and the 975ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // actual left edge, due to scaling. 976ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // scaleFromTop is the difference between the visible top edge, and the 977ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // actual top edge, due to scaling. 978ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon int scaleFromEdge = Math.round((totalSize - totalSize * scale) / 2); 979ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 980ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // The imageView is fullscreen, regardless of the aspect ratio of the actual image. 981ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // This means that some portion of the imageView will be blank. We need to 982ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // take into account the size of the blank area so that the actual image 983ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // lines up with the starting image. 984ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon int blankSize = Math.round((totalSize * scale - startSize) / 2); 985ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 986ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon return start - scaleFromEdge - blankSize; 987ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 988ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 989ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private void initTemporaryImage(Bitmap bitmap) { 99018c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon if (mEnterAnimationFinished) { 99118c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon // Forget this, we've already run the animation. 99218c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon return; 99318c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon } 994ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon mTemporaryImage.setImageBitmap(bitmap); 995ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (bitmap != null) { 99618c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon // We have not yet run the enter animation. Start it now. 99718c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon int totalWidth = mRootView.getMeasuredWidth(); 99818c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon if (totalWidth == 0) { 99918c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon // the measure pass has not yet finished. We can't properly 100018c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon // run out animation until that is done. Listen for the layout 100118c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon // to occur, then fire the animation. 100218c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon final View base = mRootView; 100318c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon base.getViewTreeObserver().addOnGlobalLayoutListener( 100418c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon new OnGlobalLayoutListener() { 100518c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon @Override 100618c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon public void onGlobalLayout() { 100718c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon int version = android.os.Build.VERSION.SDK_INT; 100818c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon if (version >= android.os.Build.VERSION_CODES.JELLY_BEAN) { 100918c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon base.getViewTreeObserver().removeOnGlobalLayoutListener(this); 101018c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon } else { 101118c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon base.getViewTreeObserver().removeGlobalOnLayoutListener(this); 1012ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 101318c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon runEnterAnimation(); 101418c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon } 101518c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon }); 101618c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon } else { 101718c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon // initiate the animation 101818c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon runEnterAnimation(); 1019ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 1020ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 1021ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // Kick off the photo list loader 1022ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon getSupportLoaderManager().initLoader(LOADER_PHOTO_LIST, null, this); 1023ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 1024ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 1025ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon private class BitmapCallback implements LoaderManager.LoaderCallbacks<BitmapResult> { 1026ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 1027ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon @Override 1028ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public Loader<BitmapResult> onCreateLoader(int id, Bundle args) { 1029ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon String uri = args.getString(ARG_IMAGE_URI); 1030ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon switch (id) { 1031ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon case PhotoViewCallbacks.BITMAP_LOADER_THUMBNAIL: 1032ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon return onCreateBitmapLoader(PhotoViewCallbacks.BITMAP_LOADER_THUMBNAIL, 1033ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon args, uri); 1034ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon case PhotoViewCallbacks.BITMAP_LOADER_AVATAR: 1035ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon return onCreateBitmapLoader(PhotoViewCallbacks.BITMAP_LOADER_AVATAR, 1036ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon args, uri); 1037ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 1038ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon return null; 1039ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 1040ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 1041ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon @Override 1042ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void onLoadFinished(Loader<BitmapResult> loader, BitmapResult result) { 1043ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon Bitmap bitmap = result.bitmap; 1044ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon final ActionBar actionBar = getSupportActionBar(); 1045ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon switch (loader.getId()) { 1046ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon case PhotoViewCallbacks.BITMAP_LOADER_THUMBNAIL: 1047ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // We just loaded the initial thumbnail that we can display 1048ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // while waiting for the full viewPager to get initialized. 1049ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon initTemporaryImage(bitmap); 105018c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon // Destroy the loader so we don't attempt to load the thumbnail 105118c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon // again on screen rotations. 105218c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon getSupportLoaderManager().destroyLoader( 105318c85692c141d3a0266dfe88f16f41ae1f20d13eMartin Hibdon PhotoViewCallbacks.BITMAP_LOADER_THUMBNAIL); 1054ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon break; 1055ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon case PhotoViewCallbacks.BITMAP_LOADER_AVATAR: 1056ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon if (bitmap == null) { 1057ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon actionBar.setLogo(null); 1058ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } else { 1059ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon BitmapDrawable drawable = new BitmapDrawable(getResources(), bitmap); 1060ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon actionBar.setLogo(drawable); 1061ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 1062ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon break; 1063ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 1064ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 1065ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon 1066ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon @Override 1067ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon public void onLoaderReset(Loader<BitmapResult> loader) { 1068ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon // Do nothing 1069ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 1070ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon } 1071f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein} 1072