PhotoViewFragment.java revision 150e623129eef49467f1d6f67649e4636a4513f2
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.fragments;
19f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
20f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.app.Activity;
21f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.app.Fragment;
22150e623129eef49467f1d6f67649e4636a4513f2Andrew Sappersteinimport android.app.LoaderManager;
23f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.app.LoaderManager.LoaderCallbacks;
24f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.content.Context;
25f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.content.Intent;
26f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.content.Loader;
270c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sappersteinimport android.database.Cursor;
28f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.graphics.Bitmap;
29f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.os.Bundle;
30f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.util.DisplayMetrics;
31f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.view.LayoutInflater;
32f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.view.View;
33f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.view.View.OnClickListener;
34f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.view.ViewGroup;
35f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.view.WindowManager;
369007d640832f674a9d65058a3c2a484c078d239eAndrew Sappersteinimport android.widget.ImageView;
37150e623129eef49467f1d6f67649e4636a4513f2Andrew Sappersteinimport android.widget.ProgressBar;
38150e623129eef49467f1d6f67649e4636a4513f2Andrew Sappersteinimport android.widget.TextView;
39f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
40f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.Intents;
41f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.PhotoViewActivity;
420c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sappersteinimport com.android.ex.photo.PhotoViewActivity.CursorChangedListener;
43f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.PhotoViewActivity.OnScreenListener;
44f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.R;
450c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sappersteinimport com.android.ex.photo.adapters.PhotoPagerAdapter;
46f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.loaders.PhotoBitmapLoader;
47f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.util.ImageUtils;
48f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.views.PhotoView;
49150e623129eef49467f1d6f67649e4636a4513f2Andrew Sappersteinimport com.android.ex.photo.views.ProgressBarWrapper;
50f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
51f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein/**
52f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * Displays a photo.
53f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein */
54f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinpublic class PhotoViewFragment extends Fragment implements
550c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein        LoaderCallbacks<Bitmap>, OnClickListener, OnScreenListener, CursorChangedListener {
56f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /**
57f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * Interface for components that are internally scrollable left-to-right.
58f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     */
59f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public static interface HorizontallyScrollable {
60f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        /**
61f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein         * Return {@code true} if the component needs to receive right-to-left
62f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein         * touch movements.
63f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein         *
64f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein         * @param origX the raw x coordinate of the initial touch
65f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein         * @param origY the raw y coordinate of the initial touch
66f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein         */
67f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
68f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        public boolean interceptMoveLeft(float origX, float origY);
69f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
70f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        /**
71f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein         * Return {@code true} if the component needs to receive left-to-right
72f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein         * touch movements.
73f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein         *
74f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein         * @param origX the raw x coordinate of the initial touch
75f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein         * @param origY the raw y coordinate of the initial touch
76f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein         */
77f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        public boolean interceptMoveRight(float origX, float origY);
78f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
79f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
80f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private final static String STATE_INTENT_KEY =
81f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            "com.android.mail.photo.fragments.PhotoViewFragment.INTENT";
82f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
83f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    // Loader IDs
84928a39fb533255b34145285fabbd4f51961df63aAndrew Sapperstein    private final static int LOADER_ID_PHOTO = 1;
85928a39fb533255b34145285fabbd4f51961df63aAndrew Sapperstein    private final static int LOADER_ID_THUMBNAIL = 2;
86f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
87f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** The size of the photo */
88f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public static Integer sPhotoSize;
89f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
90f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** The URL of a photo to display */
91f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private String mResolvedPhotoUri;
92928a39fb533255b34145285fabbd4f51961df63aAndrew Sapperstein    private String mThumbnailUri;
93f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** The intent we were launched with */
94f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private Intent mIntent;
95f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private PhotoViewActivity mCallback;
960c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    private PhotoPagerAdapter mAdapter;
97f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
98f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private PhotoView mPhotoView;
99150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein    private ImageView mPhotoPreviewImage;
100150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein    private TextView mEmptyText;
101150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein    private ImageView mRetryButton;
102150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein    private ProgressBarWrapper mPhotoProgressBar;
103150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein
1040c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    private final int mPosition;
105f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
106f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /** Whether or not the fragment should make the photo full-screen */
107f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private boolean mFullScreen;
108f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
109150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein    private View mPhotoPreviewAndProgress;
110928a39fb533255b34145285fabbd4f51961df63aAndrew Sapperstein
111f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public PhotoViewFragment() {
1120c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein        mPosition = -1;
113f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
114f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
1150c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    public PhotoViewFragment(Intent intent, int position, PhotoPagerAdapter adapter) {
116f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mIntent = intent;
1170c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein        mPosition = position;
1180c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein        mAdapter = adapter;
119f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
120f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
121f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
122f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void onAttach(Activity activity) {
123f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        super.onAttach(activity);
124f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mCallback = (PhotoViewActivity) activity;
125f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mCallback == null) {
126150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein            throw new IllegalArgumentException(
127150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein                    "Activity must be a derived class of PhotoViewActivity");
128f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
129f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
130f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (sPhotoSize == null) {
131f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            final DisplayMetrics metrics = new DisplayMetrics();
132f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            final WindowManager wm =
133f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein                    (WindowManager) getActivity().getSystemService(Context.WINDOW_SERVICE);
134f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            final ImageUtils.ImageSize imageSize = ImageUtils.sUseImageSize;
135f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            wm.getDefaultDisplay().getMetrics(metrics);
136f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            switch (imageSize) {
137f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein                case EXTRA_SMALL: {
138f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein                    // Use a photo that's 80% of the "small" size
139f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein                    sPhotoSize = (Math.min(metrics.heightPixels, metrics.widthPixels) * 800) / 1000;
140f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein                    break;
141f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein                }
142f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
143f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein                case SMALL:
144f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein                case NORMAL:
145f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein                default: {
146f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein                    sPhotoSize = Math.min(metrics.heightPixels, metrics.widthPixels);
147f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein                    break;
148f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein                }
149f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            }
150f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
151f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
152f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
153f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
154f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void onDetach() {
155f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mCallback = null;
156f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        super.onDetach();
157f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
158f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
159f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
160f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void onCreate(Bundle savedInstanceState) {
161f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        super.onCreate(savedInstanceState);
162f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
163f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (savedInstanceState != null) {
164f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            mIntent = new Intent().putExtras(savedInstanceState.getBundle(STATE_INTENT_KEY));
165f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
166f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
167f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mResolvedPhotoUri = mIntent.getStringExtra(Intents.EXTRA_RESOLVED_PHOTO_URI);
168928a39fb533255b34145285fabbd4f51961df63aAndrew Sapperstein        mThumbnailUri = mIntent.getStringExtra(Intents.EXTRA_THUMBNAIL_URI);
169f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
170f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
171f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
172f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public View onCreateView(LayoutInflater inflater, ViewGroup container,
173f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            Bundle savedInstanceState) {
174f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final View view = inflater.inflate(R.layout.photo_fragment_view, container, false);
175f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
176f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mPhotoView = (PhotoView) view.findViewById(R.id.photo_view);
177f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mPhotoView.setOnClickListener(this);
178f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mPhotoView.setFullScreen(mFullScreen, false);
1799007d640832f674a9d65058a3c2a484c078d239eAndrew Sapperstein        mPhotoView.enableImageTransforms(true);
1809007d640832f674a9d65058a3c2a484c078d239eAndrew Sapperstein
181150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein        mPhotoPreviewAndProgress = view.findViewById(R.id.photo_preview);
182150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein        mPhotoPreviewImage = (ImageView) view.findViewById(R.id.photo_preview_image);
183150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein        final ProgressBar indeterminate =
184150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein                (ProgressBar) view.findViewById(R.id.indeterminate_progress);
185150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein        final ProgressBar determinate =
186150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein                (ProgressBar) view.findViewById(R.id.determinate_progress);
187150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein        mPhotoProgressBar = new ProgressBarWrapper(determinate, indeterminate, true);
188150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein        mEmptyText = (TextView) view.findViewById(R.id.empty_text);
189150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein        mRetryButton = (ImageView) view.findViewById(R.id.retry_button);
190f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
191f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // Don't call until we've setup the entire view
192f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        setViewVisibility();
193f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
194f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        return view;
195f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
196f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
197f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
198f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void onResume() {
199f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mCallback.addScreenListener(this);
2000c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein        mCallback.addCursorListener(this);
201f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
202f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        getLoaderManager().initLoader(LOADER_ID_PHOTO, null, this);
203f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
204f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        super.onResume();
205f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
206f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
207f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
208f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void onPause() {
209f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        super.onPause();
2100c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein        // Remove listeners
2110c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein        mCallback.removeCursorListener(this);
212f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mCallback.removeScreenListener(this);
213f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        resetPhotoView();
214f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
215f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
216f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
217f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void onDestroyView() {
218f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // Clean up views and other components
219f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mPhotoView != null) {
220f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            mPhotoView.clear();
221f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            mPhotoView = null;
222f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
223f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
224f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        super.onDestroyView();
225f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
226f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
227f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
228f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void onSaveInstanceState(Bundle outState) {
229f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        super.onSaveInstanceState(outState);
230f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
231f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mIntent != null) {
232f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            outState.putParcelable(STATE_INTENT_KEY, mIntent.getExtras());
233f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
234f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
235f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
236f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
237f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public Loader<Bitmap> onCreateLoader(int id, Bundle args) {
238928a39fb533255b34145285fabbd4f51961df63aAndrew Sapperstein        switch (id) {
239928a39fb533255b34145285fabbd4f51961df63aAndrew Sapperstein            case LOADER_ID_PHOTO:
240928a39fb533255b34145285fabbd4f51961df63aAndrew Sapperstein                return new PhotoBitmapLoader(getActivity(), mResolvedPhotoUri);
241928a39fb533255b34145285fabbd4f51961df63aAndrew Sapperstein            case LOADER_ID_THUMBNAIL:
242928a39fb533255b34145285fabbd4f51961df63aAndrew Sapperstein                return new PhotoBitmapLoader(getActivity(), mThumbnailUri);
243928a39fb533255b34145285fabbd4f51961df63aAndrew Sapperstein            default:
244928a39fb533255b34145285fabbd4f51961df63aAndrew Sapperstein                return null;
245f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
246f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
247f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
248f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
249f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void onLoadFinished(Loader<Bitmap> loader, Bitmap data) {
250f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // If we don't have a view, the fragment has been paused. We'll get the cursor again later.
251f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (getView() == null) {
252f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            return;
253f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
254f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
255f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final int id = loader.getId();
256928a39fb533255b34145285fabbd4f51961df63aAndrew Sapperstein        switch (id) {
257928a39fb533255b34145285fabbd4f51961df63aAndrew Sapperstein            case LOADER_ID_PHOTO:
258928a39fb533255b34145285fabbd4f51961df63aAndrew Sapperstein                if (data == null) {
259928a39fb533255b34145285fabbd4f51961df63aAndrew Sapperstein                    getLoaderManager().initLoader(LOADER_ID_THUMBNAIL, null, this);
260150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein                } else {
261150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein                    bindPhoto(data);
262150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein                    mPhotoPreviewAndProgress.setVisibility(View.GONE);
263928a39fb533255b34145285fabbd4f51961df63aAndrew Sapperstein                }
264928a39fb533255b34145285fabbd4f51961df63aAndrew Sapperstein                break;
265928a39fb533255b34145285fabbd4f51961df63aAndrew Sapperstein            case LOADER_ID_THUMBNAIL:
2669007d640832f674a9d65058a3c2a484c078d239eAndrew Sapperstein                if (isPhotoBound()) {
2679007d640832f674a9d65058a3c2a484c078d239eAndrew Sapperstein                    return;
268150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein                } else if (data == null) {
2699007d640832f674a9d65058a3c2a484c078d239eAndrew Sapperstein                    // no preview, show default
270150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein                    mPhotoPreviewImage.setVisibility(View.VISIBLE);
271150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein                    mPhotoPreviewImage.setImageResource(R.drawable.default_image);
272150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein                } else {
273150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein                    mPhotoPreviewImage.setVisibility(View.VISIBLE);
274150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein                    mPhotoPreviewImage.setImageBitmap(data);
275928a39fb533255b34145285fabbd4f51961df63aAndrew Sapperstein                }
276928a39fb533255b34145285fabbd4f51961df63aAndrew Sapperstein                break;
277928a39fb533255b34145285fabbd4f51961df63aAndrew Sapperstein            default:
278928a39fb533255b34145285fabbd4f51961df63aAndrew Sapperstein                break;
279f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
280150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein
281150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein        mCallback.setViewActivated();
282150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein        setViewVisibility();
283f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
284f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
285f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /**
286f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * Binds an image to the photo view.
287f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     */
288f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private void bindPhoto(Bitmap bitmap) {
289f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mPhotoView != null) {
290f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            mPhotoView.bindPhoto(bitmap);
291f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
292f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
293f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
294f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /**
295f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * Resets the photo view to it's default state w/ no bound photo.
296f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     */
297f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private void resetPhotoView() {
298f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mPhotoView != null) {
299f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            mPhotoView.bindPhoto(null);
300f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
301f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
302f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
303f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
304f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void onLoaderReset(Loader<Bitmap> loader) {
305f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // Do nothing
306f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
307f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
308f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
309f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void onClick(View v) {
3101abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein        mCallback.toggleFullScreen();
311f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
312f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
313f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
3141abd4654c2eeacc7d854a438a9c72d7239278beaAndrew Sapperstein    public void onFullScreenChanged(boolean fullScreen) {
315f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        setViewVisibility();
316f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
317f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
318f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
319f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void onViewActivated() {
320f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (!mCallback.isFragmentActive(this)) {
321f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            // we're not in the foreground; reset our view
322f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            resetViews();
323f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        } else {
324f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            mCallback.onFragmentVisible(this);
325f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
326f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
327f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
328f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /**
329f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * Reset the views to their default states
330f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     */
331f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void resetViews() {
332f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mPhotoView != null) {
333f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            mPhotoView.resetTransformations();
334f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
335f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
336f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
337f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
338f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public boolean onInterceptMoveLeft(float origX, float origY) {
339f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (!mCallback.isFragmentActive(this)) {
340f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            // we're not in the foreground; don't intercept any touches
341f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            return false;
342f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
343f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
344f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        return (mPhotoView != null && mPhotoView.interceptMoveLeft(origX, origY));
345f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
346f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
347f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
348f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public boolean onInterceptMoveRight(float origX, float origY) {
349f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (!mCallback.isFragmentActive(this)) {
350f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            // we're not in the foreground; don't intercept any touches
351f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            return false;
352f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
353f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
354f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        return (mPhotoView != null && mPhotoView.interceptMoveRight(origX, origY));
355f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
356f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
357f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /**
358f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * Returns {@code true} if a photo has been bound. Otherwise, returns {@code false}.
359f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     */
360f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public boolean isPhotoBound() {
361150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein        return (mPhotoView != null && mPhotoView.isPhotoBound());
362f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
363f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
364f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /**
365f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * Sets view visibility depending upon whether or not we're in "full screen" mode.
366f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     */
367f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private void setViewVisibility() {
368f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final boolean fullScreen = mCallback.isFragmentFullScreen(this);
369f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        final boolean hide = fullScreen;
370f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
371f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        setFullScreen(hide);
372f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
373f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
374f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /**
375f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * Sets full-screen mode for the views.
376f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     */
377f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public void setFullScreen(boolean fullScreen) {
378f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mFullScreen = fullScreen;
379f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
3800c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein
3810c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    @Override
3820c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    public void onCursorChanged(Cursor cursor) {
3830c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein        if (cursor.moveToPosition(mPosition) && !isPhotoBound()) {
3840c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein            final LoaderManager manager = getLoaderManager();
3850c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein            final Loader<Bitmap> fakeLoader = manager.getLoader(LOADER_ID_PHOTO);
3860c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein            if (fakeLoader == null) {
3870c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein                return;
3880c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein            }
3890c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein
3900c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein            final PhotoBitmapLoader loader =
3910c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein                    (PhotoBitmapLoader) fakeLoader;
3920c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein            mResolvedPhotoUri = mAdapter.getPhotoUri(cursor);
3930c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein            loader.setPhotoUri(mResolvedPhotoUri);
3940c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein            loader.forceLoad();
3950c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein        }
3960c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    }
397150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein
398150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein    public ProgressBarWrapper getPhotoProgressBar() {
399150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein        return mPhotoProgressBar;
400150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein    }
401150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein
402150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein    public TextView getEmptyText() {
403150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein        return mEmptyText;
404150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein    }
405150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein
406150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein    public ImageView getRetryButton() {
407150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein        return mRetryButton;
408150e623129eef49467f1d6f67649e4636a4513f2Andrew Sapperstein    }
409f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein}
410