1403e82bd940231d26041bff179da98eabaddc60cRay Chen/*
24177add422a041ea9f1007c05ff42361bf529d52Chih-Chung Chang * Copyright (C) 2009 The Android Open Source Project
3403e82bd940231d26041bff179da98eabaddc60cRay Chen *
4403e82bd940231d26041bff179da98eabaddc60cRay Chen * Licensed under the Apache License, Version 2.0 (the "License");
5403e82bd940231d26041bff179da98eabaddc60cRay Chen * you may not use this file except in compliance with the License.
6403e82bd940231d26041bff179da98eabaddc60cRay Chen * You may obtain a copy of the License at
7403e82bd940231d26041bff179da98eabaddc60cRay Chen *
8403e82bd940231d26041bff179da98eabaddc60cRay Chen *      http://www.apache.org/licenses/LICENSE-2.0
9403e82bd940231d26041bff179da98eabaddc60cRay Chen *
10403e82bd940231d26041bff179da98eabaddc60cRay Chen * Unless required by applicable law or agreed to in writing, software
11403e82bd940231d26041bff179da98eabaddc60cRay Chen * distributed under the License is distributed on an "AS IS" BASIS,
12403e82bd940231d26041bff179da98eabaddc60cRay Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13403e82bd940231d26041bff179da98eabaddc60cRay Chen * See the License for the specific language governing permissions and
14403e82bd940231d26041bff179da98eabaddc60cRay Chen * limitations under the License.
15403e82bd940231d26041bff179da98eabaddc60cRay Chen */
16403e82bd940231d26041bff179da98eabaddc60cRay Chen
17403e82bd940231d26041bff179da98eabaddc60cRay Chenpackage com.android.camera;
18403e82bd940231d26041bff179da98eabaddc60cRay Chen
1928f3595372cfbff1a2e5e83bf59d8dff76e14215Ray Chenimport android.content.ContentResolver;
20403e82bd940231d26041bff179da98eabaddc60cRay Chenimport android.graphics.Bitmap;
21403e82bd940231d26041bff179da98eabaddc60cRay Chenimport android.graphics.BitmapFactory;
2228f3595372cfbff1a2e5e83bf59d8dff76e14215Ray Chenimport android.provider.MediaStore.Images;
2328f3595372cfbff1a2e5e83bf59d8dff76e14215Ray Chenimport android.provider.MediaStore.Video;
24403e82bd940231d26041bff179da98eabaddc60cRay Chenimport android.util.Log;
25403e82bd940231d26041bff179da98eabaddc60cRay Chen
26403e82bd940231d26041bff179da98eabaddc60cRay Chenimport java.io.FileDescriptor;
27403e82bd940231d26041bff179da98eabaddc60cRay Chenimport java.util.WeakHashMap;
28403e82bd940231d26041bff179da98eabaddc60cRay Chen
29403e82bd940231d26041bff179da98eabaddc60cRay Chen/**
30271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * Provides utilities to decode bitmap, get thumbnail, and cancel the
31271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * operations.
32937fc48b37fafe3ffc8f4b52bd9a171bbb4d3a37Owen Lin *
33271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * <p>The function {@link #decodeFileDescriptor(FileDescriptor,
34271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * BitmapFactory.Options)} is used to decode a bitmap. During decoding another
35271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * thread can cancel it using the function {@link #cancelThreadDecoding(Thread,
36271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * ContentResolver)} specifying the {@code Thread} which is in decoding.
37403e82bd940231d26041bff179da98eabaddc60cRay Chen *
38271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * <p>{@code cancelThreadDecoding(Thread,ContentResolver)} is sticky until
39271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * {@code allowThreadDecoding(Thread) } is called.
40403e82bd940231d26041bff179da98eabaddc60cRay Chen */
41403e82bd940231d26041bff179da98eabaddc60cRay Chenpublic class BitmapManager {
42403e82bd940231d26041bff179da98eabaddc60cRay Chen    private static final String TAG = "BitmapManager";
434177add422a041ea9f1007c05ff42361bf529d52Chih-Chung Chang    private static enum State {CANCEL, ALLOW}
44403e82bd940231d26041bff179da98eabaddc60cRay Chen    private static class ThreadStatus {
454177add422a041ea9f1007c05ff42361bf529d52Chih-Chung Chang        public State mState = State.ALLOW;
464177add422a041ea9f1007c05ff42361bf529d52Chih-Chung Chang        public BitmapFactory.Options mOptions;
4782544b4564c079ece1a9065d19add36b2635bb8fOwen Lin
48937fc48b37fafe3ffc8f4b52bd9a171bbb4d3a37Owen Lin        @Override
49403e82bd940231d26041bff179da98eabaddc60cRay Chen        public String toString() {
50403e82bd940231d26041bff179da98eabaddc60cRay Chen            String s;
514177add422a041ea9f1007c05ff42361bf529d52Chih-Chung Chang            if (mState == State.CANCEL) {
52403e82bd940231d26041bff179da98eabaddc60cRay Chen                s = "Cancel";
534177add422a041ea9f1007c05ff42361bf529d52Chih-Chung Chang            } else if (mState == State.ALLOW) {
544177add422a041ea9f1007c05ff42361bf529d52Chih-Chung Chang                s = "Allow";
55937fc48b37fafe3ffc8f4b52bd9a171bbb4d3a37Owen Lin            } else {
564177add422a041ea9f1007c05ff42361bf529d52Chih-Chung Chang                s = "?";
57403e82bd940231d26041bff179da98eabaddc60cRay Chen            }
584177add422a041ea9f1007c05ff42361bf529d52Chih-Chung Chang            s = "thread state = " + s + ", options = " + mOptions;
59403e82bd940231d26041bff179da98eabaddc60cRay Chen            return s;
60403e82bd940231d26041bff179da98eabaddc60cRay Chen        }
61403e82bd940231d26041bff179da98eabaddc60cRay Chen    }
62896182a590fc1bbed5dfb78a74e9a71b30d8f9aaRay Chen
63d30b5877fbdedcebc0af5cccffddccfe9b11cb0bOwen Lin    private final WeakHashMap<Thread, ThreadStatus> mThreadStatus =
64403e82bd940231d26041bff179da98eabaddc60cRay Chen            new WeakHashMap<Thread, ThreadStatus>();
65896182a590fc1bbed5dfb78a74e9a71b30d8f9aaRay Chen
66896182a590fc1bbed5dfb78a74e9a71b30d8f9aaRay Chen    private static BitmapManager sManager = null;
67403e82bd940231d26041bff179da98eabaddc60cRay Chen
68403e82bd940231d26041bff179da98eabaddc60cRay Chen    private BitmapManager() {
69403e82bd940231d26041bff179da98eabaddc60cRay Chen    }
70937fc48b37fafe3ffc8f4b52bd9a171bbb4d3a37Owen Lin
71403e82bd940231d26041bff179da98eabaddc60cRay Chen    /**
72403e82bd940231d26041bff179da98eabaddc60cRay Chen     * Get thread status and create one if specified.
73403e82bd940231d26041bff179da98eabaddc60cRay Chen     */
744177add422a041ea9f1007c05ff42361bf529d52Chih-Chung Chang    private synchronized ThreadStatus getOrCreateThreadStatus(Thread t) {
75403e82bd940231d26041bff179da98eabaddc60cRay Chen        ThreadStatus status = mThreadStatus.get(t);
764177add422a041ea9f1007c05ff42361bf529d52Chih-Chung Chang        if (status == null) {
77403e82bd940231d26041bff179da98eabaddc60cRay Chen            status = new ThreadStatus();
78403e82bd940231d26041bff179da98eabaddc60cRay Chen            mThreadStatus.put(t, status);
79403e82bd940231d26041bff179da98eabaddc60cRay Chen        }
80403e82bd940231d26041bff179da98eabaddc60cRay Chen        return status;
81403e82bd940231d26041bff179da98eabaddc60cRay Chen    }
82403e82bd940231d26041bff179da98eabaddc60cRay Chen
83403e82bd940231d26041bff179da98eabaddc60cRay Chen    public synchronized boolean canThreadDecoding(Thread t) {
84403e82bd940231d26041bff179da98eabaddc60cRay Chen        ThreadStatus status = mThreadStatus.get(t);
85403e82bd940231d26041bff179da98eabaddc60cRay Chen        if (status == null) {
8627576d1b5abbddfc3da7add5a9b9f602d9e9e954Ray Chen            // allow decoding by default
874177add422a041ea9f1007c05ff42361bf529d52Chih-Chung Chang            return true;
88403e82bd940231d26041bff179da98eabaddc60cRay Chen        }
89937fc48b37fafe3ffc8f4b52bd9a171bbb4d3a37Owen Lin
904177add422a041ea9f1007c05ff42361bf529d52Chih-Chung Chang        boolean result = (status.mState != State.CANCEL);
91403e82bd940231d26041bff179da98eabaddc60cRay Chen        return result;
92403e82bd940231d26041bff179da98eabaddc60cRay Chen    }
93937fc48b37fafe3ffc8f4b52bd9a171bbb4d3a37Owen Lin
94271b3095b9f763421c0547109da9de774795072dChih-Chung Chang    /**
95271b3095b9f763421c0547109da9de774795072dChih-Chung Chang     * Gets the thumbnail of the given ID of the original image.
96271b3095b9f763421c0547109da9de774795072dChih-Chung Chang     *
97271b3095b9f763421c0547109da9de774795072dChih-Chung Chang     * <p> This method wraps around @{code getThumbnail} in {@code
98271b3095b9f763421c0547109da9de774795072dChih-Chung Chang     * android.provider.MediaStore}. It provides the ability to cancel it.
99271b3095b9f763421c0547109da9de774795072dChih-Chung Chang     */
10028f3595372cfbff1a2e5e83bf59d8dff76e14215Ray Chen    public Bitmap getThumbnail(ContentResolver cr, long origId, int kind,
10128f3595372cfbff1a2e5e83bf59d8dff76e14215Ray Chen            BitmapFactory.Options options, boolean isVideo) {
10228f3595372cfbff1a2e5e83bf59d8dff76e14215Ray Chen        Thread t = Thread.currentThread();
10328f3595372cfbff1a2e5e83bf59d8dff76e14215Ray Chen        ThreadStatus status = getOrCreateThreadStatus(t);
10428f3595372cfbff1a2e5e83bf59d8dff76e14215Ray Chen
10528f3595372cfbff1a2e5e83bf59d8dff76e14215Ray Chen        if (!canThreadDecoding(t)) {
10628f3595372cfbff1a2e5e83bf59d8dff76e14215Ray Chen            Log.d(TAG, "Thread " + t + " is not allowed to decode.");
10728f3595372cfbff1a2e5e83bf59d8dff76e14215Ray Chen            return null;
10828f3595372cfbff1a2e5e83bf59d8dff76e14215Ray Chen        }
10928f3595372cfbff1a2e5e83bf59d8dff76e14215Ray Chen
11028f3595372cfbff1a2e5e83bf59d8dff76e14215Ray Chen        try {
11128f3595372cfbff1a2e5e83bf59d8dff76e14215Ray Chen            if (isVideo) {
11228f3595372cfbff1a2e5e83bf59d8dff76e14215Ray Chen                return Video.Thumbnails.getThumbnail(cr, origId, t.getId(),
11328f3595372cfbff1a2e5e83bf59d8dff76e14215Ray Chen                        kind, null);
11428f3595372cfbff1a2e5e83bf59d8dff76e14215Ray Chen            } else {
11528f3595372cfbff1a2e5e83bf59d8dff76e14215Ray Chen                return Images.Thumbnails.getThumbnail(cr, origId, t.getId(),
11628f3595372cfbff1a2e5e83bf59d8dff76e14215Ray Chen                        kind, null);
11728f3595372cfbff1a2e5e83bf59d8dff76e14215Ray Chen            }
11828f3595372cfbff1a2e5e83bf59d8dff76e14215Ray Chen        } finally {
11928f3595372cfbff1a2e5e83bf59d8dff76e14215Ray Chen            synchronized (status) {
12028f3595372cfbff1a2e5e83bf59d8dff76e14215Ray Chen                status.notifyAll();
12128f3595372cfbff1a2e5e83bf59d8dff76e14215Ray Chen            }
12228f3595372cfbff1a2e5e83bf59d8dff76e14215Ray Chen        }
123403e82bd940231d26041bff179da98eabaddc60cRay Chen    }
124937fc48b37fafe3ffc8f4b52bd9a171bbb4d3a37Owen Lin
125896182a590fc1bbed5dfb78a74e9a71b30d8f9aaRay Chen    public static synchronized BitmapManager instance() {
126896182a590fc1bbed5dfb78a74e9a71b30d8f9aaRay Chen        if (sManager == null) {
127896182a590fc1bbed5dfb78a74e9a71b30d8f9aaRay Chen            sManager = new BitmapManager();
128896182a590fc1bbed5dfb78a74e9a71b30d8f9aaRay Chen        }
129896182a590fc1bbed5dfb78a74e9a71b30d8f9aaRay Chen        return sManager;
130896182a590fc1bbed5dfb78a74e9a71b30d8f9aaRay Chen    }
131403e82bd940231d26041bff179da98eabaddc60cRay Chen}
132