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