Fields Summary |
---|
private static final String | TAG |
private static final String | STATE_INITIAL_URI_KEY |
private static final String | STATE_CURRENT_URI_KEY |
private static final String | STATE_CURRENT_INDEX_KEY |
private static final String | STATE_FULLSCREEN_KEY |
private static final String | STATE_ACTIONBARTITLE_KEY |
private static final String | STATE_ACTIONBARSUBTITLE_KEY |
private static final String | STATE_ENTERANIMATIONFINISHED_KEY |
protected static final String | ARG_IMAGE_URI |
public static final int | LOADER_PHOTO_LIST |
public static final int | ALBUM_COUNT_UNKNOWNCount used when the real photo count is unknown [but, may be determined] |
public static final int | ENTER_ANIMATION_DURATION_MS |
public static final int | EXIT_ANIMATION_DURATION_MS |
public static final String | KEY_MESSAGEArgument key for the dialog message |
public static int | sMemoryClass |
public static int | sMaxPhotoSize |
private final ActivityInterface | mActivity |
private int | mLastFlags |
private final View.OnSystemUiVisibilityChangeListener | mSystemUiVisibilityChangeListener |
private String | mPhotosUriThe URI of the photos we're viewing; may be {@code null} |
private String | mInitialPhotoUriThe uri of the initial photo |
private int | mCurrentPhotoIndexThe index of the currently viewed photo |
private String | mCurrentPhotoUriThe uri of the currently viewed photo |
private String[] | mProjectionThe query projection to use; may be {@code null} |
protected int | mAlbumCountThe total number of photos; only valid if {@link #mIsEmpty} is {@code false}. |
protected boolean | mIsEmpty{@code true} if the view is empty. Otherwise, {@code false}. |
protected android.view.View | mRootViewthe main root view |
protected android.view.View | mBackgroundBackground image that contains nothing, so it can be alpha faded from
transparent to black without affecting any other views. |
protected PhotoViewPager | mViewPagerThe main pager; provides left/right swipe between photos |
protected android.widget.ImageView | mTemporaryImageThe temporary image so that we can quickly scale up the fullscreen thumbnail |
protected com.android.ex.photo.adapters.PhotoPagerAdapter | mAdapterAdapter to create pager views |
protected boolean | mFullScreenWhether or not we're in "full screen" mode |
private final Map | mScreenListenersThe listeners wanting full screen state for each screen position |
private final Set | mCursorListenersThe set of listeners wanting full screen state |
private boolean | mKickLoaderWhen {@code true}, restart the loader when the activity becomes active |
private boolean | mIsDestroyedCompatDon't attempt operations that may trigger a fragment transaction when the activity is
destroyed |
protected boolean | mIsPausedWhether or not this activity is paused |
protected float | mMaxInitialScaleThe maximum scale factor applied to images when they are initially displayed |
protected String | mActionBarTitleThe title in the actionbar |
protected String | mActionBarSubtitleThe subtitle in the actionbar |
private boolean | mEnterAnimationFinished |
protected boolean | mScaleAnimationEnabled |
protected int | mAnimationStartX |
protected int | mAnimationStartY |
protected int | mAnimationStartWidth |
protected int | mAnimationStartHeight |
protected boolean | mActionBarHiddenInitially |
protected boolean | mDisplayThumbsFullScreen |
private final android.view.accessibility.AccessibilityManager | mAccessibilityManager |
protected BitmapCallback | mBitmapCallback |
protected final android.os.Handler | mHandler |
private long | mEnterFullScreenDelayTime |
private final Runnable | mEnterFullScreenRunnable |
Methods Summary |
---|
public synchronized void | addCursorListener(CursorChangedListener listener)
mCursorListeners.add(listener);
|
public void | addScreenListener(int position, OnScreenListener listener)
mScreenListeners.put(position, listener);
|
private int | calculateTranslate(int start, int startSize, int totalSize, float scale)
// Translation takes precedence over scale. What this means is that if
// we want an view's upper left corner to be a particular spot on screen,
// but that view is scaled to something other than 1, we need to take into
// account the pixels lost to scaling.
// So if we have a view that is 200x300, and we want it's upper left corner
// to be at 50x50, but it's scaled by 50%, we can't just translate it to 50x50.
// If we were to do that, the view's *visible* upper left corner would be at
// 100x200. We need to take into account the difference between the outside
// size of the view (i.e. the size prior to scaling) and the scaled size.
// scaleFromEdge is the difference between the visible left edge and the
// actual left edge, due to scaling.
// scaleFromTop is the difference between the visible top edge, and the
// actual top edge, due to scaling.
int scaleFromEdge = Math.round((totalSize - totalSize * scale) / 2);
// The imageView is fullscreen, regardless of the aspect ratio of the actual image.
// This means that some portion of the imageView will be blank. We need to
// take into account the size of the blank area so that the actual image
// lines up with the starting image.
int blankSize = Math.round((totalSize * scale - startSize) / 2);
return start - scaleFromEdge - blankSize;
|
private void | cancelEnterFullScreenRunnable()
mHandler.removeCallbacks(mEnterFullScreenRunnable);
|
public com.android.ex.photo.adapters.PhotoPagerAdapter | createPhotoPagerAdapter(android.content.Context context, android.support.v4.app.FragmentManager fm, android.database.Cursor c, float maxScale)
return new PhotoPagerAdapter(context, fm, c, maxScale, mDisplayThumbsFullScreen);
|
protected android.view.View | findViewById(int id)
return mActivity.findViewById(id);
|
public com.android.ex.photo.PhotoViewController$ActivityInterface | getActivity()
return mActivity;
|
public com.android.ex.photo.adapters.PhotoPagerAdapter | getAdapter()
return mAdapter;
|
public android.database.Cursor | getCursor()
return (mAdapter == null) ? null : mAdapter.getCursor();
|
public android.database.Cursor | getCursorAtProperPosition()Utility method that will return the cursor that contains the data
at the current position so that it refers to the current image on screen.
if (mViewPager == null) {
return null;
}
final int position = mViewPager.getCurrentItem();
final Cursor cursor = mAdapter.getCursor();
if (cursor == null) {
return null;
}
cursor.moveToPosition(position);
return cursor;
|
private static final java.lang.String | getInputOrEmpty(java.lang.String in)If the input string is non-null, it is returned, otherwise an empty string is returned;
if (in == null) {
return "";
}
return in;
|
protected java.lang.String | getPhotoAccessibilityAnnouncement(int position)Returns a string used as an announcement for accessibility after the user moves to a new
photo. It will be called after {@link #updateActionBar} has been called.
String announcement = mActionBarTitle;
if (mActionBarSubtitle != null) {
announcement = mActivity.getContext().getResources().getString(
R.string.titles, mActionBarTitle, mActionBarSubtitle);
}
return announcement;
|
public android.view.View | getRootView()
return mRootView;
|
public View.OnSystemUiVisibilityChangeListener | getSystemUiVisibilityChangeListener()Note: This should only be called when API level is 11 or above.
return mSystemUiVisibilityChangeListener;
|
public void | hideActionBar()
mActivity.getActionBarInterface().hide();
|
private void | initMaxPhotoSize()
if (sMaxPhotoSize == 0) {
final DisplayMetrics metrics = new DisplayMetrics();
final WindowManager wm = (WindowManager)
mActivity.getContext().getSystemService(Context.WINDOW_SERVICE);
final ImageUtils.ImageSize imageSize = ImageUtils.sUseImageSize;
wm.getDefaultDisplay().getMetrics(metrics);
switch (imageSize) {
case EXTRA_SMALL:
// Use a photo that's 80% of the "small" size
sMaxPhotoSize = (Math.min(metrics.heightPixels, metrics.widthPixels) * 800) / 1000;
break;
case SMALL:
// Fall through.
case NORMAL:
// Fall through.
default:
sMaxPhotoSize = Math.min(metrics.heightPixels, metrics.widthPixels);
break;
}
}
|
private void | initTemporaryImage(android.graphics.drawable.Drawable drawable)
if (mEnterAnimationFinished) {
// Forget this, we've already run the animation.
return;
}
mTemporaryImage.setImageDrawable(drawable);
if (drawable != null) {
// We have not yet run the enter animation. Start it now.
int totalWidth = mRootView.getMeasuredWidth();
if (totalWidth == 0) {
// the measure pass has not yet finished. We can't properly
// run out animation until that is done. Listen for the layout
// to occur, then fire the animation.
final View base = mRootView;
base.getViewTreeObserver().addOnGlobalLayoutListener(
new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int version = android.os.Build.VERSION.SDK_INT;
if (version >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
base.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
base.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
runEnterAnimation();
}
});
} else {
// initiate the animation
runEnterAnimation();
}
}
// Kick off the photo list loader
mActivity.getSupportLoaderManager().initLoader(LOADER_PHOTO_LIST, null, this);
|
private boolean | isDestroyedCompat()
return mIsDestroyedCompat;
|
public boolean | isEnterAnimationFinished()
return mEnterAnimationFinished;
|
public boolean | isFragmentActive(android.support.v4.app.Fragment fragment)
if (mViewPager == null || mAdapter == null) {
return false;
}
return mViewPager.getCurrentItem() == mAdapter.getItemPosition(fragment);
|
public boolean | isFragmentFullScreen(android.support.v4.app.Fragment fragment)
if (mViewPager == null || mAdapter == null || mAdapter.getCount() == 0) {
return mFullScreen;
}
return mFullScreen || (mViewPager.getCurrentItem() != mAdapter.getItemPosition(fragment));
|
protected boolean | isFullScreen()
return mFullScreen;
|
public boolean | isScaleAnimationEnabled()
return mScaleAnimationEnabled;
|
private boolean | kitkatIsSecondaryUser()Return true iff the app is being run as a secondary user on kitkat.
This is a hack which we only know to work on kitkat.
if (Build.VERSION.SDK_INT != Build.VERSION_CODES.KITKAT) {
throw new IllegalStateException("kitkatIsSecondary user is only callable on KitKat");
}
return Process.myUid() > 100000;
|
private synchronized void | notifyCursorListeners(android.database.Cursor data)
// tell all of the objects listening for cursor changes
// that the cursor has changed
for (CursorChangedListener listener : mCursorListeners) {
listener.onCursorChanged(data);
}
|
public void | onActivityResult(int requestCode, int resultCode, android.content.Intent data)
|
public boolean | onBackPressed()
// If we are in fullscreen mode, and the default is not full screen, then
// switch back to actionBar display mode.
if (mFullScreen && !mActionBarHiddenInitially) {
toggleFullScreen();
} else {
if (mScaleAnimationEnabled) {
runExitAnimation();
} else {
return false;
}
}
return true;
|
public void | onCreate(android.os.Bundle savedInstanceState)
initMaxPhotoSize();
final ActivityManager mgr = (ActivityManager) mActivity.getApplicationContext().
getSystemService(Activity.ACTIVITY_SERVICE);
sMemoryClass = mgr.getMemoryClass();
final Intent intent = mActivity.getIntent();
// uri of the photos to view; optional
if (intent.hasExtra(Intents.EXTRA_PHOTOS_URI)) {
mPhotosUri = intent.getStringExtra(Intents.EXTRA_PHOTOS_URI);
}
if (intent.getBooleanExtra(Intents.EXTRA_SCALE_UP_ANIMATION, false)) {
mScaleAnimationEnabled = true;
mAnimationStartX = intent.getIntExtra(Intents.EXTRA_ANIMATION_START_X, 0);
mAnimationStartY = intent.getIntExtra(Intents.EXTRA_ANIMATION_START_Y, 0);
mAnimationStartWidth = intent.getIntExtra(Intents.EXTRA_ANIMATION_START_WIDTH, 0);
mAnimationStartHeight = intent.getIntExtra(Intents.EXTRA_ANIMATION_START_HEIGHT, 0);
}
mActionBarHiddenInitially = intent.getBooleanExtra(
Intents.EXTRA_ACTION_BAR_HIDDEN_INITIALLY, false)
&& !Util.isTouchExplorationEnabled(mAccessibilityManager);
mDisplayThumbsFullScreen = intent.getBooleanExtra(
Intents.EXTRA_DISPLAY_THUMBS_FULLSCREEN, false);
// projection for the query; optional
// If not set, the default projection is used.
// This projection must include the columns from the default projection.
if (intent.hasExtra(Intents.EXTRA_PROJECTION)) {
mProjection = intent.getStringArrayExtra(Intents.EXTRA_PROJECTION);
} else {
mProjection = null;
}
// Set the max initial scale, defaulting to 1x
mMaxInitialScale = intent.getFloatExtra(Intents.EXTRA_MAX_INITIAL_SCALE, 1.0f);
mCurrentPhotoUri = null;
mCurrentPhotoIndex = -1;
// We allow specifying the current photo by either index or uri.
// This is because some users may have live datasets that can change,
// adding new items to either the beginning or end of the set. For clients
// that do not need that capability, ability to specify the current photo
// by index is offered as a convenience.
if (intent.hasExtra(Intents.EXTRA_PHOTO_INDEX)) {
mCurrentPhotoIndex = intent.getIntExtra(Intents.EXTRA_PHOTO_INDEX, -1);
}
if (intent.hasExtra(Intents.EXTRA_INITIAL_PHOTO_URI)) {
mInitialPhotoUri = intent.getStringExtra(Intents.EXTRA_INITIAL_PHOTO_URI);
mCurrentPhotoUri = mInitialPhotoUri;
}
mIsEmpty = true;
if (savedInstanceState != null) {
mInitialPhotoUri = savedInstanceState.getString(STATE_INITIAL_URI_KEY);
mCurrentPhotoUri = savedInstanceState.getString(STATE_CURRENT_URI_KEY);
mCurrentPhotoIndex = savedInstanceState.getInt(STATE_CURRENT_INDEX_KEY);
mFullScreen = savedInstanceState.getBoolean(STATE_FULLSCREEN_KEY, false)
&& !Util.isTouchExplorationEnabled(mAccessibilityManager);
mActionBarTitle = savedInstanceState.getString(STATE_ACTIONBARTITLE_KEY);
mActionBarSubtitle = savedInstanceState.getString(STATE_ACTIONBARSUBTITLE_KEY);
mEnterAnimationFinished = savedInstanceState.getBoolean(
STATE_ENTERANIMATIONFINISHED_KEY, false);
} else {
mFullScreen = mActionBarHiddenInitially;
}
mActivity.setContentView(R.layout.photo_activity_view);
// Create the adapter and add the view pager
mAdapter = createPhotoPagerAdapter(mActivity.getContext(),
mActivity.getSupportFragmentManager(), null, mMaxInitialScale);
final Resources resources = mActivity.getResources();
mRootView = findViewById(R.id.photo_activity_root_view);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
mRootView.setOnSystemUiVisibilityChangeListener(getSystemUiVisibilityChangeListener());
}
mBackground = findViewById(R.id.photo_activity_background);
mTemporaryImage = (ImageView) findViewById(R.id.photo_activity_temporary_image);
mViewPager = (PhotoViewPager) findViewById(R.id.photo_view_pager);
mViewPager.setAdapter(mAdapter);
mViewPager.setOnPageChangeListener(this);
mViewPager.setOnInterceptTouchListener(this);
mViewPager.setPageMargin(resources.getDimensionPixelSize(R.dimen.photo_page_margin));
mBitmapCallback = new BitmapCallback();
if (!mScaleAnimationEnabled || mEnterAnimationFinished) {
// We are not running the scale up animation. Just let the fragments
// display and handle the animation.
mActivity.getSupportLoaderManager().initLoader(LOADER_PHOTO_LIST, null, this);
// Make the background opaque immediately so that we don't see the activity
// behind this one.
mBackground.setVisibility(View.VISIBLE);
} else {
// Attempt to load the initial image thumbnail. Once we have the
// image, animate it up. Once the animation is complete, we can kick off
// loading the ViewPager. After the primary fullres image is loaded, we will
// make our temporary image invisible and display the ViewPager.
mViewPager.setVisibility(View.GONE);
Bundle args = new Bundle();
args.putString(ARG_IMAGE_URI, mInitialPhotoUri);
mActivity.getSupportLoaderManager().initLoader(
BITMAP_LOADER_THUMBNAIL, args, mBitmapCallback);
}
mEnterFullScreenDelayTime =
resources.getInteger(R.integer.reenter_fullscreen_delay_time_in_millis);
final ActionBarInterface actionBar = mActivity.getActionBarInterface();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.addOnMenuVisibilityListener(this);
actionBar.setDisplayOptionsShowTitle();
// Set the title and subtitle immediately here, rather than waiting
// for the fragment to be initialized.
setActionBarTitles(actionBar);
}
if (!mScaleAnimationEnabled) {
setLightsOutMode(mFullScreen);
} else {
// Keep lights out mode as false. This is to prevent jank cause by concurrent
// animations during the enter animation.
setLightsOutMode(false);
}
|
public android.support.v4.content.Loader | onCreateBitmapLoader(int id, android.os.Bundle args, java.lang.String uri)
switch (id) {
case BITMAP_LOADER_AVATAR:
case BITMAP_LOADER_THUMBNAIL:
case BITMAP_LOADER_PHOTO:
return new PhotoBitmapLoader(mActivity.getContext(), uri);
default:
return null;
}
|
public android.support.v4.content.Loader | onCreateLoader(int id, android.os.Bundle args)
if (id == LOADER_PHOTO_LIST) {
return new PhotoPagerLoader(mActivity.getContext(), Uri.parse(mPhotosUri), mProjection);
}
return null;
|
public boolean | onCreateOptionsMenu(android.view.Menu menu)
return true;
|
public void | onCursorChanged(com.android.ex.photo.fragments.PhotoViewFragment fragment, android.database.Cursor cursor)
// do nothing
|
public void | onDestroy()
mIsDestroyedCompat = true;
|
public void | onEnterAnimationComplete()
mEnterAnimationFinished = true;
mViewPager.setVisibility(View.VISIBLE);
setLightsOutMode(mFullScreen);
|
private void | onExitAnimationComplete()
mActivity.finish();
mActivity.overridePendingTransition(0, 0);
|
public void | onFragmentPhotoLoadComplete(com.android.ex.photo.fragments.PhotoViewFragment fragment, boolean success)
if (mTemporaryImage.getVisibility() != View.GONE &&
TextUtils.equals(fragment.getPhotoUri(), mCurrentPhotoUri)) {
if (success) {
// The fragment for the current image is now ready for display.
mTemporaryImage.setVisibility(View.GONE);
mViewPager.setVisibility(View.VISIBLE);
} else {
// This means that we are unable to load the fragment's photo.
// I'm not sure what the best thing to do here is, but at least if
// we display the viewPager, the fragment itself can decide how to
// display the failure of its own image.
Log.w(TAG, "Failed to load fragment image");
mTemporaryImage.setVisibility(View.GONE);
mViewPager.setVisibility(View.VISIBLE);
}
mActivity.getSupportLoaderManager().destroyLoader(
PhotoViewCallbacks.BITMAP_LOADER_THUMBNAIL);
}
|
public void | onFragmentVisible(com.android.ex.photo.fragments.PhotoViewFragment fragment)
// Do nothing, we handle this in setViewActivated
|
public void | onLoadFinished(android.support.v4.content.Loader loader, android.database.Cursor data)
final int id = loader.getId();
if (id == LOADER_PHOTO_LIST) {
if (data == null || data.getCount() == 0) {
mIsEmpty = true;
mAdapter.swapCursor(null);
} else {
mAlbumCount = data.getCount();
if (mCurrentPhotoUri != null) {
int index = 0;
// Clear query params. Compare only the path.
final int uriIndex = data.getColumnIndex(PhotoContract.PhotoViewColumns.URI);
final Uri currentPhotoUri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
currentPhotoUri = Uri.parse(mCurrentPhotoUri).buildUpon()
.clearQuery().build();
} else {
currentPhotoUri = Uri.parse(mCurrentPhotoUri).buildUpon()
.query(null).build();
}
// Rewind data cursor to the start if it has already advanced.
data.moveToPosition(-1);
while (data.moveToNext()) {
final String uriString = data.getString(uriIndex);
final Uri uri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
uri = Uri.parse(uriString).buildUpon().clearQuery().build();
} else {
uri = Uri.parse(uriString).buildUpon().query(null).build();
}
if (currentPhotoUri != null && currentPhotoUri.equals(uri)) {
mCurrentPhotoIndex = index;
break;
}
index++;
}
}
// We're paused; don't do anything now, we'll get re-invoked
// when the activity becomes active again
if (mIsPaused) {
mKickLoader = true;
mAdapter.swapCursor(null);
return;
}
boolean wasEmpty = mIsEmpty;
mIsEmpty = false;
mAdapter.swapCursor(data);
if (mViewPager.getAdapter() == null) {
mViewPager.setAdapter(mAdapter);
}
notifyCursorListeners(data);
// Use an index of 0 if the index wasn't specified or couldn't be found
if (mCurrentPhotoIndex < 0) {
mCurrentPhotoIndex = 0;
}
mViewPager.setCurrentItem(mCurrentPhotoIndex, false);
if (wasEmpty) {
setViewActivated(mCurrentPhotoIndex);
}
}
// Update the any action items
updateActionItems();
}
|
public void | onLoaderReset(android.support.v4.content.Loader loader)
// If the loader is reset, remove the reference in the adapter to this cursor
if (!isDestroyedCompat()) {
// This will cause a fragment transaction which can't happen if we're destroyed,
// but we don't care in that case because we're destroyed anyways.
mAdapter.swapCursor(null);
}
|
public void | onMenuVisibilityChanged(boolean isVisible)
if (isVisible) {
cancelEnterFullScreenRunnable();
} else {
postEnterFullScreenRunnableWithDelay();
}
|
public void | onNewPhotoLoaded(int position)
// do nothing
|
public boolean | onOptionsItemSelected(android.view.MenuItem item)
switch (item.getItemId()) {
case android.R.id.home:
mActivity.finish();
return true;
default:
return false;
}
|
public void | onPageScrollStateChanged(int state)
|
public void | onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
if (positionOffset < 0.0001) {
OnScreenListener before = mScreenListeners.get(position - 1);
if (before != null) {
before.onViewUpNext();
}
OnScreenListener after = mScreenListeners.get(position + 1);
if (after != null) {
after.onViewUpNext();
}
}
|
public void | onPageSelected(int position)
mCurrentPhotoIndex = position;
setViewActivated(position);
|
public void | onPause()
mIsPaused = true;
|
public void | onPhotoRemoved(long photoId)
final Cursor data = mAdapter.getCursor();
if (data == null) {
// Huh?! How would this happen?
return;
}
final int dataCount = data.getCount();
if (dataCount <= 1) {
mActivity.finish();
return;
}
mActivity.getSupportLoaderManager().restartLoader(LOADER_PHOTO_LIST, null, this);
|
public boolean | onPrepareOptionsMenu(android.view.Menu menu)
return true;
|
public void | onResume()
setFullScreen(mFullScreen, false);
mIsPaused = false;
if (mKickLoader) {
mKickLoader = false;
mActivity.getSupportLoaderManager().initLoader(LOADER_PHOTO_LIST, null, this);
}
|
public void | onSaveInstanceState(android.os.Bundle outState)
outState.putString(STATE_INITIAL_URI_KEY, mInitialPhotoUri);
outState.putString(STATE_CURRENT_URI_KEY, mCurrentPhotoUri);
outState.putInt(STATE_CURRENT_INDEX_KEY, mCurrentPhotoIndex);
outState.putBoolean(STATE_FULLSCREEN_KEY, mFullScreen);
outState.putString(STATE_ACTIONBARTITLE_KEY, mActionBarTitle);
outState.putString(STATE_ACTIONBARSUBTITLE_KEY, mActionBarSubtitle);
outState.putBoolean(STATE_ENTERANIMATIONFINISHED_KEY, mEnterAnimationFinished);
|
public void | onStart()
|
public void | onStop()
|
public com.android.ex.photo.PhotoViewPager.InterceptType | onTouchIntercept(float origX, float origY)
boolean interceptLeft = false;
boolean interceptRight = false;
for (OnScreenListener listener : mScreenListeners.values()) {
if (!interceptLeft) {
interceptLeft = listener.onInterceptMoveLeft(origX, origY);
}
if (!interceptRight) {
interceptRight = listener.onInterceptMoveRight(origX, origY);
}
}
if (interceptLeft) {
if (interceptRight) {
return InterceptType.BOTH;
}
return InterceptType.LEFT;
} else if (interceptRight) {
return InterceptType.RIGHT;
}
return InterceptType.NONE;
|
private void | postEnterFullScreenRunnableWithDelay()
mHandler.postDelayed(mEnterFullScreenRunnable, mEnterFullScreenDelayTime);
|
public synchronized void | removeCursorListener(CursorChangedListener listener)
mCursorListeners.remove(listener);
|
public void | removeScreenListener(int position)
mScreenListeners.remove(position);
|
private void | runEnterAnimation()
final int totalWidth = mRootView.getMeasuredWidth();
final int totalHeight = mRootView.getMeasuredHeight();
// FLAG: Need to handle the aspect ratio of the bitmap. If it's a portrait
// bitmap, then we need to position the view higher so that the middle
// pixels line up.
mTemporaryImage.setVisibility(View.VISIBLE);
// We need to take a full screen image, and scale/translate it so that
// it appears at exactly the same location onscreen as it is in the
// prior activity.
// The final image will take either the full screen width or height (or both).
final float scaleW = (float) mAnimationStartWidth / totalWidth;
final float scaleY = (float) mAnimationStartHeight / totalHeight;
final float scale = Math.max(scaleW, scaleY);
final int translateX = calculateTranslate(mAnimationStartX, mAnimationStartWidth,
totalWidth, scale);
final int translateY = calculateTranslate(mAnimationStartY, mAnimationStartHeight,
totalHeight, scale);
final int version = android.os.Build.VERSION.SDK_INT;
if (version >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
mBackground.setAlpha(0f);
mBackground.animate().alpha(1f).setDuration(ENTER_ANIMATION_DURATION_MS).start();
mBackground.setVisibility(View.VISIBLE);
mTemporaryImage.setScaleX(scale);
mTemporaryImage.setScaleY(scale);
mTemporaryImage.setTranslationX(translateX);
mTemporaryImage.setTranslationY(translateY);
Runnable endRunnable = new Runnable() {
@Override
public void run() {
PhotoViewController.this.onEnterAnimationComplete();
}
};
ViewPropertyAnimator animator = mTemporaryImage.animate().scaleX(1f).scaleY(1f)
.translationX(0).translationY(0).setDuration(ENTER_ANIMATION_DURATION_MS);
if (version >= Build.VERSION_CODES.JELLY_BEAN) {
animator.withEndAction(endRunnable);
} else {
mHandler.postDelayed(endRunnable, ENTER_ANIMATION_DURATION_MS);
}
animator.start();
} else {
final Animation alphaAnimation = new AlphaAnimation(0f, 1f);
alphaAnimation.setDuration(ENTER_ANIMATION_DURATION_MS);
mBackground.startAnimation(alphaAnimation);
mBackground.setVisibility(View.VISIBLE);
final Animation translateAnimation = new TranslateAnimation(translateX,
translateY, 0, 0);
translateAnimation.setDuration(ENTER_ANIMATION_DURATION_MS);
Animation scaleAnimation = new ScaleAnimation(scale, scale, 0, 0);
scaleAnimation.setDuration(ENTER_ANIMATION_DURATION_MS);
AnimationSet animationSet = new AnimationSet(true);
animationSet.addAnimation(translateAnimation);
animationSet.addAnimation(scaleAnimation);
AnimationListener listener = new AnimationListener() {
@Override
public void onAnimationEnd(Animation arg0) {
PhotoViewController.this.onEnterAnimationComplete();
}
@Override
public void onAnimationRepeat(Animation arg0) {
}
@Override
public void onAnimationStart(Animation arg0) {
}
};
animationSet.setAnimationListener(listener);
mTemporaryImage.startAnimation(animationSet);
}
|
private void | runExitAnimation()
Intent intent = mActivity.getIntent();
// FLAG: should just fall back to a standard animation if either:
// 1. images have been added or removed since we've been here, or
// 2. we are currently looking at some image other than the one we
// started on.
final int totalWidth = mRootView.getMeasuredWidth();
final int totalHeight = mRootView.getMeasuredHeight();
// We need to take a full screen image, and scale/translate it so that
// it appears at exactly the same location onscreen as it is in the
// prior activity.
// The final image will take either the full screen width or height (or both).
final float scaleW = (float) mAnimationStartWidth / totalWidth;
final float scaleY = (float) mAnimationStartHeight / totalHeight;
final float scale = Math.max(scaleW, scaleY);
final int translateX = calculateTranslate(mAnimationStartX, mAnimationStartWidth,
totalWidth, scale);
final int translateY = calculateTranslate(mAnimationStartY, mAnimationStartHeight,
totalHeight, scale);
final int version = android.os.Build.VERSION.SDK_INT;
if (version >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
mBackground.animate().alpha(0f).setDuration(EXIT_ANIMATION_DURATION_MS).start();
mBackground.setVisibility(View.VISIBLE);
Runnable endRunnable = new Runnable() {
@Override
public void run() {
PhotoViewController.this.onExitAnimationComplete();
}
};
// If the temporary image is still visible it means that we have
// not yet loaded the fullres image, so we need to animate
// the temporary image out.
ViewPropertyAnimator animator = null;
if (mTemporaryImage.getVisibility() == View.VISIBLE) {
animator = mTemporaryImage.animate().scaleX(scale).scaleY(scale)
.translationX(translateX).translationY(translateY)
.setDuration(EXIT_ANIMATION_DURATION_MS);
} else {
animator = mViewPager.animate().scaleX(scale).scaleY(scale)
.translationX(translateX).translationY(translateY)
.setDuration(EXIT_ANIMATION_DURATION_MS);
}
// If the user has swiped to a different photo, fade out the current photo
// along with the scale animation.
if (!mInitialPhotoUri.equals(mCurrentPhotoUri)) {
animator.alpha(0f);
}
if (version >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
animator.withEndAction(endRunnable);
} else {
mHandler.postDelayed(endRunnable, EXIT_ANIMATION_DURATION_MS);
}
animator.start();
} else {
final Animation alphaAnimation = new AlphaAnimation(1f, 0f);
alphaAnimation.setDuration(EXIT_ANIMATION_DURATION_MS);
mBackground.startAnimation(alphaAnimation);
mBackground.setVisibility(View.VISIBLE);
final Animation scaleAnimation = new ScaleAnimation(1f, 1f, scale, scale);
scaleAnimation.setDuration(EXIT_ANIMATION_DURATION_MS);
AnimationListener listener = new AnimationListener() {
@Override
public void onAnimationEnd(Animation arg0) {
PhotoViewController.this.onExitAnimationComplete();
}
@Override
public void onAnimationRepeat(Animation arg0) {
}
@Override
public void onAnimationStart(Animation arg0) {
}
};
scaleAnimation.setAnimationListener(listener);
// If the temporary image is still visible it means that we have
// not yet loaded the fullres image, so we need to animate
// the temporary image out.
if (mTemporaryImage.getVisibility() == View.VISIBLE) {
mTemporaryImage.startAnimation(scaleAnimation);
} else {
mViewPager.startAnimation(scaleAnimation);
}
}
|
protected final void | setActionBarTitles(ActionBarInterface actionBar)Sets the Action Bar title to {@link #mActionBarTitle} and the subtitle to
{@link #mActionBarSubtitle}
if (actionBar == null) {
return;
}
actionBar.setTitle(getInputOrEmpty(mActionBarTitle));
actionBar.setSubtitle(getInputOrEmpty(mActionBarSubtitle));
|
protected void | setFullScreen(boolean fullScreen, boolean setDelayedRunnable)Updates the title bar according to the value of {@link #mFullScreen}.
if (Util.isTouchExplorationEnabled(mAccessibilityManager)) {
// Disallow full screen mode when accessibility is enabled so that the action bar
// stays accessible.
fullScreen = false;
setDelayedRunnable = false;
}
final boolean fullScreenChanged = (fullScreen != mFullScreen);
mFullScreen = fullScreen;
if (mFullScreen) {
setLightsOutMode(true);
cancelEnterFullScreenRunnable();
} else {
setLightsOutMode(false);
if (setDelayedRunnable) {
postEnterFullScreenRunnableWithDelay();
}
}
if (fullScreenChanged) {
for (OnScreenListener listener : mScreenListeners.values()) {
listener.onFullScreenChanged(mFullScreen);
}
}
|
public void | setImmersiveMode(boolean enabled)
int flags = 0;
final int version = Build.VERSION.SDK_INT;
final boolean manuallyUpdateActionBar = version < Build.VERSION_CODES.JELLY_BEAN;
if (enabled &&
(!isScaleAnimationEnabled() || isEnterAnimationFinished())) {
// Turning on immersive mode causes an animation. If the scale animation is enabled and
// the enter animation isn't yet complete, then an immersive mode animation should not
// occur, since two concurrent animations are very janky.
// Disable immersive mode for seconary users to prevent b/12015090 (freezing crash)
// This is fixed in KK_MR2 but there is no way to differentiate between KK and KK_MR2.
if (version > Build.VERSION_CODES.KITKAT ||
version == Build.VERSION_CODES.KITKAT && !kitkatIsSecondaryUser()) {
flags = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE;
} else if (version >= Build.VERSION_CODES.JELLY_BEAN) {
// Clients that use the scale animation should set the following system UI flags to
// prevent janky animations on exit when the status bar is hidden:
// View.SYSTEM_UI_FLAG_VISIBLE | View.SYSTEM_UI_FLAG_STABLE
// As well, client should ensure `android:fitsSystemWindows` is set on the root
// content view.
flags = View.SYSTEM_UI_FLAG_LOW_PROFILE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_FULLSCREEN;
} else if (version >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
flags = View.SYSTEM_UI_FLAG_LOW_PROFILE;
} else if (version >= Build.VERSION_CODES.HONEYCOMB) {
flags = View.STATUS_BAR_HIDDEN;
}
if (manuallyUpdateActionBar) {
hideActionBar();
}
} else {
if (version >= Build.VERSION_CODES.KITKAT) {
flags = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
} else if (version >= Build.VERSION_CODES.JELLY_BEAN) {
flags = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
} else if (version >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
flags = View.SYSTEM_UI_FLAG_VISIBLE;
} else if (version >= Build.VERSION_CODES.HONEYCOMB) {
flags = View.STATUS_BAR_VISIBLE;
}
if (manuallyUpdateActionBar) {
showActionBar();
}
}
if (version >= Build.VERSION_CODES.HONEYCOMB) {
mLastFlags = flags;
getRootView().setSystemUiVisibility(flags);
}
|
protected void | setLightsOutMode(boolean enabled)
setImmersiveMode(enabled);
|
protected void | setPhotoIndex(int index)
mCurrentPhotoIndex = index;
|
public void | setViewActivated(int position)
OnScreenListener listener = mScreenListeners.get(position);
if (listener != null) {
listener.onViewActivated();
}
final Cursor cursor = getCursorAtProperPosition();
mCurrentPhotoIndex = position;
// FLAG: get the column indexes once in onLoadFinished().
// That would make this more efficient, instead of looking these up
// repeatedly whenever we want them.
int uriIndex = cursor.getColumnIndex(PhotoContract.PhotoViewColumns.URI);
mCurrentPhotoUri = cursor.getString(uriIndex);
updateActionBar();
if (mAccessibilityManager.isEnabled()) {
String announcement = getPhotoAccessibilityAnnouncement(position);
if (announcement != null) {
Util.announceForAccessibility(mRootView, mAccessibilityManager, announcement);
}
}
// Restart the timer to return to fullscreen.
cancelEnterFullScreenRunnable();
postEnterFullScreenRunnableWithDelay();
|
public void | showActionBar()
mActivity.getActionBarInterface().show();
|
public void | toggleFullScreen()
setFullScreen(!mFullScreen, true);
|
public void | updateActionBar()Adjusts the activity title and subtitle to reflect the photo name and count.
final int position = mViewPager.getCurrentItem() + 1;
final boolean hasAlbumCount = mAlbumCount >= 0;
final Cursor cursor = getCursorAtProperPosition();
if (cursor != null) {
// FLAG: We should grab the indexes when we first get the cursor
// and store them so we don't need to do it each time.
final int photoNameIndex = cursor.getColumnIndex(PhotoContract.PhotoViewColumns.NAME);
mActionBarTitle = cursor.getString(photoNameIndex);
} else {
mActionBarTitle = null;
}
if (mIsEmpty || !hasAlbumCount || position <= 0) {
mActionBarSubtitle = null;
} else {
mActionBarSubtitle = mActivity.getResources().getString(
R.string.photo_view_count, position, mAlbumCount);
}
setActionBarTitles(mActivity.getActionBarInterface());
|
public void | updateActionItems()
// Do nothing, but allow extending classes to do work
|