PhotoViewActivity.java revision 99f6f3ea0e43d5ac96344a987735fc39485f8f05
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;
2499f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdonimport android.content.Context;
25f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.content.Intent;
26f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.database.Cursor;
27f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.net.Uri;
281abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sappersteinimport android.os.Build;
29f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.os.Bundle;
30f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.os.Handler;
318746927a945358bb9e515985a37cac7807261026Martin Hibdonimport android.support.v4.app.Fragment;
328746927a945358bb9e515985a37cac7807261026Martin Hibdonimport android.support.v4.app.FragmentActivity;
338746927a945358bb9e515985a37cac7807261026Martin Hibdonimport android.support.v4.app.LoaderManager;
348746927a945358bb9e515985a37cac7807261026Martin Hibdonimport android.support.v4.content.Loader;
35f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.support.v4.view.ViewPager.OnPageChangeListener;
3699f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdonimport android.text.TextUtils;
37bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Coppimport android.view.MenuItem;
38f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.view.View;
39f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
40f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.PhotoViewPager.InterceptType;
41f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.PhotoViewPager.OnInterceptTouchListener;
42f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.adapters.PhotoPagerAdapter;
430c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sappersteinimport com.android.ex.photo.fragments.PhotoViewFragment;
44f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.loaders.PhotoPagerLoader;
45f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.provider.PhotoContract;
46f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
47f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport java.util.HashSet;
48f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport java.util.Set;
49f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
50f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein/**
51f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * Activity to view the contents of an album.
52f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein */
538746927a945358bb9e515985a37cac7807261026Martin Hibdonpublic class PhotoViewActivity extends FragmentActivity implements
548746927a945358bb9e515985a37cac7807261026Martin Hibdon        LoaderManager.LoaderCallbacks<Cursor>, OnPageChangeListener, OnInterceptTouchListener,
55399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon        OnMenuVisibilityListener, PhotoViewCallbacks {
560c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein
57f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private final static String STATE_ITEM_KEY =
58f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            "com.google.android.apps.plus.PhotoViewFragment.ITEM";
59f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private final static String STATE_FULLSCREEN_KEY =
60f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            "com.google.android.apps.plus.PhotoViewFragment.FULLSCREEN";
61f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
62f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private static final int LOADER_PHOTO_LIST = 1;
63f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
64f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** Count used when the real photo count is unknown [but, may be determined] */
65f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public static final int ALBUM_COUNT_UNKNOWN = -1;
66f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
67f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** Argument key for the dialog message */
68f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public static final String KEY_MESSAGE = "dialog_message";
69f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
70f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public static int sMemoryClass;
71f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
72f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** The URI of the photos we're viewing; may be {@code null} */
73f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private String mPhotosUri;
7499f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon    /** The URI of the initial photo to display */
7599f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon    private String mInitialPhotoUri;
76f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** The index of the currently viewed photo */
77f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private int mPhotoIndex;
78f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** The query projection to use; may be {@code null} */
79f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private String[] mProjection;
80f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** The total number of photos; only valid if {@link #mIsEmpty} is {@code false}. */
81f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private int mAlbumCount = ALBUM_COUNT_UNKNOWN;
82f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** {@code true} if the view is empty. Otherwise, {@code false}. */
83f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private boolean mIsEmpty;
8499f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon    /** the main root view */
8599f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon    protected View mRootView;
86f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** The main pager; provides left/right swipe between photos */
8799f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon    protected PhotoViewPager mViewPager;
88f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** Adapter to create pager views */
8999f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon    protected PhotoPagerAdapter mAdapter;
90f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** Whether or not we're in "full screen" mode */
91f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private boolean mFullScreen;
92f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** The set of listeners wanting full screen state */
93f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private Set<OnScreenListener> mScreenListeners = new HashSet<OnScreenListener>();
940c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    /** The set of listeners wanting full screen state */
950c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    private Set<CursorChangedListener> mCursorListeners = new HashSet<CursorChangedListener>();
96f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** When {@code true}, restart the loader when the activity becomes active */
97f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private boolean mRestartLoader;
98f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** Whether or not this activity is paused */
99f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private boolean mIsPaused = true;
10091dbfd25cc234de393ae22fc39a832a6335e1bc2Adam Copp    /** The maximum scale factor applied to images when they are initially displayed */
10191dbfd25cc234de393ae22fc39a832a6335e1bc2Adam Copp    private float mMaxInitialScale;
102e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook    private final Handler mHandler = new Handler();
103f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    // TODO Find a better way to do this. We basically want the activity to display the
104f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    // "loading..." progress until the fragment takes over and shows it's own "loading..."
105f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    // progress [located in photo_header_view.xml]. We could potentially have all status displayed
106f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    // by the activity, but, that gets tricky when it comes to screen rotation. For now, we
107f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    // track the loading by this variable which is fragile and may cause phantom "loading..."
108f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    // text.
1091abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein    private long mActionBarHideDelayTime;
110f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
11199f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon    protected PhotoPagerAdapter createPhotoPagerAdapter(Context context,
11299f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon            android.support.v4.app.FragmentManager fm, Cursor c, float maxScale) {
11399f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon        return new PhotoPagerAdapter(context, fm, c, maxScale);
11499f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon    }
11599f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon
116f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
117f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    protected void onCreate(Bundle savedInstanceState) {
118f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        super.onCreate(savedInstanceState);
119f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
120f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final ActivityManager mgr = (ActivityManager) getApplicationContext().
121f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein                getSystemService(Activity.ACTIVITY_SERVICE);
122f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        sMemoryClass = mgr.getMemoryClass();
123f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
124f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        Intent mIntent = getIntent();
125f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
126f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        int currentItem = -1;
127f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (savedInstanceState != null) {
128f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            currentItem = savedInstanceState.getInt(STATE_ITEM_KEY, -1);
129f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            mFullScreen = savedInstanceState.getBoolean(STATE_FULLSCREEN_KEY, false);
130f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
131f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
132f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // uri of the photos to view; optional
133f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mIntent.hasExtra(Intents.EXTRA_PHOTOS_URI)) {
134f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            mPhotosUri = mIntent.getStringExtra(Intents.EXTRA_PHOTOS_URI);
135f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
136f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
137f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // projection for the query; optional
138f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // I.f not set, the default projection is used.
139f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // This projection must include the columns from the default projection.
140f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mIntent.hasExtra(Intents.EXTRA_PROJECTION)) {
141f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            mProjection = mIntent.getStringArrayExtra(Intents.EXTRA_PROJECTION);
142f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        } else {
143f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            mProjection = null;
144f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
145f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
146f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // Set the current item from the intent if wasn't in the saved instance
147f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mIntent.hasExtra(Intents.EXTRA_PHOTO_INDEX) && currentItem < 0) {
148f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            currentItem = mIntent.getIntExtra(Intents.EXTRA_PHOTO_INDEX, -1);
149f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
15099f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon        if (mIntent.hasExtra(Intents.EXTRA_INITIAL_PHOTO_URI) && currentItem < 0) {
15199f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon            mInitialPhotoUri = mIntent.getStringExtra(Intents.EXTRA_INITIAL_PHOTO_URI);
15299f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon        }
15391dbfd25cc234de393ae22fc39a832a6335e1bc2Adam Copp
15491dbfd25cc234de393ae22fc39a832a6335e1bc2Adam Copp        // Set the max initial scale, defaulting to 1x
15591dbfd25cc234de393ae22fc39a832a6335e1bc2Adam Copp        mMaxInitialScale = mIntent.getFloatExtra(Intents.EXTRA_MAX_INITIAL_SCALE, 1.0f);
15691dbfd25cc234de393ae22fc39a832a6335e1bc2Adam Copp
157f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mPhotoIndex = currentItem;
158f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
159f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        setContentView(R.layout.photo_activity_view);
160f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
161f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // Create the adapter and add the view pager
16299f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon        mAdapter = createPhotoPagerAdapter(this, getSupportFragmentManager(),
16399f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon            null, mMaxInitialScale);
16499f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon        mRootView = findViewById(R.id.photo_activity_root_view);
165f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mViewPager = (PhotoViewPager) findViewById(R.id.photo_view_pager);
166f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mViewPager.setOnPageChangeListener(this);
167f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mViewPager.setOnInterceptTouchListener(this);
168f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
169f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // Kick off the loader
1708746927a945358bb9e515985a37cac7807261026Martin Hibdon        getSupportLoaderManager().initLoader(LOADER_PHOTO_LIST, null, this);
171f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
172f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final ActionBar actionBar = getActionBar();
17399f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon        if (actionBar != null) {
17499f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon            actionBar.setDisplayHomeAsUpEnabled(true);
17599f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon            mActionBarHideDelayTime = getResources().getInteger(
17699f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon                    R.integer.action_bar_delay_time_in_millis);
17799f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon            actionBar.addOnMenuVisibilityListener(this);
17899f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon            actionBar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
17999f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon        }
180f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
181f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
182f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
183f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    protected void onResume() {
184f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        super.onResume();
185f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        setFullScreen(mFullScreen, false);
186f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
187f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mIsPaused = false;
188f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mRestartLoader) {
189f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            mRestartLoader = false;
1908746927a945358bb9e515985a37cac7807261026Martin Hibdon            getSupportLoaderManager().restartLoader(LOADER_PHOTO_LIST, null, this);
191f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
192f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
193f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
194f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
195f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    protected void onPause() {
196f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mIsPaused = true;
197f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
198f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        super.onPause();
199f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
200f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
201f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
202f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void onBackPressed() {
203f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // If in full screen mode, toggle mode & eat the 'back'
204f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mFullScreen) {
205f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            toggleFullScreen();
206f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        } else {
207f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            super.onBackPressed();
208f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
209f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
210f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
211f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
212f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void onSaveInstanceState(Bundle outState) {
213f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        super.onSaveInstanceState(outState);
214f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
215f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        outState.putInt(STATE_ITEM_KEY, mViewPager.getCurrentItem());
216f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        outState.putBoolean(STATE_FULLSCREEN_KEY, mFullScreen);
217f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
218f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
219bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp    @Override
220bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp    public boolean onOptionsItemSelected(MenuItem item) {
221bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp       switch (item.getItemId()) {
222bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp          case android.R.id.home:
223bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp             finish();
224bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp          default:
225bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp             return super.onOptionsItemSelected(item);
226bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp       }
227bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp    }
228bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp
229399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon    @Override
230f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void addScreenListener(OnScreenListener listener) {
231f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mScreenListeners.add(listener);
232f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
233f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
234399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon    @Override
235f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void removeScreenListener(OnScreenListener listener) {
236f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mScreenListeners.remove(listener);
237f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
238f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
239399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon    @Override
2400c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    public synchronized void addCursorListener(CursorChangedListener listener) {
2410c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein        mCursorListeners.add(listener);
2420c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    }
2430c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein
244399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon    @Override
2450c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    public synchronized void removeCursorListener(CursorChangedListener listener) {
2460c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein        mCursorListeners.remove(listener);
2470c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    }
2480c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein
249399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon    @Override
250f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public boolean isFragmentFullScreen(Fragment fragment) {
251f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mViewPager == null || mAdapter == null || mAdapter.getCount() == 0) {
252f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            return mFullScreen;
253f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
254f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        return mFullScreen || (mViewPager.getCurrentItem() != mAdapter.getItemPosition(fragment));
255f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
256f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
257399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon    @Override
258f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void toggleFullScreen() {
259f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        setFullScreen(!mFullScreen, true);
260f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
261f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
262f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void onPhotoRemoved(long photoId) {
263f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final Cursor data = mAdapter.getCursor();
264f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (data == null) {
265f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            // Huh?! How would this happen?
266f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            return;
267f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
268f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
269f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final int dataCount = data.getCount();
270f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (dataCount <= 1) {
271f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            finish();
272f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            return;
273f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
274f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
2758746927a945358bb9e515985a37cac7807261026Martin Hibdon        getSupportLoaderManager().restartLoader(LOADER_PHOTO_LIST, null, this);
276f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
277f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
278f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
279f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
280f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (id == LOADER_PHOTO_LIST) {
281f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            return new PhotoPagerLoader(this, Uri.parse(mPhotosUri), mProjection);
282f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
283f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        return null;
284f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
285f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
286f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
2878746927a945358bb9e515985a37cac7807261026Martin Hibdon    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
288f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final int id = loader.getId();
289f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (id == LOADER_PHOTO_LIST) {
290f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            if (data == null || data.getCount() == 0) {
291f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein                mIsEmpty = true;
292f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            } else {
293f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein                mAlbumCount = data.getCount();
294f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
29599f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon                if (mInitialPhotoUri != null) {
29699f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon                    int index = 0;
29799f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon                    int uriIndex = data.getColumnIndex(PhotoContract.PhotoViewColumns.URI);
29899f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon                    while (data.moveToNext()) {
29999f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon                        String uri = data.getString(uriIndex);
30099f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon                        if (TextUtils.equals(uri, mInitialPhotoUri)) {
30199f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon                            mInitialPhotoUri = null;
30299f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon                            mPhotoIndex = index;
30399f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon                            break;
30499f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon                        }
30599f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon                        index++;
30699f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon                    }
30799f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon                }
30899f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon
309e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                // We're paused; don't do anything now, we'll get re-invoked
310e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                // when the activity becomes active again
311e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                // TODO(pwestbro): This shouldn't be necessary, as the loader manager should
312e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                // restart the loader
313e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                if (mIsPaused) {
314e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                    mRestartLoader = true;
315e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                    return;
316e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                }
317e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                mIsEmpty = false;
318e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook
3194a6a7183e0740dfb305a16676c867e182aced7aaAdam Copp                mAdapter.swapCursor(data);
32099f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon                if (mViewPager.getAdapter() == null) {
32199f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon                    mViewPager.setAdapter(mAdapter);
32299f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon                }
3234a6a7183e0740dfb305a16676c867e182aced7aaAdam Copp                notifyCursorListeners(data);
3244a6a7183e0740dfb305a16676c867e182aced7aaAdam Copp
325e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                // set the selected photo
326e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                int itemIndex = mPhotoIndex;
327e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook
328e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                // Use an index of 0 if the index wasn't specified or couldn't be found
329e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                if (itemIndex < 0) {
330e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                    itemIndex = 0;
331e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                }
332e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook
333e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                mViewPager.setCurrentItem(itemIndex, false);
334e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook                setViewActivated();
335f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            }
3362989cf0c8e4b0aee4c9ac2b5384a392fd74cd6a9Paul Westbrook            // Update the any action items
3372989cf0c8e4b0aee4c9ac2b5384a392fd74cd6a9Paul Westbrook            updateActionItems();
338f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
339f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
340f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
3418746927a945358bb9e515985a37cac7807261026Martin Hibdon    @Override
3428746927a945358bb9e515985a37cac7807261026Martin Hibdon    public void onLoaderReset(android.support.v4.content.Loader<Cursor> loader) {
3438746927a945358bb9e515985a37cac7807261026Martin Hibdon        // If the loader is reset, remove the reference in the adapter to this cursor
3448746927a945358bb9e515985a37cac7807261026Martin Hibdon        // TODO(pwestbro): reenable this when b/7075236 is fixed
3458746927a945358bb9e515985a37cac7807261026Martin Hibdon        // mAdapter.swapCursor(null);
3468746927a945358bb9e515985a37cac7807261026Martin Hibdon    }
3478746927a945358bb9e515985a37cac7807261026Martin Hibdon
3482989cf0c8e4b0aee4c9ac2b5384a392fd74cd6a9Paul Westbrook    protected void updateActionItems() {
3492989cf0c8e4b0aee4c9ac2b5384a392fd74cd6a9Paul Westbrook        // Do nothing, but allow extending classes to do work
3502989cf0c8e4b0aee4c9ac2b5384a392fd74cd6a9Paul Westbrook    }
3512989cf0c8e4b0aee4c9ac2b5384a392fd74cd6a9Paul Westbrook
3520c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    private synchronized void notifyCursorListeners(Cursor data) {
3530c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein        // tell all of the objects listening for cursor changes
3540c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein        // that the cursor has changed
3550c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein        for (CursorChangedListener listener : mCursorListeners) {
3560c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein            listener.onCursorChanged(data);
3570c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein        }
3580c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    }
3590c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein
360f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
361f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
362f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
363f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
364f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
365f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void onPageSelected(int position) {
366f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mPhotoIndex = position;
367150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein        setViewActivated();
368f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
369f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
370f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
371f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void onPageScrollStateChanged(int state) {
372f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
373f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
374399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon    @Override
375f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public boolean isFragmentActive(Fragment fragment) {
376f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mViewPager == null || mAdapter == null) {
377f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            return false;
378f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
379f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        return mViewPager.getCurrentItem() == mAdapter.getItemPosition(fragment);
380f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
381f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
38299f6f3ea0e43d5ac96344a987735fc39485f8f05Martin Hibdon    @Override
3830c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    public void onFragmentVisible(PhotoViewFragment fragment) {
384150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein        updateActionBar(fragment);
385f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
386f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
387f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
388f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public InterceptType onTouchIntercept(float origX, float origY) {
389f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        boolean interceptLeft = false;
390f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        boolean interceptRight = false;
391f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
392f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        for (OnScreenListener listener : mScreenListeners) {
393f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            if (!interceptLeft) {
394f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein                interceptLeft = listener.onInterceptMoveLeft(origX, origY);
395f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            }
396f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            if (!interceptRight) {
397f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein                interceptRight = listener.onInterceptMoveRight(origX, origY);
398f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            }
399f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            listener.onViewActivated();
400f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
401f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
402f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (interceptLeft) {
403f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            if (interceptRight) {
404f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein                return InterceptType.BOTH;
405f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            }
406f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            return InterceptType.LEFT;
407f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        } else if (interceptRight) {
408f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            return InterceptType.RIGHT;
409f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
410f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        return InterceptType.NONE;
411f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
412f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
413f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /**
414f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * Updates the title bar according to the value of {@link #mFullScreen}.
415f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     */
4160ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp    protected void setFullScreen(boolean fullScreen, boolean setDelayedRunnable) {
417f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final boolean fullScreenChanged = (fullScreen != mFullScreen);
418f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mFullScreen = fullScreen;
419f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
420f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mFullScreen) {
4211abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein            setLightsOutMode(true);
422150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein            cancelActionBarHideRunnable();
423f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        } else {
4241abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein            setLightsOutMode(false);
4251abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein            if (setDelayedRunnable) {
426150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein                postActionBarHideRunnableWithDelay();
4271abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein            }
428f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
429f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
430f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (fullScreenChanged) {
431f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            for (OnScreenListener listener : mScreenListeners) {
4321abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein                listener.onFullScreenChanged(mFullScreen);
4331abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein            }
4341abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein        }
4351abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein    }
4361abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein
437150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein    private void postActionBarHideRunnableWithDelay() {
438e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook        mHandler.postDelayed(mActionBarHideRunnable,
439150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein                mActionBarHideDelayTime);
440150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein    }
441150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein
442150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein    private void cancelActionBarHideRunnable() {
443e6d03190d2b2ec6ea07a59daa7e687c3c383f9c3Paul Westbrook        mHandler.removeCallbacks(mActionBarHideRunnable);
444150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein    }
445150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein
4467e6995626b551c215bc3064c95b9996af940746aAdam Copp    protected void setLightsOutMode(boolean enabled) {
4471abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
4481abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein            int flags = enabled
4491abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein                    ? View.SYSTEM_UI_FLAG_LOW_PROFILE
4501abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein                    | View.SYSTEM_UI_FLAG_FULLSCREEN
4511abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
4521abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
4531abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein                    : View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
4541abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
4551abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein
4561abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein            // using mViewPager since we have it and we need a view
4571abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein            mViewPager.setSystemUiVisibility(flags);
4581abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein        } else {
4591abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein            final ActionBar actionBar = getActionBar();
4601abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein            if (enabled) {
4611abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein                actionBar.hide();
4621abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein            } else {
4631abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein                actionBar.show();
464f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            }
4651abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein            int flags = enabled
4661abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein                    ? View.SYSTEM_UI_FLAG_LOW_PROFILE
4671abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein                    : View.SYSTEM_UI_FLAG_VISIBLE;
4681abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein            mViewPager.setSystemUiVisibility(flags);
469f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
470f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
471f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
4721abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein    private Runnable mActionBarHideRunnable = new Runnable() {
4731abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein        @Override
4741abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein        public void run() {
475b462d1bf5d3833fabbdc38d13f66dadcf6ceda54Adam Copp            setFullScreen(true, true);
4761abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein        }
4771abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein    };
4781abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein
479399fe3d995ed4366a18c7ce6632b3014284df57aMartin Hibdon    @Override
4800c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    public void setViewActivated() {
481f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        for (OnScreenListener listener : mScreenListeners) {
482f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            listener.onViewActivated();
483f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
484f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
485f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
486f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /**
487f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * Adjusts the activity title and subtitle to reflect the photo name and count.
488f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     */
489150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein    protected void updateActionBar(PhotoViewFragment fragment) {
490f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final int position = mViewPager.getCurrentItem() + 1;
49168a16aa04f9b98868f4412e7324b0fc292c9d858Andrew Sapperstein        final String title;
492f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final String subtitle;
493f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final boolean hasAlbumCount = mAlbumCount >= 0;
494f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
495f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final Cursor cursor = getCursorAtProperPosition();
496f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
497f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (cursor != null) {
498f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            final int photoNameIndex = cursor.getColumnIndex(PhotoContract.PhotoViewColumns.NAME);
49968a16aa04f9b98868f4412e7324b0fc292c9d858Andrew Sapperstein            title = cursor.getString(photoNameIndex);
50068a16aa04f9b98868f4412e7324b0fc292c9d858Andrew Sapperstein        } else {
50168a16aa04f9b98868f4412e7324b0fc292c9d858Andrew Sapperstein            title = null;
502f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
503f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
504f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mIsEmpty || !hasAlbumCount || position <= 0) {
505f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            subtitle = null;
506f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        } else {
507f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            subtitle = getResources().getString(R.string.photo_view_count, position, mAlbumCount);
508f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
509f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
510f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final ActionBar actionBar = getActionBar();
51168a16aa04f9b98868f4412e7324b0fc292c9d858Andrew Sapperstein        actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE, ActionBar.DISPLAY_SHOW_TITLE);
51268a16aa04f9b98868f4412e7324b0fc292c9d858Andrew Sapperstein        actionBar.setTitle(title);
513f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        actionBar.setSubtitle(subtitle);
514f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
515f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
516f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /**
517f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * Utility method that will return the cursor that contains the data
518f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * at the current position so that it refers to the current image on screen.
519f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * @return the cursor at the current position or
520f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * null if no cursor exists or if the {@link PhotoViewPager} is null.
521f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     */
522f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public Cursor getCursorAtProperPosition() {
523f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mViewPager == null) {
524f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            return null;
525f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
526f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
527f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final int position = mViewPager.getCurrentItem();
528f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final Cursor cursor = mAdapter.getCursor();
529f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
530f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (cursor == null) {
531f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            return null;
532f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
533f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
534f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        cursor.moveToPosition(position);
535f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
536f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        return cursor;
537f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
5389007d640832f674a9d65058a3c2a484c078d239eAndrew Sapperstein
5399007d640832f674a9d65058a3c2a484c078d239eAndrew Sapperstein    public Cursor getCursor() {
5409007d640832f674a9d65058a3c2a484c078d239eAndrew Sapperstein        return (mAdapter == null) ? null : mAdapter.getCursor();
5419007d640832f674a9d65058a3c2a484c078d239eAndrew Sapperstein    }
542150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein
543150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein    @Override
544150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein    public void onMenuVisibilityChanged(boolean isVisible) {
545150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein        if (isVisible) {
546150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein            cancelActionBarHideRunnable();
547150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein        } else {
548150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein            postActionBarHideRunnableWithDelay();
549150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein        }
550150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein    }
5510ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp
5520ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp    protected boolean isFullScreen() {
5530ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp        return mFullScreen;
5540ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp    }
5550ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp
5560ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp    protected void setPhotoIndex(int index) {
5570ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp        mPhotoIndex = index;
5580ab3e0cf9cbb5751a276e4c2555640a0e8173b5fAdam Copp    }
5598746927a945358bb9e515985a37cac7807261026Martin Hibdon
560f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein}
561