PhotoViewActivity.java revision 7b2d2778159adf9d01e5e7fc5371e49850b2e084
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.ActionBar;
21150e623129eef49467f1d6f67649e4636a4513f2Andrew Sappersteinimport android.app.ActionBar.OnMenuVisibilityListener;
22f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.app.Activity;
23f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.app.ActivityManager;
24d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrookimport android.content.Context;
25f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.content.Intent;
2629e47d946fd19443c12ebad9f94e83741c7d9120Paul Westbrookimport android.content.res.Resources;
27f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.database.Cursor;
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.FragmentActivity;
348746927a945358bb9e515985a37cac7807261026Martin Hibdonimport android.support.v4.app.LoaderManager;
358746927a945358bb9e515985a37cac7807261026Martin Hibdonimport android.support.v4.content.Loader;
36f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.support.v4.view.ViewPager.OnPageChangeListener;
37d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrookimport android.text.TextUtils;
38bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Coppimport android.view.MenuItem;
39f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.view.View;
40f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
41f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.PhotoViewPager.InterceptType;
42f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.PhotoViewPager.OnInterceptTouchListener;
43f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.adapters.PhotoPagerAdapter;
440c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sappersteinimport com.android.ex.photo.fragments.PhotoViewFragment;
45f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.loaders.PhotoPagerLoader;
46f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.provider.PhotoContract;
47f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
4879bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Weiimport java.util.HashMap;
49f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport java.util.HashSet;
5079bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Weiimport java.util.Map;
51f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport java.util.Set;
52f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
53f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein/**
54f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * Activity to view the contents of an album.
55f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein */
568746927a945358bb9e515985a37cac7807261026Martin Hibdonpublic class PhotoViewActivity extends FragmentActivity implements
578746927a945358bb9e515985a37cac7807261026Martin Hibdon        LoaderManager.LoaderCallbacks<Cursor>, OnPageChangeListener, OnInterceptTouchListener,
58399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon        OnMenuVisibilityListener, PhotoViewCallbacks {
590c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein
60f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private final static String STATE_ITEM_KEY =
61f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            "com.google.android.apps.plus.PhotoViewFragment.ITEM";
62f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private final static String STATE_FULLSCREEN_KEY =
63f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            "com.google.android.apps.plus.PhotoViewFragment.FULLSCREEN";
647b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal    private final static String STATE_ACTIONBARTITLE_KEY =
657b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal            "com.google.android.apps.plus.PhotoViewFragment.ACTIONBARTITLE";
667b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal    private final static String STATE_ACTIONBARSUBTITLE_KEY =
677b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal            "com.google.android.apps.plus.PhotoViewFragment.ACTIONBARSUBTITLE";
68f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
69f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private static final int LOADER_PHOTO_LIST = 1;
70f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
71f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** Count used when the real photo count is unknown [but, may be determined] */
72f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public static final int ALBUM_COUNT_UNKNOWN = -1;
73f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
74f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** Argument key for the dialog message */
75f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public static final String KEY_MESSAGE = "dialog_message";
76f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
77f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public static int sMemoryClass;
78f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
79f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** The URI of the photos we're viewing; may be {@code null} */
80f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private String mPhotosUri;
81d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook    /** The URI of the initial photo to display */
82d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook    private String mInitialPhotoUri;
83f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** The index of the currently viewed photo */
84f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private int mPhotoIndex;
85f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** The query projection to use; may be {@code null} */
86f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private String[] mProjection;
87f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** The total number of photos; only valid if {@link #mIsEmpty} is {@code false}. */
88f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private int mAlbumCount = ALBUM_COUNT_UNKNOWN;
89f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** {@code true} if the view is empty. Otherwise, {@code false}. */
90f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private boolean mIsEmpty;
91d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook    /** the main root view */
92d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook    protected View mRootView;
93f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** The main pager; provides left/right swipe between photos */
94d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook    protected PhotoViewPager mViewPager;
95f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** Adapter to create pager views */
96d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook    protected PhotoPagerAdapter mAdapter;
97f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** Whether or not we're in "full screen" mode */
98f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private boolean mFullScreen;
9979bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei    /** The listeners wanting full screen state for each screen position */
10079bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei    private Map<Integer, OnScreenListener>
10179bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei            mScreenListeners = new HashMap<Integer, OnScreenListener>();
1020c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    /** The set of listeners wanting full screen state */
1030c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    private Set<CursorChangedListener> mCursorListeners = new HashSet<CursorChangedListener>();
104f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** When {@code true}, restart the loader when the activity becomes active */
105f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private boolean mRestartLoader;
106f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** Whether or not this activity is paused */
107f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private boolean mIsPaused = true;
10891dbfd25cc234de393ae22fc39a832a6335e1bc2Adam Copp    /** The maximum scale factor applied to images when they are initially displayed */
10991dbfd25cc234de393ae22fc39a832a6335e1bc2Adam Copp    private float mMaxInitialScale;
1107b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal    /** The title in the actionbar */
1117b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal    private String mActionBarTitle;
1127b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal    /** The subtitle in the actionbar */
1137b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal    private String mActionBarSubtitle;
1147b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal
115e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook    private final Handler mHandler = new Handler();
116f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    // TODO Find a better way to do this. We basically want the activity to display the
117f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    // "loading..." progress until the fragment takes over and shows it's own "loading..."
118f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    // progress [located in photo_header_view.xml]. We could potentially have all status displayed
119f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    // by the activity, but, that gets tricky when it comes to screen rotation. For now, we
120f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    // track the loading by this variable which is fragile and may cause phantom "loading..."
121f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    // text.
12240a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook    private long mEnterFullScreenDelayTime;
123f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
124d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook    protected PhotoPagerAdapter createPhotoPagerAdapter(Context context,
125d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook            android.support.v4.app.FragmentManager fm, Cursor c, float maxScale) {
126d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook        return new PhotoPagerAdapter(context, fm, c, maxScale);
127d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook    }
128d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook
129f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
130f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    protected void onCreate(Bundle savedInstanceState) {
131f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        super.onCreate(savedInstanceState);
132f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
133f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final ActivityManager mgr = (ActivityManager) getApplicationContext().
134f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein                getSystemService(Activity.ACTIVITY_SERVICE);
135f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        sMemoryClass = mgr.getMemoryClass();
136f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
137f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        Intent mIntent = getIntent();
138f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
139f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        int currentItem = -1;
140f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (savedInstanceState != null) {
141f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            currentItem = savedInstanceState.getInt(STATE_ITEM_KEY, -1);
142f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            mFullScreen = savedInstanceState.getBoolean(STATE_FULLSCREEN_KEY, false);
1437b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal            mActionBarTitle = savedInstanceState.getString(STATE_ACTIONBARTITLE_KEY);
1447b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal            mActionBarSubtitle = savedInstanceState.getString(STATE_ACTIONBARSUBTITLE_KEY);
145f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
146f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
147f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // uri of the photos to view; optional
148f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mIntent.hasExtra(Intents.EXTRA_PHOTOS_URI)) {
149f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            mPhotosUri = mIntent.getStringExtra(Intents.EXTRA_PHOTOS_URI);
150f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
151f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
152f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // projection for the query; optional
153f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // I.f not set, the default projection is used.
154f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // This projection must include the columns from the default projection.
155f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mIntent.hasExtra(Intents.EXTRA_PROJECTION)) {
156f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            mProjection = mIntent.getStringArrayExtra(Intents.EXTRA_PROJECTION);
157f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        } else {
158f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            mProjection = null;
159f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
160f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
161f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // Set the current item from the intent if wasn't in the saved instance
162f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mIntent.hasExtra(Intents.EXTRA_PHOTO_INDEX) && currentItem < 0) {
163f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            currentItem = mIntent.getIntExtra(Intents.EXTRA_PHOTO_INDEX, -1);
164f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
165d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook        if (mIntent.hasExtra(Intents.EXTRA_INITIAL_PHOTO_URI) && currentItem < 0) {
166d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook            mInitialPhotoUri = mIntent.getStringExtra(Intents.EXTRA_INITIAL_PHOTO_URI);
167d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook        }
16891dbfd25cc234de393ae22fc39a832a6335e1bc2Adam Copp
16991dbfd25cc234de393ae22fc39a832a6335e1bc2Adam Copp        // Set the max initial scale, defaulting to 1x
17091dbfd25cc234de393ae22fc39a832a6335e1bc2Adam Copp        mMaxInitialScale = mIntent.getFloatExtra(Intents.EXTRA_MAX_INITIAL_SCALE, 1.0f);
17191dbfd25cc234de393ae22fc39a832a6335e1bc2Adam Copp
172f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mPhotoIndex = currentItem;
17379bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei        mIsEmpty = true;
174f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
175f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        setContentView(R.layout.photo_activity_view);
176f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
177f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // Create the adapter and add the view pager
178d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook        mAdapter = createPhotoPagerAdapter(this, getSupportFragmentManager(),
179d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook            null, mMaxInitialScale);
180fd925449925f3eb6e2ab6e1c50203c4a4bc165b2Paul Westbrook        final Resources resources = getResources();
181d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook        mRootView = findViewById(R.id.photo_activity_root_view);
182f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mViewPager = (PhotoViewPager) findViewById(R.id.photo_view_pager);
183f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mViewPager.setOnPageChangeListener(this);
184f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mViewPager.setOnInterceptTouchListener(this);
185fd925449925f3eb6e2ab6e1c50203c4a4bc165b2Paul Westbrook        mViewPager.setPageMargin(resources.getDimensionPixelSize(R.dimen.photo_page_margin));
186f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
187f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // Kick off the loader
1888746927a945358bb9e515985a37cac7807261026Martin Hibdon        getSupportLoaderManager().initLoader(LOADER_PHOTO_LIST, null, this);
189f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
19040a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook        mEnterFullScreenDelayTime =
19140a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook                resources.getInteger(R.integer.reenter_fullscreen_delay_time_in_millis);
19240a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook
193f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final ActionBar actionBar = getActionBar();
194d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook        if (actionBar != null) {
195d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook            actionBar.setDisplayHomeAsUpEnabled(true);
196d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook            actionBar.addOnMenuVisibilityListener(this);
1977b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal            final int showTitle = ActionBar.DISPLAY_SHOW_TITLE;
1987b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal            actionBar.setDisplayOptions(showTitle, showTitle);
1997b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal            setActionBarTitles(actionBar);
200d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook        }
201f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
202f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
203f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
204f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    protected void onResume() {
205f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        super.onResume();
206f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        setFullScreen(mFullScreen, false);
207f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
208f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mIsPaused = false;
209f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mRestartLoader) {
210f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            mRestartLoader = false;
2118746927a945358bb9e515985a37cac7807261026Martin Hibdon            getSupportLoaderManager().restartLoader(LOADER_PHOTO_LIST, null, this);
212f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
213f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
214f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
215f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
216f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    protected void onPause() {
217f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mIsPaused = true;
218f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
219f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        super.onPause();
220f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
221f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
222f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
223f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void onBackPressed() {
224f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // If in full screen mode, toggle mode & eat the 'back'
225f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mFullScreen) {
226f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            toggleFullScreen();
227f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        } else {
228f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            super.onBackPressed();
229f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
230f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
231f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
232f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
233f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void onSaveInstanceState(Bundle outState) {
234f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        super.onSaveInstanceState(outState);
235f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
236f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        outState.putInt(STATE_ITEM_KEY, mViewPager.getCurrentItem());
237f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        outState.putBoolean(STATE_FULLSCREEN_KEY, mFullScreen);
2387b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal        outState.putString(STATE_ACTIONBARTITLE_KEY, mActionBarTitle);
2397b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal        outState.putString(STATE_ACTIONBARSUBTITLE_KEY, mActionBarSubtitle);
240f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
241f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
242bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp    @Override
243bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp    public boolean onOptionsItemSelected(MenuItem item) {
244bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp       switch (item.getItemId()) {
245bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp          case android.R.id.home:
246bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp             finish();
247bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp          default:
248bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp             return super.onOptionsItemSelected(item);
249bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp       }
250bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp    }
251bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp
252399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon    @Override
25379bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei    public void addScreenListener(int position, OnScreenListener listener) {
25479bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei        mScreenListeners.put(position, listener);
255f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
256f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
257399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon    @Override
25879bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei    public void removeScreenListener(int position) {
25979bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei        mScreenListeners.remove(position);
260f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
261f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
262399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon    @Override
2630c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    public synchronized void addCursorListener(CursorChangedListener listener) {
2640c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein        mCursorListeners.add(listener);
2650c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    }
2660c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein
267399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon    @Override
2680c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    public synchronized void removeCursorListener(CursorChangedListener listener) {
2690c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein        mCursorListeners.remove(listener);
2700c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    }
2710c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein
272399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon    @Override
273f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public boolean isFragmentFullScreen(Fragment fragment) {
274f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mViewPager == null || mAdapter == null || mAdapter.getCount() == 0) {
275f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            return mFullScreen;
276f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
277f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        return mFullScreen || (mViewPager.getCurrentItem() != mAdapter.getItemPosition(fragment));
278f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
279f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
280399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon    @Override
281f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void toggleFullScreen() {
282f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        setFullScreen(!mFullScreen, true);
283f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
284f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
285f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void onPhotoRemoved(long photoId) {
286f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final Cursor data = mAdapter.getCursor();
287f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (data == null) {
288f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            // Huh?! How would this happen?
289f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            return;
290f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
291f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
292f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final int dataCount = data.getCount();
293f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (dataCount <= 1) {
294f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            finish();
295f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            return;
296f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
297f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
2988746927a945358bb9e515985a37cac7807261026Martin Hibdon        getSupportLoaderManager().restartLoader(LOADER_PHOTO_LIST, null, this);
299f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
300f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
301f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
302f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
303f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (id == LOADER_PHOTO_LIST) {
304f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            return new PhotoPagerLoader(this, Uri.parse(mPhotosUri), mProjection);
305f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
306f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        return null;
307f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
308f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
309f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
3108746927a945358bb9e515985a37cac7807261026Martin Hibdon    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
311f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final int id = loader.getId();
312f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (id == LOADER_PHOTO_LIST) {
313f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            if (data == null || data.getCount() == 0) {
314f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein                mIsEmpty = true;
315f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            } else {
316f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein                mAlbumCount = data.getCount();
317f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
318d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook                if (mInitialPhotoUri != null) {
319d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook                    int index = 0;
320d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook                    int uriIndex = data.getColumnIndex(PhotoContract.PhotoViewColumns.URI);
321d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook                    while (data.moveToNext()) {
322d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook                        String uri = data.getString(uriIndex);
323d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook                        if (TextUtils.equals(uri, mInitialPhotoUri)) {
324d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook                            mInitialPhotoUri = null;
325d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook                            mPhotoIndex = index;
326d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook                            break;
327d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook                        }
328d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook                        index++;
329d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook                    }
330d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook                }
331d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook
332e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                // We're paused; don't do anything now, we'll get re-invoked
333e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                // when the activity becomes active again
334e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                // TODO(pwestbro): This shouldn't be necessary, as the loader manager should
335e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                // restart the loader
336e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                if (mIsPaused) {
337e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                    mRestartLoader = true;
338e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                    return;
339e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                }
34079bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei                boolean wasEmpty = mIsEmpty;
341e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                mIsEmpty = false;
342e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook
3434a6a7183e0740dfb305a16676c867e182aced7aaAdam Copp                mAdapter.swapCursor(data);
344d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook                if (mViewPager.getAdapter() == null) {
345d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook                    mViewPager.setAdapter(mAdapter);
346d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook                }
3474a6a7183e0740dfb305a16676c867e182aced7aaAdam Copp                notifyCursorListeners(data);
3484a6a7183e0740dfb305a16676c867e182aced7aaAdam Copp
349e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                // set the selected photo
350e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                int itemIndex = mPhotoIndex;
351e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook
352e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                // Use an index of 0 if the index wasn't specified or couldn't be found
353e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                if (itemIndex < 0) {
354e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                    itemIndex = 0;
355e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                }
356e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook
357e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                mViewPager.setCurrentItem(itemIndex, false);
35879bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei                if (wasEmpty) {
35979bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei                    setViewActivated(itemIndex);
36079bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei                }
361f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            }
3622989cf0c8e4b0aee4c9ac2b5384a392fd74cd6a9Paul Westbrook            // Update the any action items
3632989cf0c8e4b0aee4c9ac2b5384a392fd74cd6a9Paul Westbrook            updateActionItems();
364f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
365f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
366f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
3678746927a945358bb9e515985a37cac7807261026Martin Hibdon    @Override
3688746927a945358bb9e515985a37cac7807261026Martin Hibdon    public void onLoaderReset(android.support.v4.content.Loader<Cursor> loader) {
3698746927a945358bb9e515985a37cac7807261026Martin Hibdon        // If the loader is reset, remove the reference in the adapter to this cursor
3708746927a945358bb9e515985a37cac7807261026Martin Hibdon        // TODO(pwestbro): reenable this when b/7075236 is fixed
3718746927a945358bb9e515985a37cac7807261026Martin Hibdon        // mAdapter.swapCursor(null);
3728746927a945358bb9e515985a37cac7807261026Martin Hibdon    }
3738746927a945358bb9e515985a37cac7807261026Martin Hibdon
3742989cf0c8e4b0aee4c9ac2b5384a392fd74cd6a9Paul Westbrook    protected void updateActionItems() {
3752989cf0c8e4b0aee4c9ac2b5384a392fd74cd6a9Paul Westbrook        // Do nothing, but allow extending classes to do work
3762989cf0c8e4b0aee4c9ac2b5384a392fd74cd6a9Paul Westbrook    }
3772989cf0c8e4b0aee4c9ac2b5384a392fd74cd6a9Paul Westbrook
3780c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    private synchronized void notifyCursorListeners(Cursor data) {
3790c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein        // tell all of the objects listening for cursor changes
3800c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein        // that the cursor has changed
3810c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein        for (CursorChangedListener listener : mCursorListeners) {
3820c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein            listener.onCursorChanged(data);
3830c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein        }
3840c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    }
3850c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein
386f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
387f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
388f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
389f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
390f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
391f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void onPageSelected(int position) {
392f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mPhotoIndex = position;
39379bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei        setViewActivated(position);
394f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
395f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
396f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
397f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void onPageScrollStateChanged(int state) {
398f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
399f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
400399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon    @Override
401f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public boolean isFragmentActive(Fragment fragment) {
402f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mViewPager == null || mAdapter == null) {
403f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            return false;
404f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
405f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        return mViewPager.getCurrentItem() == mAdapter.getItemPosition(fragment);
406f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
407f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
408d4f7888c44dbc6808c20db3605bc48cc42f0b350Paul Westbrook    @Override
4090c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    public void onFragmentVisible(PhotoViewFragment fragment) {
4107b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal        updateActionBar();
411f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
412f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
413f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
414f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public InterceptType onTouchIntercept(float origX, float origY) {
415f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        boolean interceptLeft = false;
416f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        boolean interceptRight = false;
417f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
41879bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei        for (OnScreenListener listener : mScreenListeners.values()) {
419f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            if (!interceptLeft) {
420f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein                interceptLeft = listener.onInterceptMoveLeft(origX, origY);
421f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            }
422f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            if (!interceptRight) {
423f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein                interceptRight = listener.onInterceptMoveRight(origX, origY);
424f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            }
425f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
426f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
427f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (interceptLeft) {
428f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            if (interceptRight) {
429f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein                return InterceptType.BOTH;
430f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            }
431f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            return InterceptType.LEFT;
432f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        } else if (interceptRight) {
433f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            return InterceptType.RIGHT;
434f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
435f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        return InterceptType.NONE;
436f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
437f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
438f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /**
439f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * Updates the title bar according to the value of {@link #mFullScreen}.
440f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     */
4410ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp    protected void setFullScreen(boolean fullScreen, boolean setDelayedRunnable) {
442f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final boolean fullScreenChanged = (fullScreen != mFullScreen);
443f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mFullScreen = fullScreen;
444f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
445f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mFullScreen) {
4461abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein            setLightsOutMode(true);
44740a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook            cancelEnterFullScreenRunnable();
448f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        } else {
4491abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein            setLightsOutMode(false);
4501abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein            if (setDelayedRunnable) {
45140a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook                postEnterFullScreenRunnableWithDelay();
4521abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein            }
453f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
454f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
455f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (fullScreenChanged) {
45679bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei            for (OnScreenListener listener : mScreenListeners.values()) {
4571abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein                listener.onFullScreenChanged(mFullScreen);
4581abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein            }
4591abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein        }
4601abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein    }
4611abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein
46240a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook    private void postEnterFullScreenRunnableWithDelay() {
46340a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook        mHandler.postDelayed(mEnterFullScreenRunnable, mEnterFullScreenDelayTime);
464150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein    }
465150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein
46640a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook    private void cancelEnterFullScreenRunnable() {
46740a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook        mHandler.removeCallbacks(mEnterFullScreenRunnable);
468150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein    }
469150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein
4707e6995626b551c215bc3064c95b9996af940746aAdam Copp    protected void setLightsOutMode(boolean enabled) {
4711abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
4721abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein            int flags = enabled
4731abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein                    ? View.SYSTEM_UI_FLAG_LOW_PROFILE
4741abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein                    | View.SYSTEM_UI_FLAG_FULLSCREEN
4751abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
4761abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
4771abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein                    : View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
4781abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
4791abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein
4801abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein            // using mViewPager since we have it and we need a view
4811abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein            mViewPager.setSystemUiVisibility(flags);
4821abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein        } else {
4831abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein            final ActionBar actionBar = getActionBar();
4841abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein            if (enabled) {
4851abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein                actionBar.hide();
4861abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein            } else {
4871abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein                actionBar.show();
488f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            }
4891abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein            int flags = enabled
4901abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein                    ? View.SYSTEM_UI_FLAG_LOW_PROFILE
4911abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein                    : View.SYSTEM_UI_FLAG_VISIBLE;
4921abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein            mViewPager.setSystemUiVisibility(flags);
493f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
494f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
495f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
49640a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook    private Runnable mEnterFullScreenRunnable = new Runnable() {
4971abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein        @Override
4981abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein        public void run() {
499b462d1bf5d3833fabbdc38d13f66dadcf6ceda54Adam Copp            setFullScreen(true, true);
5001abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein        }
5011abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein    };
5021abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein
503399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon    @Override
50479bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei    public void setViewActivated(int position) {
50579bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei        OnScreenListener listener = mScreenListeners.get(position);
50679bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei        if (listener != null) {
507f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            listener.onViewActivated();
508f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
509f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
510f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
511f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /**
512f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * Adjusts the activity title and subtitle to reflect the photo name and count.
513f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     */
5147b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal    protected void updateActionBar() {
515f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final int position = mViewPager.getCurrentItem() + 1;
516f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final boolean hasAlbumCount = mAlbumCount >= 0;
517f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
518f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final Cursor cursor = getCursorAtProperPosition();
519f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (cursor != null) {
520f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            final int photoNameIndex = cursor.getColumnIndex(PhotoContract.PhotoViewColumns.NAME);
5217b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal            mActionBarTitle = cursor.getString(photoNameIndex);
52268a16aa04f9b98868f4412e7324b0fc292c9d858Andrew Sapperstein        } else {
5237b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal            mActionBarTitle = null;
524f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
525f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
526f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mIsEmpty || !hasAlbumCount || position <= 0) {
5277b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal            mActionBarSubtitle = null;
528f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        } else {
5297b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal            mActionBarSubtitle =
5307b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal                    getResources().getString(R.string.photo_view_count, position, mAlbumCount);
531f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
5327b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal        setActionBarTitles(getActionBar());
5337b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal    }
534f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
5357b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal    /**
5367b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal     * Sets the Action Bar title to {@link #mActionBarTitle} and the subtitle to
5377b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal     * {@link #mActionBarSubtitle}
5387b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal     */
5397b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal    private final void setActionBarTitles(ActionBar actionBar) {
5407b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal        if (actionBar == null) {
5417b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal            return;
5427b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal        }
5437b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal        actionBar.setTitle(getInputOrEmpty(mActionBarTitle));
5447b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal        actionBar.setSubtitle(getInputOrEmpty(mActionBarSubtitle));
5457b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal    }
5467b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal
5477b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal    /**
5487b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal     * If the input string is non-null, it is returned, otherwise an empty string is returned;
5497b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal     * @param in
5507b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal     * @return
5517b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal     */
5527b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal    private static final String getInputOrEmpty(String in) {
5537b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal        if (in == null) {
5547b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal            return "";
5557b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal        }
5567b2d2778159adf9d01e5e7fc5371e49850b2e084Vikram Aggarwal        return in;
557f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
558f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
559f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /**
560f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * Utility method that will return the cursor that contains the data
561f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * at the current position so that it refers to the current image on screen.
562f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * @return the cursor at the current position or
563f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * null if no cursor exists or if the {@link PhotoViewPager} is null.
564f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     */
565f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public Cursor getCursorAtProperPosition() {
566f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mViewPager == null) {
567f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            return null;
568f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
569f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
570f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final int position = mViewPager.getCurrentItem();
571f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final Cursor cursor = mAdapter.getCursor();
572f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
573f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (cursor == null) {
574f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            return null;
575f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
576f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
577f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        cursor.moveToPosition(position);
578f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
579f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        return cursor;
580f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
5819007d640832f674a9d65058a3c2a484c078d239eAndrew Sapperstein
5829007d640832f674a9d65058a3c2a484c078d239eAndrew Sapperstein    public Cursor getCursor() {
5839007d640832f674a9d65058a3c2a484c078d239eAndrew Sapperstein        return (mAdapter == null) ? null : mAdapter.getCursor();
5849007d640832f674a9d65058a3c2a484c078d239eAndrew Sapperstein    }
585150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein
586150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein    @Override
587150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein    public void onMenuVisibilityChanged(boolean isVisible) {
588150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein        if (isVisible) {
58940a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook            cancelEnterFullScreenRunnable();
590150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein        } else {
59140a26567ebaf6311bd7a102491d669abd1d68646Paul Westbrook            postEnterFullScreenRunnableWithDelay();
592150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein        }
593150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein    }
5940ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp
5950bf849421d303e05c600cdcd7dab73cc84809a36Mark Wei    @Override
59679bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei    public void onNewPhotoLoaded(int position) {
59779bc0d5ba2f06b25052fe95fac1593ebde234d9aMark Wei        // do nothing
5988f359e98b9f18064a75c80b9c9ad8bda2713c612Paul Westbrook    }
5998f359e98b9f18064a75c80b9c9ad8bda2713c612Paul Westbrook
6000ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp    protected boolean isFullScreen() {
6010ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp        return mFullScreen;
6020ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp    }
6030ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp
6040ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp    protected void setPhotoIndex(int index) {
6050ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp        mPhotoIndex = index;
6060ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp    }
6078746927a945358bb9e515985a37cac7807261026Martin Hibdon
6080bf849421d303e05c600cdcd7dab73cc84809a36Mark Wei    @Override
6090bf849421d303e05c600cdcd7dab73cc84809a36Mark Wei    public void onCursorChanged(PhotoViewFragment fragment, Cursor cursor) {
6100bf849421d303e05c600cdcd7dab73cc84809a36Mark Wei        // do nothing
6110bf849421d303e05c600cdcd7dab73cc84809a36Mark Wei    }
612f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein}
613