1ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin/*
2ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * Copyright (C) 2014 The Android Open Source Project
3ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin *
4ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * Licensed under the Apache License, Version 2.0 (the "License");
5ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * you may not use this file except in compliance with the License.
6ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * You may obtain a copy of the License at
7ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin *
8ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin *      http://www.apache.org/licenses/LICENSE-2.0
9ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin *
10ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * Unless required by applicable law or agreed to in writing, software
11ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * distributed under the License is distributed on an "AS IS" BASIS,
12ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * See the License for the specific language governing permissions and
14ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * limitations under the License.
15ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */
16ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
173830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberlingpackage com.android.camera.processing.imagebackend;
18ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
19ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport android.net.Uri;
20ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
21ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport com.android.camera.debug.Log;
2230ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Linimport com.android.camera.one.v2.camera2proxy.ImageProxy;
23ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
240f0329889f69182648fe8f535335e48978d63cc0I-Jong Linimport com.google.common.annotations.VisibleForTesting;
250f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin
26ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport java.util.ArrayList;
27ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport java.util.HashMap;
28ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport java.util.List;
29ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
300f0329889f69182648fe8f535335e48978d63cc0I-Jong Linimport javax.annotation.Nullable;
310f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin
32ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin/**
3330ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin * Implements the ability for the object to send events to multiple listeners in
3430ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin * a thread-safe manner. Also, listeners can also filter messages based on the a
350f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * specific image result.
360f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * <p>
370f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * TODO: Replace this object with a more generic listener class. TODO: Replace
380f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * the image filter code with something more efficient.
39ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */
40ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linpublic class ImageProcessorProxyListener implements ImageProcessorListener {
41ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
42ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin    private final static Log.Tag TAG = new Log.Tag("IProxyListener");
43ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
440f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin    private final List<ImageProcessorListener> mRegisteredListeners;
45ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
460f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin    private final HashMap<ImageProcessorListener, Long> mImageFilter;
47ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
4830ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin    /**
490f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin     * Wrapper for the log to avoid direct references to Android Log objects
500f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin     * that will crash unit tests. Subclasses may override this method for
510f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin     * debugging.
520f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin     *
5330ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin     * @param message
5430ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin     */
5530ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin    protected void logWrapper(String message) {
560f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin        // Uncomment for more verbose messaging.
570f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin        // Log.v(TAG, message);
5830ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin    }
5930ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin
60ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin    ImageProcessorProxyListener() {
61ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin        mRegisteredListeners = new ArrayList<ImageProcessorListener>();
62ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin        mImageFilter = new HashMap<ImageProcessorListener, Long>();
63ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin    }
64ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
650f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin    /**
660f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin     * Returns the size of the ImageFilter so that we ensure that there are no
670f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin     * reference leaks.
680f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin     *
690f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin     * @return the number of elements in the mapping between
700f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin     *         ImageProcessorListener and their ids.
710f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin     */
720f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin    @VisibleForTesting
730f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin    public int getMapSize() {
740f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin        synchronized (mRegisteredListeners) {
750f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin            return mImageFilter.size();
760f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin        }
770f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin    }
780f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin
790f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin    /**
800f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin     * Returns the number of ImageProcessorListener held by the system so that
810f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin     * we ensure that there are no reference leaks.
820f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin     *
830f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin     * @return the number of registered ImageProcessorListener
840f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin     */
850f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin    @VisibleForTesting
860f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin    public int getNumRegisteredListeners() {
87ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin        synchronized (mRegisteredListeners) {
880f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin            return mRegisteredListeners.size();
890f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin        }
900f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin    }
910f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin
920f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin    /**
930f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin     * Register a listener filtered by a particular image object. If image is
940f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin     * null, then events from all image processing will be sent to the
950f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin     * registered listener.
960f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin     *
970f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin     * @param listener The listener to be registered.
980f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin     * @param image The specific image to filter the events to the listener. If
990f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin     *            null, then the listener receives events from all images that
1000f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin     *            are being processed.
1010f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin     */
1020f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin    public void registerListener(ImageProcessorListener listener,
1030f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin            @Nullable ImageProxy image) {
1040f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin        synchronized (mRegisteredListeners) {
1050f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin            logWrapper("There are " + mRegisteredListeners.size()
1060f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin                    + " listeners before addition");
1070f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin            if (!mRegisteredListeners.contains(listener)) {
1080f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin                mRegisteredListeners.add(listener);
1090f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin                logWrapper("Listener will be overwritten.");
1100f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin            }
1110f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin
112ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin            if (image == null) {
113ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin                mImageFilter.put(listener, null);
114ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin            } else {
115ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin                mImageFilter.put(listener, image.getTimestamp());
116ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin            }
1170f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin            logWrapper("There are " + mRegisteredListeners.size()
1180f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin                    + " listeners after addition");
119ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin        }
120ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
1210f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin        return;
122ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin    }
123ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
124ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin    private List<ImageProcessorListener> filteredListeners(long imageId) {
125ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin        List<ImageProcessorListener> filteredList = new ArrayList<ImageProcessorListener>();
126ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
127ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin        for (ImageProcessorListener l : mRegisteredListeners) {
128ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin            if (mImageFilter.get(l) == null || mImageFilter.get(l) == imageId) {
129ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin                filteredList.add(l);
130ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin            }
131ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin        }
132ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
133ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin        return filteredList;
134ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin    }
135ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
136ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin    public void unregisterListener(ImageProcessorListener listener) {
137ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin        synchronized (mRegisteredListeners) {
138ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin            if (mRegisteredListeners.contains(listener)) {
139ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin                mRegisteredListeners.remove(listener);
140ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin                mImageFilter.remove(listener);
1410f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin                logWrapper("There are " + mRegisteredListeners.size()
1420f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin                        + " listeners after removal");
143ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin            } else {
14430ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin                logWrapper("Couldn't find listener.  There are " + mRegisteredListeners.size()
145ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin                        + " listeners after removal");
146ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin            }
147ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin        }
148ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin    }
149ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
150ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin    public void onStart(TaskImageContainer.TaskInfo job) {
15122f00c96114a150ed75f02810a3fff1fa6461564Paul Rohde        final List<ImageProcessorListener> listeners;
152ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin        synchronized (mRegisteredListeners) {
15322f00c96114a150ed75f02810a3fff1fa6461564Paul Rohde            listeners = filteredListeners(job.contentId);
15422f00c96114a150ed75f02810a3fff1fa6461564Paul Rohde        }
15522f00c96114a150ed75f02810a3fff1fa6461564Paul Rohde
15622f00c96114a150ed75f02810a3fff1fa6461564Paul Rohde        for (ImageProcessorListener l : listeners) {
15722f00c96114a150ed75f02810a3fff1fa6461564Paul Rohde            l.onStart(job);
158ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin        }
159ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin    }
160ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
161ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin    public void onResultCompressed(TaskImageContainer.TaskInfo job,
162ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin            TaskImageContainer.CompressedPayload payload) {
16322f00c96114a150ed75f02810a3fff1fa6461564Paul Rohde        final List<ImageProcessorListener> listeners;
164ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin        synchronized (mRegisteredListeners) {
16522f00c96114a150ed75f02810a3fff1fa6461564Paul Rohde            listeners = filteredListeners(job.contentId);
16622f00c96114a150ed75f02810a3fff1fa6461564Paul Rohde        }
16722f00c96114a150ed75f02810a3fff1fa6461564Paul Rohde
16822f00c96114a150ed75f02810a3fff1fa6461564Paul Rohde        for (ImageProcessorListener l : listeners) {
16922f00c96114a150ed75f02810a3fff1fa6461564Paul Rohde            l.onResultCompressed(job, payload);
170ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin        }
171ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin    }
172ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
173ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin    public void onResultUncompressed(TaskImageContainer.TaskInfo job,
174ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin            TaskImageContainer.UncompressedPayload payload) {
17522f00c96114a150ed75f02810a3fff1fa6461564Paul Rohde        final List<ImageProcessorListener> listeners;
176ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin        synchronized (mRegisteredListeners) {
17722f00c96114a150ed75f02810a3fff1fa6461564Paul Rohde            listeners = filteredListeners(job.contentId);
17822f00c96114a150ed75f02810a3fff1fa6461564Paul Rohde        }
17922f00c96114a150ed75f02810a3fff1fa6461564Paul Rohde
18022f00c96114a150ed75f02810a3fff1fa6461564Paul Rohde        for (ImageProcessorListener l : listeners) {
18122f00c96114a150ed75f02810a3fff1fa6461564Paul Rohde            l.onResultUncompressed(job, payload);
182ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin        }
183ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin    }
184ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
185ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin    public void onResultUri(TaskImageContainer.TaskInfo job, Uri uri) {
18622f00c96114a150ed75f02810a3fff1fa6461564Paul Rohde        final List<ImageProcessorListener> listeners;
187ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin        synchronized (mRegisteredListeners) {
18822f00c96114a150ed75f02810a3fff1fa6461564Paul Rohde            listeners = filteredListeners(job.contentId);
18922f00c96114a150ed75f02810a3fff1fa6461564Paul Rohde        }
19022f00c96114a150ed75f02810a3fff1fa6461564Paul Rohde
19122f00c96114a150ed75f02810a3fff1fa6461564Paul Rohde        for (ImageProcessorListener l : listeners) {
19222f00c96114a150ed75f02810a3fff1fa6461564Paul Rohde            l.onResultUri(job, uri);
193ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin        }
194ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin    }
195ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
196ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin}
197