BitmapManager.java revision af7f98026f1564d7a4f9c8084bba763ec1698e04
1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.camera;
18
19import android.graphics.Bitmap;
20import android.graphics.BitmapFactory;
21import android.util.Log;
22
23import java.io.FileDescriptor;
24import java.util.WeakHashMap;
25
26/**
27 * This class provides several utilities to cancel bitmap decoding.
28 *
29 * The function decodeFileDescriptor() is used to decode a bitmap. During
30 * decoding if another thread wants to cancel it, it calls the function
31 * cancelThreadDecoding() specifying the Thread which is in decoding.
32 *
33 * cancelThreadDecoding() is sticky until allowThreadDecoding() is called.
34 */
35public class BitmapManager {
36    private static final String TAG = "BitmapManager";
37    private static enum State {CANCEL, ALLOW}
38    private static class ThreadStatus {
39        public State mState = State.ALLOW;
40        public BitmapFactory.Options mOptions;
41
42        @Override
43        public String toString() {
44            String s;
45            if (mState == State.CANCEL) {
46                s = "Cancel";
47            } else if (mState == State.ALLOW) {
48                s = "Allow";
49            } else {
50                s = "?";
51            }
52            s = "thread state = " + s + ", options = " + mOptions;
53            return s;
54        }
55    }
56
57    private final WeakHashMap<Thread, ThreadStatus> mThreadStatus =
58            new WeakHashMap<Thread, ThreadStatus>();
59
60    private static BitmapManager sManager = null;
61
62    private BitmapManager() {
63    }
64
65    /**
66     * Get thread status and create one if specified.
67     */
68    private synchronized ThreadStatus getOrCreateThreadStatus(Thread t) {
69        ThreadStatus status = mThreadStatus.get(t);
70        if (status == null) {
71            status = new ThreadStatus();
72            mThreadStatus.put(t, status);
73        }
74        return status;
75    }
76
77    /**
78     * The following three methods are used to keep track of
79     * BitmapFaction.Options used for decoding and cancelling.
80     */
81    private synchronized void setDecodingOptions(Thread t,
82            BitmapFactory.Options options) {
83        getOrCreateThreadStatus(t).mOptions = options;
84    }
85
86    synchronized void removeDecodingOptions(Thread t) {
87        ThreadStatus status = mThreadStatus.get(t);
88        status.mOptions = null;
89    }
90
91    /**
92     * The following three methods are used to keep track of which thread
93     * is being disabled for bitmap decoding.
94     */
95    public synchronized boolean canThreadDecoding(Thread t) {
96        ThreadStatus status = mThreadStatus.get(t);
97        if (status == null) {
98            // allow decoding by default
99            return true;
100        }
101
102        boolean result = (status.mState != State.CANCEL);
103        return result;
104    }
105
106    public synchronized void allowThreadDecoding(Thread t) {
107        getOrCreateThreadStatus(t).mState = State.ALLOW;
108    }
109
110    public synchronized void cancelThreadDecoding(Thread t) {
111        ThreadStatus status = getOrCreateThreadStatus(t);
112        status.mState = State.CANCEL;
113        if (status.mOptions != null) {
114            status.mOptions.requestCancelDecode();
115        }
116
117        // Wake up threads in waiting list
118        notifyAll();
119    }
120
121    public static synchronized BitmapManager instance() {
122        if (sManager == null) {
123            sManager = new BitmapManager();
124        }
125        return sManager;
126    }
127
128    /**
129     * The real place to delegate bitmap decoding to BitmapFactory.
130     */
131    public Bitmap decodeFileDescriptor(FileDescriptor fd,
132                                       BitmapFactory.Options options) {
133        if (options.mCancel) {
134            return null;
135        }
136
137        Thread thread = Thread.currentThread();
138        if (!canThreadDecoding(thread)) {
139            Log.d(TAG, "Thread " + thread + " is not allowed to decode.");
140            return null;
141        }
142
143        setDecodingOptions(thread, options);
144        Bitmap b = BitmapFactory.decodeFileDescriptor(fd, null, options);
145
146        removeDecodingOptions(thread);
147        return b;
148    }
149}
150