10b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin/*
20b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin * Copyright (C) 2014 The Android Open Source Project
30b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin *
40b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin * Licensed under the Apache License, Version 2.0 (the "License");
50b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin * you may not use this file except in compliance with the License.
60b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin * You may obtain a copy of the License at
70b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin *
80b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin *      http://www.apache.org/licenses/LICENSE-2.0
90b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin *
100b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin * Unless required by applicable law or agreed to in writing, software
110b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin * distributed under the License is distributed on an "AS IS" BASIS,
120b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin * See the License for the specific language governing permissions and
140b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin * limitations under the License.
150b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin */
160b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkinpackage android.hardware.camera2.dispatch;
170b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin
180b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkinimport android.hardware.camera2.utils.UncheckedThrow;
190b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkinimport android.os.Handler;
200b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkinimport android.util.Log;
210b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin
220b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkinimport java.lang.reflect.InvocationTargetException;
230b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkinimport java.lang.reflect.Method;
240b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin
250b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkinimport static com.android.internal.util.Preconditions.*;
260b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin
270b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin/**
280b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin * Forward all interface calls into a handler by posting it as a {@code Runnable}.
290b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin *
300b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin * <p>All calls will return immediately; functions with return values will return a default
310b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin * value of {@code null}, {@code 0}, or {@code false} where that value is legal.</p>
320b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin *
330b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin * <p>Any exceptions thrown on the handler while trying to invoke a method
340b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin * will be re-thrown. Throwing checked exceptions on a handler which doesn't expect any
350b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin * checked exceptions to be thrown will result in "undefined" behavior
360b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin * (although in practice it is usually thrown as normal).</p>
370b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin */
380b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkinpublic class HandlerDispatcher<T> implements Dispatchable<T> {
390b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin
400b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin    private static final String TAG = "HandlerDispatcher";
410b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin
420b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin    private final Dispatchable<T> mDispatchTarget;
430b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin    private final Handler mHandler;
440b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin
450b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin    /**
460b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin     * Create a dispatcher that forwards it's dispatch calls by posting
470b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin     * them onto the {@code handler} as a {@code Runnable}.
480b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin     *
490b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin     * @param dispatchTarget the destination whose method calls will be redirected into the handler
500b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin     * @param handler all calls into {@code dispatchTarget} will be posted onto this handler
510b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin     * @param <T> the type of the element you want to wrap.
520b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin     * @return a dispatcher that will forward it's dispatch calls to a handler
530b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin     */
540b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin    public HandlerDispatcher(Dispatchable<T> dispatchTarget, Handler handler) {
550b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin        mDispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null");
560b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin        mHandler = checkNotNull(handler, "handler must not be null");
570b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin    }
580b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin
590b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin    @Override
600b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin    public Object dispatch(final Method method, final Object[] args) throws Throwable {
610b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin        mHandler.post(new Runnable() {
620b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin            @Override
630b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin            public void run() {
640b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin                try {
650b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin                    mDispatchTarget.dispatch(method, args);
660b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin                } catch (InvocationTargetException e) {
670b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin                    Throwable t = e.getTargetException();
680b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin                    // Potential UB. Hopefully 't' is a runtime exception.
690b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin                    UncheckedThrow.throwAnyException(t);
700b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin                } catch (IllegalAccessException e) {
710b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin                    // Impossible
720b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin                    Log.wtf(TAG, "IllegalAccessException while invoking " + method, e);
730b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin                } catch (IllegalArgumentException e) {
740b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin                    // Impossible
750b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin                    Log.wtf(TAG, "IllegalArgumentException while invoking " + method, e);
760b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin                } catch (Throwable e) {
770b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin                    UncheckedThrow.throwAnyException(e);
780b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin                }
790b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin            }
800b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin        });
810b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin
820b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin        // TODO handle primitive return values that would avoid NPE if unboxed
830b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin        return null;
840b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin    }
850b27d3453d5e257594792e9177c5fedb1bc6f9e9Igor Murashkin}
86