18ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher/*
28ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher * Copyright (C) 2014 The Android Open Source Project
38ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher *
48ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher * Licensed under the Apache License, Version 2.0 (the "License");
58ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher * you may not use this file except in compliance with the License.
68ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher * You may obtain a copy of the License at
78ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher *
88ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher *      http://www.apache.org/licenses/LICENSE-2.0
98ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher *
108ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher * Unless required by applicable law or agreed to in writing, software
118ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher * distributed under the License is distributed on an "AS IS" BASIS,
128ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher * See the License for the specific language governing permissions and
148ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher * limitations under the License.
158ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher */
168ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher
178ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucherpackage com.android.ex.camera2.utils;
188ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher
198ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucherimport android.hardware.camera2.CameraAccessException;
208ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucherimport android.hardware.camera2.CameraDevice;
218ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucherimport android.hardware.camera2.CaptureRequest;
228ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucherimport android.hardware.camera2.CaptureRequest.Builder;
238ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucherimport android.hardware.camera2.CaptureRequest.Key;
248ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucherimport android.view.Surface;
258ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher
268ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucherimport java.util.HashMap;
278ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucherimport java.util.Map;
288ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucherimport java.util.Objects;
298ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher
308ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher/**
318ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher * A set of settings to be used when filing a {@link CaptureRequest}.
328ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher */
338ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucherpublic class Camera2RequestSettingsSet {
348ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    private final Map<Key<?>, Object> mDictionary;
358ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    private long mRevision;
368ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher
378ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    /**
388ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * Create a new instance with no settings defined.
398ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     *
408ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * <p>Creating a request from this object without first specifying any
418ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * properties on it is equivalent to just creating a request directly
428ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * from the template of choice. Its revision identifier is initially
438ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * {@code 0}, and will remain thus until its first modification.</p>
448ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     */
458ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    public Camera2RequestSettingsSet() {
468ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        mDictionary = new HashMap<>();
478ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        mRevision = 0;
488ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    }
498ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher
508ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    /**
518ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * Perform a deep copy of the defined settings and revision number.
528ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     *
538ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * @param other The reference instance.
548ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     *
558ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * @throws NullPointerException If {@code other} is {@code null}.
568ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     */
578ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    public Camera2RequestSettingsSet(Camera2RequestSettingsSet other) {
588ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        if (other == null) {
598ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher            throw new NullPointerException("Tried to copy null Camera2RequestSettingsSet");
608ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        }
618ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher
628ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        mDictionary = new HashMap<>(other.mDictionary);
638ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        mRevision = other.mRevision;
648ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    }
658ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher
668ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    /**
678ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * Specify a setting, potentially overriding the template's default choice.
688ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     *
698ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * <p>Providing a {@code null} {@code value} will indicate a forced use of
708ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * the template's selection for that {@code key}; the difference here is
718ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * that this information will be propagated with unions as documented in
728ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * {@link #union}. This method increments the revision identifier if the new
738ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * choice is different than the existing selection.</p>
748ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     *
758ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * @param key Which setting to alter.
768ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * @param value The new selection for that setting, or {@code null} to force
778ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     *              the use of the template's default selection for this field.
788ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * @return Whether the settings were updated, which only occurs if the
798ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     *         {@code value} is different from any already stored.
808ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     *
818ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * @throws NullPointerException If {@code key} is {@code null}.
828ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     */
838ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    public <T> boolean set(Key<T> key, T value) {
848ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        if (key == null) {
858ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher            throw new NullPointerException("Received a null key");
868ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        }
878ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher
888ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        Object currentValue = get(key);
898ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        // Only save the value if it's different from the one we already have
908ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        if (!mDictionary.containsKey(key) || !Objects.equals(value, currentValue)) {
918ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher            mDictionary.put(key, value);
928ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher            ++mRevision;
938ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher            return true;
948ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        }
958ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        return false;
968ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    }
978ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher
988ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    /**
998ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * Unsets a setting, preventing it from being propagated with unions or from
1008ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * overriding the default when creating a capture request.
1018ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     *
1028ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * <p>This method increments the revision identifier if a selection had
1038ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * previously been made for that parameter.</p>
1048ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     *
1058ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * @param key Which setting to reset.
1068ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * @return Whether the settings were updated, which only occurs if the
1078ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     *         specified setting already had a value or was forced to default.
1088ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     *
1098ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * @throws NullPointerException If {@code key} is {@code null}.
1108ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     */
1118ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    public boolean unset(Key<?> key) {
1128ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        if (key == null) {
1138ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher            throw new NullPointerException("Received a null key");
1148ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        }
1158ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher
1168ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        if (mDictionary.containsKey(key)) {
1178ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher            mDictionary.remove(key);
1188ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher            ++mRevision;
1198ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher            return true;
1208ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        }
1218ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        return false;
1228ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    }
1238ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher
1248ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    /**
1258ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * Interrogate the current specialization of a setting.
1268ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     *
1278ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * @param key Which setting to check.
1288ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * @return The current selection for that setting, or {@code null} if the
1298ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     *         setting is unset or forced to the template-defined default.
1308ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     *
1318ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * @throws NullPointerException If {@code key} is {@code null}.
1328ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     */
1338ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    @SuppressWarnings("unchecked")
1348ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    public <T> T get(Key<T> key) {
1358ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        if (key == null) {
1368ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher            throw new NullPointerException("Received a null key");
1378ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        }
1388ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        return (T) mDictionary.get(key);
1398ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    }
1408ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher
1418ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    /**
1428ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * Query this instance for whether it prefers a particular choice for the
1438ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * given request parameter.
1448ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     *
1458ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * <p>This method can be used to detect whether a particular field is forced
1468ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * to its default value or simply unset. While {@link #get} will return
1478ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * {@code null} in both these cases, this method will return {@code true}
1488ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * and {@code false}, respectively.</p>
149984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher     *
1508ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * @param key Which setting to look for.
1518ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * @return Whether that setting has a value that will propagate with unions.
1528ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     *
1538ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * @throws NullPointerException If {@code key} is {@code null}.
1548ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     */
1558ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    public boolean contains(Key<?> key) {
1568ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        if (key == null) {
1578ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher            throw new NullPointerException("Received a null key");
1588ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        }
1598ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        return mDictionary.containsKey(key);
1608ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    }
1618ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher
1628ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    /**
163984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher     * Check whether the value of the specified setting matches the given one.
164984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher     *
165984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher     * <p>This method uses the {@code T} type's {@code equals} method, but is
166984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher     * {@code null}-tolerant.</p>
167984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher     *
168984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher     * @param key Which of this class's settings to check.
169984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher     * @param value Value to test for equality against.
170984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher     * @return Whether they are the same.
171984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher     */
172984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher    public <T> boolean matches(Key<T> key, T value) {
173984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher        return Objects.equals(get(key), value);
174984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher    }
175984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher
176984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher    /**
1778ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * Get this set of settings's revision identifier, which can be compared
1788ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * against cached past values to determine whether it has been modified.
179984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher     *
1808ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * <p>Distinct revisions across the same object do not necessarily indicate
1818ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * that the object's key/value pairs have changed at all, but the same
1828ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * revision on the same object does imply that they've stayed the same.</p>
1838ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     *
1848ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * @return The number of modifications made since the beginning of this
1858ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     *         object's heritage.
1868ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     */
1878ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    public long getRevision() {
1888ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        return mRevision;
1898ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    }
1908ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher
1918ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    /**
1928ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * Add all settings choices defined by {@code moreSettings} to this object.
1938ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     *
1948ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * <p>For any settings defined in both, the choice stored in the argument
1958ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * to this method take precedence. Unset settings are not propagated, but
1968ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * those forced to default as described in {@link set} are also forced to
1978ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * default in {@code this} set. Invoking this method increments {@code this}
1988ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * object's revision counter, but leaves the argument's unchanged.</p>
1998ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     *
2008ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * @param moreSettings The source of the additional settings ({@code null}
2018ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     *                     is allowed here).
2028ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * @return Whether these settings were updated, which can only fail if the
2038ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     *         target itself is also given as the argument.
2048ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     */
2058ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    public boolean union(Camera2RequestSettingsSet moreSettings) {
2068ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        if (moreSettings == null || moreSettings == this) {
2078ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher            return false;
2088ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        }
2098ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher
2108ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        mDictionary.putAll(moreSettings.mDictionary);
2118ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        ++mRevision;
2128ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        return true;
2138ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    }
2148ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher
2158ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    /**
2168ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * Create a {@link CaptureRequest} specialized for the specified
2178ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * {@link CameraDevice} and targeting the given {@link Surface}s.
2188ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     *
2198ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * @param camera The camera from which to capture.
2208ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * @param template A {@link CaptureRequest} template defined in
2218ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     *                 {@link CameraDevice}.
2228ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * @param targets The location(s) to draw the resulting image onto.
2238ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * @return The request, ready to be passed to the camera framework.
2248ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     *
2258ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * @throws CameraAccessException Upon an underlying framework API failure.
2268ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     * @throws NullPointerException If any argument is {@code null}.
2278ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher     */
2288ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    public CaptureRequest createRequest(CameraDevice camera, int template, Surface... targets)
2298ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher            throws CameraAccessException {
2308ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        if (camera == null) {
2318ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher            throw new NullPointerException("Tried to create request using null CameraDevice");
2328ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        }
2338ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher
2348ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        Builder reqBuilder = camera.createCaptureRequest(template);
2358ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        for (Key<?> key : mDictionary.keySet()) {
2368ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher            setRequestFieldIfNonNull(reqBuilder, key);
2378ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        }
2388ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        for (Surface target : targets) {
2398ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher            if (target == null) {
2408ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher                throw new NullPointerException("Tried to add null Surface as request target");
2418ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher            }
2428ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher            reqBuilder.addTarget(target);
2438ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        }
2448ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        return reqBuilder.build();
2458ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    }
2468ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher
2478ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    private <T> void setRequestFieldIfNonNull(Builder requestBuilder, Key<T> key) {
2488ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        T value = get(key);
2498ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        if (value != null) {
2508ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher            requestBuilder.set(key, value);
2518ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher        }
2528ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher    }
2538ba391e3f88936557ad6d44bbef32cb08f4ca310Sol Boucher}
254