1e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin/*
2e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin * Copyright (C) 2013 The Android Open Source Project
3e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin *
4e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin * Licensed under the Apache License, Version 2.0 (the "License");
5e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin * you may not use this file except in compliance with the License.
6e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin * You may obtain a copy of the License at
7e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin *
8e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin *      http://www.apache.org/licenses/LICENSE-2.0
9e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin *
10e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin * Unless required by applicable law or agreed to in writing, software
11e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin * distributed under the License is distributed on an "AS IS" BASIS,
12e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin * See the License for the specific language governing permissions and
14e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin * limitations under the License.
15e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin */
16e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
172f1a2e423e0fbb64467d6fcfa4e82c6384f31210Eino-Ville Talvalapackage android.hardware.camera2.utils;
18e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
192f1a2e423e0fbb64467d6fcfa4e82c6384f31210Eino-Ville Talvalaimport static android.hardware.camera2.CameraAccessException.CAMERA_DISABLED;
202f1a2e423e0fbb64467d6fcfa4e82c6384f31210Eino-Ville Talvalaimport static android.hardware.camera2.CameraAccessException.CAMERA_DISCONNECTED;
212f1a2e423e0fbb64467d6fcfa4e82c6384f31210Eino-Ville Talvalaimport static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE;
229503785393ba8999473b7a924ede2baf520e367cEino-Ville Talvalaimport static android.hardware.camera2.CameraAccessException.CAMERA_ERROR;
2368ebc1a7b4c18d587612891250f17f36edfe1bc1Zhijun Heimport static android.hardware.camera2.CameraAccessException.MAX_CAMERAS_IN_USE;
2466ef64514464a1bb9c7931993cc8db3d7539f39aRuben Brunkimport static android.hardware.camera2.CameraAccessException.CAMERA_DEPRECATED_HAL;
25e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
26e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkinimport android.os.DeadObjectException;
27e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkinimport android.os.RemoteException;
28e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
29e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkinimport java.lang.reflect.Method;
30e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
31e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin/**
32bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala * Translate camera device status_t return values into exceptions.
33e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin *
342f1a2e423e0fbb64467d6fcfa4e82c6384f31210Eino-Ville Talvala * @see android.hardware.camera2.utils.CameraBinderDecorator#newInstance
35e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin * @hide
36e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin */
37e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkinpublic class CameraBinderDecorator {
38e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
39e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    public static final int NO_ERROR = 0;
40e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    public static final int PERMISSION_DENIED = -1;
41e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    public static final int ALREADY_EXISTS = -17;
42e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    public static final int BAD_VALUE = -22;
43e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    public static final int DEAD_OBJECT = -32;
44feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public static final int INVALID_OPERATION = -38;
459503785393ba8999473b7a924ede2baf520e367cEino-Ville Talvala    public static final int TIMED_OUT = -110;
46e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
47e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    /**
48e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * TODO: add as error codes in Errors.h
49e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * - POLICY_PROHIBITS
50e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * - RESOURCE_BUSY
51e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * - NO_SUCH_DEVICE
524961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin     * - NOT_SUPPORTED
534961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin     * - TOO_MANY_USERS
54e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     */
55e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    public static final int EACCES = -13;
56e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    public static final int EBUSY = -16;
57e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    public static final int ENODEV = -19;
586462be7fa0234ca1a285f4f40089f9be1fed8316Ruben Brunk    public static final int EOPNOTSUPP = -95;
599bd5f1e6dff31e2299c065157ba3a43bc79a9d48Zhijun He    public static final int EUSERS = -87;
60e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
61feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
62bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala    static class CameraBinderDecoratorListener implements Decorator.DecoratorListener {
63e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
64e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        @Override
65e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        public void onBeforeInvocation(Method m, Object[] args) {
66e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        }
67e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
68e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        @Override
69e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        public void onAfterInvocation(Method m, Object[] args, Object result) {
70e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            // int return type => status_t => convert to exception
71e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            if (m.getReturnType() == Integer.TYPE) {
72e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                int returnValue = (Integer) result;
7385c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk                throwOnError(returnValue);
74e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            }
75e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        }
76e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
77e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        @Override
78e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        public boolean onCatchException(Method m, Object[] args, Throwable t) {
79e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
80e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            if (t instanceof DeadObjectException) {
81bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                throw new CameraRuntimeException(CAMERA_DISCONNECTED,
82e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                        "Process hosting the camera service has died unexpectedly",
83bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                        t);
84e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            } else if (t instanceof RemoteException) {
85e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                throw new UnsupportedOperationException("An unknown RemoteException was thrown" +
86e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                        " which should never happen.", t);
87e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            }
88e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
89e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            return false;
90e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        }
91e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
92e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        @Override
93e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        public void onFinally(Method m, Object[] args) {
94e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        }
95e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
96e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    }
97e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
98e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    /**
9985c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk     * Throw error codes returned by the camera service as exceptions.
10085c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk     *
10185c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk     * @param errorFlag error to throw as an exception.
10285c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk     */
10385c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk    public static void throwOnError(int errorFlag) {
10485c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk        switch (errorFlag) {
10585c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk            case NO_ERROR:
10685c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk                return;
10785c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk            case PERMISSION_DENIED:
10885c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk                throw new SecurityException("Lacking privileges to access camera service");
10985c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk            case ALREADY_EXISTS:
11085c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk                // This should be handled at the call site. Typically this isn't bad,
11185c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk                // just means we tried to do an operation that already completed.
11285c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk                return;
11385c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk            case BAD_VALUE:
11485c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk                throw new IllegalArgumentException("Bad argument passed to camera service");
11585c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk            case DEAD_OBJECT:
116bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                throw new CameraRuntimeException(CAMERA_DISCONNECTED);
1179503785393ba8999473b7a924ede2baf520e367cEino-Ville Talvala            case TIMED_OUT:
1189503785393ba8999473b7a924ede2baf520e367cEino-Ville Talvala                throw new CameraRuntimeException(CAMERA_ERROR,
1199503785393ba8999473b7a924ede2baf520e367cEino-Ville Talvala                        "Operation timed out in camera service");
12085c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk            case EACCES:
121bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                throw new CameraRuntimeException(CAMERA_DISABLED);
12285c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk            case EBUSY:
123bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                throw new CameraRuntimeException(CAMERA_IN_USE);
12485c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk            case EUSERS:
125bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                throw new CameraRuntimeException(MAX_CAMERAS_IN_USE);
12685c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk            case ENODEV:
127bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                throw new CameraRuntimeException(CAMERA_DISCONNECTED);
12885c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk            case EOPNOTSUPP:
129bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                throw new CameraRuntimeException(CAMERA_DEPRECATED_HAL);
130feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            case INVALID_OPERATION:
1319503785393ba8999473b7a924ede2baf520e367cEino-Ville Talvala                throw new CameraRuntimeException(CAMERA_ERROR,
132bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                        "Illegal state encountered in camera service.");
13385c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk        }
13485c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk
13585c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk        /**
13685c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk         * Trap the rest of the negative return values. If we have known
13785c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk         * error codes i.e. ALREADY_EXISTS that aren't really runtime
13885c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk         * errors, then add them to the top switch statement
13985c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk         */
14085c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk        if (errorFlag < 0) {
14185c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk            throw new UnsupportedOperationException(String.format("Unknown error %d",
14285c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk                    errorFlag));
14385c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk        }
14485c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk    }
14585c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk
14685c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk    /**
147e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * <p>
148e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * Wraps the type T with a proxy that will check 'status_t' return codes
149e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * from the native side of the camera service, and throw Java exceptions
150e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * automatically based on the code.
151e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * </p>
152e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * <p>
153e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * In addition it also rewrites binder's RemoteException into either a
154e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * CameraAccessException or an UnsupportedOperationException.
155e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * </p>
156e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * <p>
157e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * As a result of calling any method on the proxy, RemoteException is
158e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * guaranteed never to be thrown.
159e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * </p>
160e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     *
161e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * @param obj object that will serve as the target for all method calls
162e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * @param <T> the type of the element you want to wrap. This must be an interface.
163e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * @return a proxy that will intercept all invocations to obj
164e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     */
165e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    public static <T> T newInstance(T obj) {
166e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        return Decorator.<T> newInstance(obj, new CameraBinderDecoratorListener());
167e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    }
168e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin}
169