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