1 /* 2 * Copyright (C) 2015 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.one.v2; 18 19 import com.android.camera.one.v2.camera2proxy.ForwardingImageProxy; 20 import com.android.camera.one.v2.camera2proxy.ForwardingImageReader; 21 import com.android.camera.one.v2.camera2proxy.ImageProxy; 22 import com.android.camera.one.v2.camera2proxy.ImageReaderProxy; 23 24 import java.util.concurrent.atomic.AtomicBoolean; 25 26 import javax.annotation.Nullable; 27 import javax.annotation.concurrent.GuardedBy; 28 import javax.annotation.concurrent.ThreadSafe; 29 30 /** 31 * Defers closing the underlying {@link ImageReaderProxy} until all images have 32 * been released. 33 * <p> 34 * TODO Rename to something nicer 35 */ 36 @ThreadSafe 37 public final class CloseWhenDoneImageReader extends ForwardingImageReader implements 38 ImageReaderProxy { 39 private class ImageDecorator extends ForwardingImageProxy { 40 private final AtomicBoolean mClosed; 41 ImageDecorator(ImageProxy proxy)42 public ImageDecorator(ImageProxy proxy) { 43 super(proxy); 44 mClosed = new AtomicBoolean(false); 45 } 46 47 @Override close()48 public void close() { 49 if (!mClosed.getAndSet(true)) { 50 super.close(); 51 decrementImageCount(); 52 } 53 } 54 } 55 56 private final Object mLock; 57 @GuardedBy("mLock") 58 private boolean mClosePending; 59 @GuardedBy("mLock") 60 private boolean mClosed; 61 @GuardedBy("mLock") 62 private int mOpenImages; 63 CloseWhenDoneImageReader(ImageReaderProxy delegate)64 public CloseWhenDoneImageReader(ImageReaderProxy delegate) { 65 super(delegate); 66 mLock = new Object(); 67 mClosed = false; 68 mOpenImages = 0; 69 } 70 decrementImageCount()71 private void decrementImageCount() { 72 synchronized (mLock) { 73 mOpenImages--; 74 if (mClosePending && !mClosed && mOpenImages == 0) { 75 mClosed = true; 76 super.close(); 77 } 78 } 79 } 80 81 @Override 82 @Nullable acquireNextImage()83 public ImageProxy acquireNextImage() { 84 synchronized (mLock) { 85 if (!mClosePending && !mClosed) { 86 ImageProxy image = super.acquireNextImage(); 87 if (image != null) { 88 mOpenImages++; 89 return new ImageDecorator(image); 90 } 91 } 92 } 93 return null; 94 } 95 96 @Override 97 @Nullable acquireLatestImage()98 public ImageProxy acquireLatestImage() { 99 synchronized (mLock) { 100 if (!mClosePending && !mClosed) { 101 ImageProxy image = super.acquireLatestImage(); 102 if (image != null) { 103 mOpenImages++; 104 return new ImageDecorator(image); 105 } 106 } 107 } 108 return null; 109 } 110 111 @Override close()112 public void close() { 113 synchronized (mLock) { 114 if (mClosed || mClosePending) { 115 return; 116 } 117 mClosePending = true; 118 if (mOpenImages == 0) { 119 mClosed = true; 120 super.close(); 121 } 122 } 123 } 124 } 125