1666ea1b28a76aeba74744148b15099254d918671Owen Lin/* 2666ea1b28a76aeba74744148b15099254d918671Owen Lin * Copyright (C) 2009 The Android Open Source Project 3666ea1b28a76aeba74744148b15099254d918671Owen Lin * 4666ea1b28a76aeba74744148b15099254d918671Owen Lin * Licensed under the Apache License, Version 2.0 (the "License"); 5666ea1b28a76aeba74744148b15099254d918671Owen Lin * you may not use this file except in compliance with the License. 6666ea1b28a76aeba74744148b15099254d918671Owen Lin * You may obtain a copy of the License at 7666ea1b28a76aeba74744148b15099254d918671Owen Lin * 8666ea1b28a76aeba74744148b15099254d918671Owen Lin * http://www.apache.org/licenses/LICENSE-2.0 9666ea1b28a76aeba74744148b15099254d918671Owen Lin * 10666ea1b28a76aeba74744148b15099254d918671Owen Lin * Unless required by applicable law or agreed to in writing, software 11666ea1b28a76aeba74744148b15099254d918671Owen Lin * distributed under the License is distributed on an "AS IS" BASIS, 12666ea1b28a76aeba74744148b15099254d918671Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13666ea1b28a76aeba74744148b15099254d918671Owen Lin * See the License for the specific language governing permissions and 14666ea1b28a76aeba74744148b15099254d918671Owen Lin * limitations under the License. 15666ea1b28a76aeba74744148b15099254d918671Owen Lin */ 16666ea1b28a76aeba74744148b15099254d918671Owen Lin 17666ea1b28a76aeba74744148b15099254d918671Owen Linpackage com.android.camera; 18666ea1b28a76aeba74744148b15099254d918671Owen Lin 198aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Linimport android.content.ContentResolver; 20666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Bitmap; 21666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.BitmapFactory; 228aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Linimport android.provider.MediaStore.Images; 238aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Linimport android.provider.MediaStore.Video; 24666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.util.Log; 25666ea1b28a76aeba74744148b15099254d918671Owen Lin 26666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.io.FileDescriptor; 27666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.util.WeakHashMap; 28666ea1b28a76aeba74744148b15099254d918671Owen Lin 29666ea1b28a76aeba74744148b15099254d918671Owen Lin/** 30666ea1b28a76aeba74744148b15099254d918671Owen Lin * This class provides several utilities to cancel bitmap decoding. 31666ea1b28a76aeba74744148b15099254d918671Owen Lin * 32666ea1b28a76aeba74744148b15099254d918671Owen Lin * The function decodeFileDescriptor() is used to decode a bitmap. During 33666ea1b28a76aeba74744148b15099254d918671Owen Lin * decoding if another thread wants to cancel it, it calls the function 34666ea1b28a76aeba74744148b15099254d918671Owen Lin * cancelThreadDecoding() specifying the Thread which is in decoding. 35666ea1b28a76aeba74744148b15099254d918671Owen Lin * 36666ea1b28a76aeba74744148b15099254d918671Owen Lin * cancelThreadDecoding() is sticky until allowThreadDecoding() is called. 37666ea1b28a76aeba74744148b15099254d918671Owen Lin */ 38666ea1b28a76aeba74744148b15099254d918671Owen Linpublic class BitmapManager { 39666ea1b28a76aeba74744148b15099254d918671Owen Lin private static final String TAG = "BitmapManager"; 40666ea1b28a76aeba74744148b15099254d918671Owen Lin private static enum State {CANCEL, ALLOW} 41666ea1b28a76aeba74744148b15099254d918671Owen Lin private static class ThreadStatus { 42666ea1b28a76aeba74744148b15099254d918671Owen Lin public State mState = State.ALLOW; 43666ea1b28a76aeba74744148b15099254d918671Owen Lin public BitmapFactory.Options mOptions; 448aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin public boolean mThumbRequesting; 45666ea1b28a76aeba74744148b15099254d918671Owen Lin @Override 46666ea1b28a76aeba74744148b15099254d918671Owen Lin public String toString() { 47666ea1b28a76aeba74744148b15099254d918671Owen Lin String s; 48666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mState == State.CANCEL) { 49666ea1b28a76aeba74744148b15099254d918671Owen Lin s = "Cancel"; 50666ea1b28a76aeba74744148b15099254d918671Owen Lin } else if (mState == State.ALLOW) { 51666ea1b28a76aeba74744148b15099254d918671Owen Lin s = "Allow"; 52666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 53666ea1b28a76aeba74744148b15099254d918671Owen Lin s = "?"; 54666ea1b28a76aeba74744148b15099254d918671Owen Lin } 55666ea1b28a76aeba74744148b15099254d918671Owen Lin s = "thread state = " + s + ", options = " + mOptions; 56666ea1b28a76aeba74744148b15099254d918671Owen Lin return s; 57666ea1b28a76aeba74744148b15099254d918671Owen Lin } 58666ea1b28a76aeba74744148b15099254d918671Owen Lin } 59666ea1b28a76aeba74744148b15099254d918671Owen Lin 60666ea1b28a76aeba74744148b15099254d918671Owen Lin private final WeakHashMap<Thread, ThreadStatus> mThreadStatus = 61666ea1b28a76aeba74744148b15099254d918671Owen Lin new WeakHashMap<Thread, ThreadStatus>(); 62666ea1b28a76aeba74744148b15099254d918671Owen Lin 63666ea1b28a76aeba74744148b15099254d918671Owen Lin private static BitmapManager sManager = null; 64666ea1b28a76aeba74744148b15099254d918671Owen Lin 65666ea1b28a76aeba74744148b15099254d918671Owen Lin private BitmapManager() { 66666ea1b28a76aeba74744148b15099254d918671Owen Lin } 67666ea1b28a76aeba74744148b15099254d918671Owen Lin 68666ea1b28a76aeba74744148b15099254d918671Owen Lin /** 69666ea1b28a76aeba74744148b15099254d918671Owen Lin * Get thread status and create one if specified. 70666ea1b28a76aeba74744148b15099254d918671Owen Lin */ 71666ea1b28a76aeba74744148b15099254d918671Owen Lin private synchronized ThreadStatus getOrCreateThreadStatus(Thread t) { 72666ea1b28a76aeba74744148b15099254d918671Owen Lin ThreadStatus status = mThreadStatus.get(t); 73666ea1b28a76aeba74744148b15099254d918671Owen Lin if (status == null) { 74666ea1b28a76aeba74744148b15099254d918671Owen Lin status = new ThreadStatus(); 75666ea1b28a76aeba74744148b15099254d918671Owen Lin mThreadStatus.put(t, status); 76666ea1b28a76aeba74744148b15099254d918671Owen Lin } 77666ea1b28a76aeba74744148b15099254d918671Owen Lin return status; 78666ea1b28a76aeba74744148b15099254d918671Owen Lin } 79666ea1b28a76aeba74744148b15099254d918671Owen Lin 80666ea1b28a76aeba74744148b15099254d918671Owen Lin /** 81666ea1b28a76aeba74744148b15099254d918671Owen Lin * The following three methods are used to keep track of 82666ea1b28a76aeba74744148b15099254d918671Owen Lin * BitmapFaction.Options used for decoding and cancelling. 83666ea1b28a76aeba74744148b15099254d918671Owen Lin */ 84666ea1b28a76aeba74744148b15099254d918671Owen Lin private synchronized void setDecodingOptions(Thread t, 85666ea1b28a76aeba74744148b15099254d918671Owen Lin BitmapFactory.Options options) { 86666ea1b28a76aeba74744148b15099254d918671Owen Lin getOrCreateThreadStatus(t).mOptions = options; 87666ea1b28a76aeba74744148b15099254d918671Owen Lin } 88666ea1b28a76aeba74744148b15099254d918671Owen Lin 89666ea1b28a76aeba74744148b15099254d918671Owen Lin synchronized void removeDecodingOptions(Thread t) { 90666ea1b28a76aeba74744148b15099254d918671Owen Lin ThreadStatus status = mThreadStatus.get(t); 91666ea1b28a76aeba74744148b15099254d918671Owen Lin status.mOptions = null; 92666ea1b28a76aeba74744148b15099254d918671Owen Lin } 93666ea1b28a76aeba74744148b15099254d918671Owen Lin 94666ea1b28a76aeba74744148b15099254d918671Owen Lin /** 95666ea1b28a76aeba74744148b15099254d918671Owen Lin * The following three methods are used to keep track of which thread 96666ea1b28a76aeba74744148b15099254d918671Owen Lin * is being disabled for bitmap decoding. 97666ea1b28a76aeba74744148b15099254d918671Owen Lin */ 98666ea1b28a76aeba74744148b15099254d918671Owen Lin public synchronized boolean canThreadDecoding(Thread t) { 99666ea1b28a76aeba74744148b15099254d918671Owen Lin ThreadStatus status = mThreadStatus.get(t); 100666ea1b28a76aeba74744148b15099254d918671Owen Lin if (status == null) { 101666ea1b28a76aeba74744148b15099254d918671Owen Lin // allow decoding by default 102666ea1b28a76aeba74744148b15099254d918671Owen Lin return true; 103666ea1b28a76aeba74744148b15099254d918671Owen Lin } 104666ea1b28a76aeba74744148b15099254d918671Owen Lin 105666ea1b28a76aeba74744148b15099254d918671Owen Lin boolean result = (status.mState != State.CANCEL); 106666ea1b28a76aeba74744148b15099254d918671Owen Lin return result; 107666ea1b28a76aeba74744148b15099254d918671Owen Lin } 108666ea1b28a76aeba74744148b15099254d918671Owen Lin 109666ea1b28a76aeba74744148b15099254d918671Owen Lin public synchronized void allowThreadDecoding(Thread t) { 110666ea1b28a76aeba74744148b15099254d918671Owen Lin getOrCreateThreadStatus(t).mState = State.ALLOW; 111666ea1b28a76aeba74744148b15099254d918671Owen Lin } 112666ea1b28a76aeba74744148b15099254d918671Owen Lin 1138aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin public synchronized void cancelThreadDecoding(Thread t, ContentResolver cr) { 114666ea1b28a76aeba74744148b15099254d918671Owen Lin ThreadStatus status = getOrCreateThreadStatus(t); 115666ea1b28a76aeba74744148b15099254d918671Owen Lin status.mState = State.CANCEL; 116666ea1b28a76aeba74744148b15099254d918671Owen Lin if (status.mOptions != null) { 117666ea1b28a76aeba74744148b15099254d918671Owen Lin status.mOptions.requestCancelDecode(); 118666ea1b28a76aeba74744148b15099254d918671Owen Lin } 119666ea1b28a76aeba74744148b15099254d918671Owen Lin 120666ea1b28a76aeba74744148b15099254d918671Owen Lin // Wake up threads in waiting list 121666ea1b28a76aeba74744148b15099254d918671Owen Lin notifyAll(); 1228aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin 1238aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin // Since our cancel request can arrive MediaProvider earlier than getThumbnail request, 1248aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin // we use mThumbRequesting flag to make sure our request does cancel the request. 1258aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin try { 1268aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin synchronized (status) { 1278aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin while (status.mThumbRequesting) { 1288aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin Images.Thumbnails.cancelThumbnailRequest(cr, -1, t.getId()); 1298aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin Video.Thumbnails.cancelThumbnailRequest(cr, -1, t.getId()); 1308aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin status.wait(200); 1318aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin } 1328aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin } 1338aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin } catch (InterruptedException ex) { 1348aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin // ignore it. 1358aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin } 1368aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin } 1378aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin 1388aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin public Bitmap getThumbnail(ContentResolver cr, long origId, int kind, 1398aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin BitmapFactory.Options options, boolean isVideo) { 1408aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin Thread t = Thread.currentThread(); 1418aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin ThreadStatus status = getOrCreateThreadStatus(t); 1428aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin 1438aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin if (!canThreadDecoding(t)) { 1448aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin Log.d(TAG, "Thread " + t + " is not allowed to decode."); 1458aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin return null; 1468aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin } 1478aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin 1488aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin try { 1498aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin synchronized (status) { 1508aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin status.mThumbRequesting = true; 1518aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin } 1528aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin if (isVideo) { 1538aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin return Video.Thumbnails.getThumbnail(cr, origId, t.getId(), 1548aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin kind, null); 1558aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin } else { 1568aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin return Images.Thumbnails.getThumbnail(cr, origId, t.getId(), 1578aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin kind, null); 1588aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin } 1598aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin } finally { 1608aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin synchronized (status) { 1618aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin status.mThumbRequesting = false; 1628aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin status.notifyAll(); 1638aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin } 1648aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin } 165666ea1b28a76aeba74744148b15099254d918671Owen Lin } 166666ea1b28a76aeba74744148b15099254d918671Owen Lin 167666ea1b28a76aeba74744148b15099254d918671Owen Lin public static synchronized BitmapManager instance() { 168666ea1b28a76aeba74744148b15099254d918671Owen Lin if (sManager == null) { 169666ea1b28a76aeba74744148b15099254d918671Owen Lin sManager = new BitmapManager(); 170666ea1b28a76aeba74744148b15099254d918671Owen Lin } 171666ea1b28a76aeba74744148b15099254d918671Owen Lin return sManager; 172666ea1b28a76aeba74744148b15099254d918671Owen Lin } 173666ea1b28a76aeba74744148b15099254d918671Owen Lin 174666ea1b28a76aeba74744148b15099254d918671Owen Lin /** 175666ea1b28a76aeba74744148b15099254d918671Owen Lin * The real place to delegate bitmap decoding to BitmapFactory. 176666ea1b28a76aeba74744148b15099254d918671Owen Lin */ 177666ea1b28a76aeba74744148b15099254d918671Owen Lin public Bitmap decodeFileDescriptor(FileDescriptor fd, 178666ea1b28a76aeba74744148b15099254d918671Owen Lin BitmapFactory.Options options) { 179666ea1b28a76aeba74744148b15099254d918671Owen Lin if (options.mCancel) { 180666ea1b28a76aeba74744148b15099254d918671Owen Lin return null; 181666ea1b28a76aeba74744148b15099254d918671Owen Lin } 182666ea1b28a76aeba74744148b15099254d918671Owen Lin 183666ea1b28a76aeba74744148b15099254d918671Owen Lin Thread thread = Thread.currentThread(); 184666ea1b28a76aeba74744148b15099254d918671Owen Lin if (!canThreadDecoding(thread)) { 185666ea1b28a76aeba74744148b15099254d918671Owen Lin Log.d(TAG, "Thread " + thread + " is not allowed to decode."); 186666ea1b28a76aeba74744148b15099254d918671Owen Lin return null; 187666ea1b28a76aeba74744148b15099254d918671Owen Lin } 188666ea1b28a76aeba74744148b15099254d918671Owen Lin 189666ea1b28a76aeba74744148b15099254d918671Owen Lin setDecodingOptions(thread, options); 190666ea1b28a76aeba74744148b15099254d918671Owen Lin Bitmap b = BitmapFactory.decodeFileDescriptor(fd, null, options); 191666ea1b28a76aeba74744148b15099254d918671Owen Lin 192666ea1b28a76aeba74744148b15099254d918671Owen Lin removeDecodingOptions(thread); 193666ea1b28a76aeba74744148b15099254d918671Owen Lin return b; 194666ea1b28a76aeba74744148b15099254d918671Owen Lin } 195666ea1b28a76aeba74744148b15099254d918671Owen Lin} 196