CameraBinderDecorator.java revision e363fbb2647aeb5ef4c87160d84c6b9ae8d45598
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
17e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkinpackage android.hardware.photography.utils;
18e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
19e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkinimport static android.hardware.photography.CameraAccessException.CAMERA_DISABLED;
20e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkinimport static android.hardware.photography.CameraAccessException.CAMERA_DISCONNECTED;
21e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkinimport static android.hardware.photography.CameraAccessException.CAMERA_IN_USE;
22e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
23e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkinimport android.os.DeadObjectException;
24e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkinimport android.os.RemoteException;
25e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
26e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkinimport java.lang.reflect.Method;
27e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
28e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin/**
29e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin * Translate camera service status_t return values into exceptions.
30e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin *
31e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin * @see android.hardware.photography.utils.CameraBinderDecorator#newInstance
32e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin * @hide
33e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin */
34e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkinpublic class CameraBinderDecorator {
35e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
36e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    public static final int NO_ERROR = 0;
37e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    public static final int PERMISSION_DENIED = -1;
38e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    public static final int ALREADY_EXISTS = -17;
39e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    public static final int BAD_VALUE = -22;
40e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    public static final int DEAD_OBJECT = -32;
41e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
42e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    /**
43e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * TODO: add as error codes in Errors.h
44e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * - POLICY_PROHIBITS
45e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * - RESOURCE_BUSY
46e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * - NO_SUCH_DEVICE
47e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     */
48e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    public static final int EACCES = -13;
49e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    public static final int EBUSY = -16;
50e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    public static final int ENODEV = -19;
51e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
52e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    private static class CameraBinderDecoratorListener implements Decorator.DecoratorListener {
53e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
54e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        @Override
55e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        public void onBeforeInvocation(Method m, Object[] args) {
56e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        }
57e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
58e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        @Override
59e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        public void onAfterInvocation(Method m, Object[] args, Object result) {
60e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            // int return type => status_t => convert to exception
61e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            if (m.getReturnType() == Integer.TYPE) {
62e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                int returnValue = (Integer) result;
63e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
64e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                switch (returnValue) {
65e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                    case NO_ERROR:
66e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                        return;
67e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                    case PERMISSION_DENIED:
68e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                        throw new SecurityException("Lacking privileges to access camera service");
69e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                    case ALREADY_EXISTS:
70e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                        return;
71e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                    case BAD_VALUE:
72e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                        throw new IllegalArgumentException("Bad argument passed to camera service");
73e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                    case DEAD_OBJECT:
74e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                        UncheckedThrow.throwAnyException(new CameraRuntimeException(
75e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                                CAMERA_DISCONNECTED));
76e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                        // TODO: Camera service (native side) should return
77e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                        // EACCES error
78e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                        // when there's a policy manager disabled causing this
79e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                    case EACCES:
80e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                        UncheckedThrow.throwAnyException(new CameraRuntimeException(
81e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                                CAMERA_DISABLED));
82e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                    case EBUSY:
83e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                        UncheckedThrow.throwAnyException(new CameraRuntimeException(
84e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                                CAMERA_IN_USE));
85e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                    case ENODEV:
86e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                        UncheckedThrow.throwAnyException(new CameraRuntimeException(
87e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                                CAMERA_DISCONNECTED));
88e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                }
89e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
90e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                /**
91e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                 * Trap the rest of the negative return values. If we have known
92e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                 * error codes i.e. ALREADY_EXISTS that aren't really runtime
93e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                 * errors, then add them to the top switch statement
94e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                 */
95e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                if (returnValue < 0) {
96e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                    throw new UnsupportedOperationException(String.format("Unknown error %d",
97e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                            returnValue));
98e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                }
99e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            }
100e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        }
101e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
102e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        @Override
103e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        public boolean onCatchException(Method m, Object[] args, Throwable t) {
104e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
105e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            if (t instanceof DeadObjectException) {
106e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                UncheckedThrow.throwAnyException(new CameraRuntimeException(
107e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                        CAMERA_DISCONNECTED,
108e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                        "Process hosting the camera service has died unexpectedly",
109e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                        t));
110e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            } else if (t instanceof RemoteException) {
111e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                throw new UnsupportedOperationException("An unknown RemoteException was thrown" +
112e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                        " which should never happen.", t);
113e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            }
114e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
115e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            return false;
116e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        }
117e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
118e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        @Override
119e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        public void onFinally(Method m, Object[] args) {
120e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        }
121e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
122e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    }
123e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
124e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    /**
125e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * <p>
126e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * Wraps the type T with a proxy that will check 'status_t' return codes
127e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * from the native side of the camera service, and throw Java exceptions
128e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * automatically based on the code.
129e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * </p>
130e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * <p>
131e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * In addition it also rewrites binder's RemoteException into either a
132e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * CameraAccessException or an UnsupportedOperationException.
133e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * </p>
134e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * <p>
135e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * As a result of calling any method on the proxy, RemoteException is
136e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * guaranteed never to be thrown.
137e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * </p>
138e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     *
139e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * @param obj object that will serve as the target for all method calls
140e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * @param <T> the type of the element you want to wrap. This must be an interface.
141e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * @return a proxy that will intercept all invocations to obj
142e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     */
143e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    public static <T> T newInstance(T obj) {
144e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        return Decorator.<T> newInstance(obj, new CameraBinderDecoratorListener());
145e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    }
146e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin}
147