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.core; 18 19 import android.hardware.camera2.CameraAccessException; 20 21 import com.android.camera.async.ConcurrentState; 22 import com.android.camera.async.Observable; 23 import com.android.camera.async.SafeCloseable; 24 import com.android.camera.one.v2.camera2proxy.CameraCaptureSessionClosedException; 25 26 import java.util.List; 27 import java.util.concurrent.Executor; 28 import java.util.concurrent.atomic.AtomicBoolean; 29 import java.util.concurrent.atomic.AtomicInteger; 30 31 import javax.annotation.Nonnull; 32 import javax.annotation.Nullable; 33 import javax.annotation.ParametersAreNonnullByDefault; 34 35 /** 36 * Decorates a {@link FrameServer} to enable listening for changes to 37 * availability (whether or not an exclusive session can likely be acquired 38 * immediately). 39 */ 40 @ParametersAreNonnullByDefault 41 final class ObservableFrameServer implements FrameServer, Observable<Boolean> { 42 /** 43 * The total number of clients which either have an exclusive Session or are 44 * waiting to acquire one. When this is positive, the frame server is "not 45 * available". 46 */ 47 private final AtomicInteger mClientCount; 48 private final ConcurrentState<Boolean> mAvailability; 49 private final FrameServer mDelegate; 50 51 private class SessionImpl implements Session { 52 private final AtomicBoolean mClosed; 53 private final Session mDelegate; 54 55 private SessionImpl(Session delegate) { 56 mClosed = new AtomicBoolean(false); 57 mDelegate = delegate; 58 } 59 60 @Override 61 public void submitRequest(List<Request> burstRequests, RequestType type) 62 throws CameraAccessException, InterruptedException, 63 CameraCaptureSessionClosedException, ResourceAcquisitionFailedException { 64 mDelegate.submitRequest(burstRequests, type); 65 } 66 67 @Override 68 public void close() { 69 if (!mClosed.getAndSet(true)) { 70 int clients = mClientCount.decrementAndGet(); 71 mAvailability.update(clients == 0); 72 mDelegate.close(); 73 } 74 } 75 } 76 77 public ObservableFrameServer(FrameServer delegate) { 78 mDelegate = delegate; 79 mClientCount = new AtomicInteger(0); 80 mAvailability = new ConcurrentState<>(true); 81 } 82 83 @Nonnull 84 @Override 85 public Session createExclusiveSession() throws InterruptedException { 86 int clients = mClientCount.incrementAndGet(); 87 mAvailability.update(clients == 0); 88 try { 89 // Ownership of the incremented value in mClientCount is passed to 90 // the session, which is responsible for decrementing it later. 91 Session session = mDelegate.createExclusiveSession(); 92 return new SessionImpl(session); 93 } catch (InterruptedException e) { 94 // If no session was acquired, we still "own" the increment of 95 // mClientCount and must decrement it here. 96 clients = mClientCount.decrementAndGet(); 97 mAvailability.update(clients == 0); 98 throw e; 99 } 100 } 101 102 @Nullable 103 @Override 104 public Session tryCreateExclusiveSession() { 105 Session session = mDelegate.tryCreateExclusiveSession(); 106 if (session == null) { 107 return null; 108 } else { 109 int clients = mClientCount.incrementAndGet(); 110 mAvailability.update(clients == 0); 111 return new SessionImpl(session); 112 } 113 } 114 115 @Nonnull 116 @Override 117 public SafeCloseable addCallback(Runnable callback, Executor executor) { 118 return mAvailability.addCallback(callback, executor); 119 } 120 121 @Nonnull 122 @Override 123 public Boolean get() { 124 return mAvailability.get(); 125 } 126 } 127