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.loaders;
19f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
20f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.content.ContentResolver;
21f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.content.Context;
22f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.graphics.Bitmap;
23f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport android.net.Uri;
248746927a945358bb9e515985a37cac7807261026Martin Hibdonimport android.support.v4.content.AsyncTaskLoader;
253a14814364ff1e48109d32a06bd063c66914889bMark Weiimport android.util.DisplayMetrics;
26f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
2755ac8ea9519e981bfdbd83c82615c72cfa78d84cShri Bordeimport com.android.ex.photo.PhotoViewController;
28ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonimport com.android.ex.photo.loaders.PhotoBitmapLoaderInterface.BitmapResult;
29f77a7eb196d16110c7b1087352b423913821ff61Andrew Sappersteinimport com.android.ex.photo.util.ImageUtils;
30f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
31f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein/**
32f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein * Loader for the bitmap of a photo.
33f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein */
34ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdonpublic class PhotoBitmapLoader extends AsyncTaskLoader<BitmapResult>
35ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon    implements PhotoBitmapLoaderInterface {
360c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    private String mPhotoUri;
37f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    private Bitmap mBitmap;
38f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
39f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    public PhotoBitmapLoader(Context context, String photoUri) {
40f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        super(context);
41f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mPhotoUri = photoUri;
42f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
43f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
44ca8fdcd23fcc53e0429abf8d4ef80e8d6d8fe6faMartin Hibdon    @Override
450c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    public void setPhotoUri(String photoUri) {
460c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein        mPhotoUri = photoUri;
470c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein    }
480c18e5deef5209d21b527a01feb6b789715eb48eAndrew Sapperstein
49f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
5006d8b5e82b9b75588051a492152fda0b63f70484Mark Wei    public BitmapResult loadInBackground() {
5106d8b5e82b9b75588051a492152fda0b63f70484Mark Wei        BitmapResult result = new BitmapResult();
52f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        Context context = getContext();
53f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (context != null && mPhotoUri != null) {
54f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            final ContentResolver resolver = context.getContentResolver();
5506d8b5e82b9b75588051a492152fda0b63f70484Mark Wei            try {
56112958e7a0493f2e692bbc40d113e98715caaab8Adam Copp                result = ImageUtils.createLocalBitmap(resolver, Uri.parse(mPhotoUri),
5755ac8ea9519e981bfdbd83c82615c72cfa78d84cShri Borde                        PhotoViewController.sMaxPhotoSize);
58112958e7a0493f2e692bbc40d113e98715caaab8Adam Copp                if (result.bitmap != null) {
59112958e7a0493f2e692bbc40d113e98715caaab8Adam Copp                    result.bitmap.setDensity(DisplayMetrics.DENSITY_MEDIUM);
6006d8b5e82b9b75588051a492152fda0b63f70484Mark Wei                }
6106d8b5e82b9b75588051a492152fda0b63f70484Mark Wei            } catch (UnsupportedOperationException ex) {
6206d8b5e82b9b75588051a492152fda0b63f70484Mark Wei                // We got image bytes, but unable to decode to a Bitmap
6306d8b5e82b9b75588051a492152fda0b63f70484Mark Wei                result.status = BitmapResult.STATUS_EXCEPTION;
640f7d1502f4f7c0b364e7644875a04fb0c90807ffMark Wei            }
65f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
66f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
6706d8b5e82b9b75588051a492152fda0b63f70484Mark Wei        return result;
68f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
69f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
70f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /**
71f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * Called when there is new data to deliver to the client.  The
72f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * super class will take care of delivering it; the implementation
73f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * here just adds a little more logic.
74f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     */
75f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
7606d8b5e82b9b75588051a492152fda0b63f70484Mark Wei    public void deliverResult(BitmapResult result) {
7706d8b5e82b9b75588051a492152fda0b63f70484Mark Wei        Bitmap bitmap = result != null ? result.bitmap : null;
78f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (isReset()) {
79f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            // An async query came in while the loader is stopped.  We
80f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            // don't need the result.
81f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            if (bitmap != null) {
82f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein                onReleaseResources(bitmap);
83f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            }
84a3c441f144e3acc7aa32d8236f590cf1aac179f5Andrew Sapperstein            return;
85f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
86f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        Bitmap oldBitmap = mBitmap;
87f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        mBitmap = bitmap;
88f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
89f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (isStarted()) {
90f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            // If the Loader is currently started, we can immediately
91f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            // deliver its results.
9206d8b5e82b9b75588051a492152fda0b63f70484Mark Wei            super.deliverResult(result);
93f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
94f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
95f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // At this point we can release the resources associated with
96f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // 'oldBitmap' if needed; now that the new result is delivered we
97f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // know that it is no longer in use.
98f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (oldBitmap != null && oldBitmap != bitmap && !oldBitmap.isRecycled()) {
99f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            onReleaseResources(oldBitmap);
100f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
101f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
102f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
103f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /**
104f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * Handles a request to start the Loader.
105f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     */
106f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
107f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    protected void onStartLoading() {
108f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mBitmap != null) {
109f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            // If we currently have a result available, deliver it
110f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            // immediately.
11106d8b5e82b9b75588051a492152fda0b63f70484Mark Wei            BitmapResult result = new BitmapResult();
11206d8b5e82b9b75588051a492152fda0b63f70484Mark Wei            result.status = BitmapResult.STATUS_SUCCESS;
11306d8b5e82b9b75588051a492152fda0b63f70484Mark Wei            result.bitmap = mBitmap;
11406d8b5e82b9b75588051a492152fda0b63f70484Mark Wei            deliverResult(result);
115f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
116f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
117f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (takeContentChanged() || mBitmap == null) {
118f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            // If the data has changed since the last time it was loaded
119f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            // or is not currently available, start a load.
120f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            forceLoad();
121f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
122f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
123f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
124f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /**
125f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * Handles a request to stop the Loader.
126f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     */
127f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override protected void onStopLoading() {
128f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // Attempt to cancel the current load task if possible.
129f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        cancelLoad();
130f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
131f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
132f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /**
133f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * Handles a request to cancel a load.
134f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     */
135f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
13606d8b5e82b9b75588051a492152fda0b63f70484Mark Wei    public void onCanceled(BitmapResult result) {
13706d8b5e82b9b75588051a492152fda0b63f70484Mark Wei        super.onCanceled(result);
138f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
139f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // At this point we can release the resources associated with 'bitmap'
140f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // if needed.
14106d8b5e82b9b75588051a492152fda0b63f70484Mark Wei        if (result != null) {
14206d8b5e82b9b75588051a492152fda0b63f70484Mark Wei            onReleaseResources(result.bitmap);
14306d8b5e82b9b75588051a492152fda0b63f70484Mark Wei        }
144f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
145f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
146f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /**
147f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * Handles a request to completely reset the Loader.
148f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     */
149f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    @Override
150f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    protected void onReset() {
151f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        super.onReset();
152f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
153f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // Ensure the loader is stopped
154f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        onStopLoading();
155f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
156f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // At this point we can release the resources associated with 'bitmap'
157f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        // if needed.
158f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (mBitmap != null) {
159f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            onReleaseResources(mBitmap);
160f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            mBitmap = null;
161f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
162f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
163f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein
164f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    /**
165f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * Helper function to take care of releasing resources associated
166f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     * with an actively loaded data set.
167f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein     */
168f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    protected void onReleaseResources(Bitmap bitmap) {
169f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        if (bitmap != null && !bitmap.isRecycled()) {
170f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein            bitmap.recycle();
171f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein        }
172f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein    }
173f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein}
174