• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.camera;
18 
19 import android.graphics.Bitmap;
20 import android.graphics.BitmapFactory;
21 import android.util.Log;
22 
23 import java.io.FileDescriptor;
24 import 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  */
35 public 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
toString()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 
BitmapManager()62     private BitmapManager() {
63     }
64 
65     /**
66      * Get thread status and create one if specified.
67      */
getOrCreateThreadStatus(Thread t)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      */
setDecodingOptions(Thread t, BitmapFactory.Options options)81     private synchronized void setDecodingOptions(Thread t,
82             BitmapFactory.Options options) {
83         getOrCreateThreadStatus(t).mOptions = options;
84     }
85 
removeDecodingOptions(Thread t)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      */
canThreadDecoding(Thread t)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 
allowThreadDecoding(Thread t)106     public synchronized void allowThreadDecoding(Thread t) {
107         getOrCreateThreadStatus(t).mState = State.ALLOW;
108     }
109 
cancelThreadDecoding(Thread t)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 
instance()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      */
decodeFileDescriptor(FileDescriptor fd, BitmapFactory.Options options)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