Home | History | Annotate | Download | only in imagebackend
      1 /*
      2  * Copyright (C) 2014 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.processing.imagebackend;
     18 
     19 import android.net.Uri;
     20 
     21 import com.android.camera.debug.Log;
     22 import com.android.camera.one.v2.camera2proxy.ImageProxy;
     23 
     24 import com.google.common.annotations.VisibleForTesting;
     25 
     26 import java.util.ArrayList;
     27 import java.util.HashMap;
     28 import java.util.List;
     29 
     30 import javax.annotation.Nullable;
     31 
     32 /**
     33  * Implements the ability for the object to send events to multiple listeners in
     34  * a thread-safe manner. Also, listeners can also filter messages based on the a
     35  * specific image result.
     36  * <p>
     37  * TODO: Replace this object with a more generic listener class. TODO: Replace
     38  * the image filter code with something more efficient.
     39  */
     40 public class ImageProcessorProxyListener implements ImageProcessorListener {
     41 
     42     private final static Log.Tag TAG = new Log.Tag("IProxyListener");
     43 
     44     private final List<ImageProcessorListener> mRegisteredListeners;
     45 
     46     private final HashMap<ImageProcessorListener, Long> mImageFilter;
     47 
     48     /**
     49      * Wrapper for the log to avoid direct references to Android Log objects
     50      * that will crash unit tests. Subclasses may override this method for
     51      * debugging.
     52      *
     53      * @param message
     54      */
     55     protected void logWrapper(String message) {
     56         // Uncomment for more verbose messaging.
     57         // Log.v(TAG, message);
     58     }
     59 
     60     ImageProcessorProxyListener() {
     61         mRegisteredListeners = new ArrayList<ImageProcessorListener>();
     62         mImageFilter = new HashMap<ImageProcessorListener, Long>();
     63     }
     64 
     65     /**
     66      * Returns the size of the ImageFilter so that we ensure that there are no
     67      * reference leaks.
     68      *
     69      * @return the number of elements in the mapping between
     70      *         ImageProcessorListener and their ids.
     71      */
     72     @VisibleForTesting
     73     public int getMapSize() {
     74         synchronized (mRegisteredListeners) {
     75             return mImageFilter.size();
     76         }
     77     }
     78 
     79     /**
     80      * Returns the number of ImageProcessorListener held by the system so that
     81      * we ensure that there are no reference leaks.
     82      *
     83      * @return the number of registered ImageProcessorListener
     84      */
     85     @VisibleForTesting
     86     public int getNumRegisteredListeners() {
     87         synchronized (mRegisteredListeners) {
     88             return mRegisteredListeners.size();
     89         }
     90     }
     91 
     92     /**
     93      * Register a listener filtered by a particular image object. If image is
     94      * null, then events from all image processing will be sent to the
     95      * registered listener.
     96      *
     97      * @param listener The listener to be registered.
     98      * @param image The specific image to filter the events to the listener. If
     99      *            null, then the listener receives events from all images that
    100      *            are being processed.
    101      */
    102     public void registerListener(ImageProcessorListener listener,
    103             @Nullable ImageProxy image) {
    104         synchronized (mRegisteredListeners) {
    105             logWrapper("There are " + mRegisteredListeners.size()
    106                     + " listeners before addition");
    107             if (!mRegisteredListeners.contains(listener)) {
    108                 mRegisteredListeners.add(listener);
    109                 logWrapper("Listener will be overwritten.");
    110             }
    111 
    112             if (image == null) {
    113                 mImageFilter.put(listener, null);
    114             } else {
    115                 mImageFilter.put(listener, image.getTimestamp());
    116             }
    117             logWrapper("There are " + mRegisteredListeners.size()
    118                     + " listeners after addition");
    119         }
    120 
    121         return;
    122     }
    123 
    124     private List<ImageProcessorListener> filteredListeners(long imageId) {
    125         List<ImageProcessorListener> filteredList = new ArrayList<ImageProcessorListener>();
    126 
    127         for (ImageProcessorListener l : mRegisteredListeners) {
    128             if (mImageFilter.get(l) == null || mImageFilter.get(l) == imageId) {
    129                 filteredList.add(l);
    130             }
    131         }
    132 
    133         return filteredList;
    134     }
    135 
    136     public void unregisterListener(ImageProcessorListener listener) {
    137         synchronized (mRegisteredListeners) {
    138             if (mRegisteredListeners.contains(listener)) {
    139                 mRegisteredListeners.remove(listener);
    140                 mImageFilter.remove(listener);
    141                 logWrapper("There are " + mRegisteredListeners.size()
    142                         + " listeners after removal");
    143             } else {
    144                 logWrapper("Couldn't find listener.  There are " + mRegisteredListeners.size()
    145                         + " listeners after removal");
    146             }
    147         }
    148     }
    149 
    150     public void onStart(TaskImageContainer.TaskInfo job) {
    151         final List<ImageProcessorListener> listeners;
    152         synchronized (mRegisteredListeners) {
    153             listeners = filteredListeners(job.contentId);
    154         }
    155 
    156         for (ImageProcessorListener l : listeners) {
    157             l.onStart(job);
    158         }
    159     }
    160 
    161     public void onResultCompressed(TaskImageContainer.TaskInfo job,
    162             TaskImageContainer.CompressedPayload payload) {
    163         final List<ImageProcessorListener> listeners;
    164         synchronized (mRegisteredListeners) {
    165             listeners = filteredListeners(job.contentId);
    166         }
    167 
    168         for (ImageProcessorListener l : listeners) {
    169             l.onResultCompressed(job, payload);
    170         }
    171     }
    172 
    173     public void onResultUncompressed(TaskImageContainer.TaskInfo job,
    174             TaskImageContainer.UncompressedPayload payload) {
    175         final List<ImageProcessorListener> listeners;
    176         synchronized (mRegisteredListeners) {
    177             listeners = filteredListeners(job.contentId);
    178         }
    179 
    180         for (ImageProcessorListener l : listeners) {
    181             l.onResultUncompressed(job, payload);
    182         }
    183     }
    184 
    185     public void onResultUri(TaskImageContainer.TaskInfo job, Uri uri) {
    186         final List<ImageProcessorListener> listeners;
    187         synchronized (mRegisteredListeners) {
    188             listeners = filteredListeners(job.contentId);
    189         }
    190 
    191         for (ImageProcessorListener l : listeners) {
    192             l.onResultUri(job, uri);
    193         }
    194     }
    195 
    196 }
    197