Home | History | Annotate | Download | only in core
      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