1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package android.hardware.camera2.dispatch; 17 18import android.hardware.camera2.utils.UncheckedThrow; 19import android.os.Handler; 20import android.util.Log; 21 22import java.lang.reflect.InvocationTargetException; 23import java.lang.reflect.Method; 24 25import static com.android.internal.util.Preconditions.*; 26 27/** 28 * Forward all interface calls into a handler by posting it as a {@code Runnable}. 29 * 30 * <p>All calls will return immediately; functions with return values will return a default 31 * value of {@code null}, {@code 0}, or {@code false} where that value is legal.</p> 32 * 33 * <p>Any exceptions thrown on the handler while trying to invoke a method 34 * will be re-thrown. Throwing checked exceptions on a handler which doesn't expect any 35 * checked exceptions to be thrown will result in "undefined" behavior 36 * (although in practice it is usually thrown as normal).</p> 37 */ 38public class HandlerDispatcher<T> implements Dispatchable<T> { 39 40 private static final String TAG = "HandlerDispatcher"; 41 42 private final Dispatchable<T> mDispatchTarget; 43 private final Handler mHandler; 44 45 /** 46 * Create a dispatcher that forwards it's dispatch calls by posting 47 * them onto the {@code handler} as a {@code Runnable}. 48 * 49 * @param dispatchTarget the destination whose method calls will be redirected into the handler 50 * @param handler all calls into {@code dispatchTarget} will be posted onto this handler 51 * @param <T> the type of the element you want to wrap. 52 * @return a dispatcher that will forward it's dispatch calls to a handler 53 */ 54 public HandlerDispatcher(Dispatchable<T> dispatchTarget, Handler handler) { 55 mDispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null"); 56 mHandler = checkNotNull(handler, "handler must not be null"); 57 } 58 59 @Override 60 public Object dispatch(final Method method, final Object[] args) throws Throwable { 61 mHandler.post(new Runnable() { 62 @Override 63 public void run() { 64 try { 65 mDispatchTarget.dispatch(method, args); 66 } catch (InvocationTargetException e) { 67 Throwable t = e.getTargetException(); 68 // Potential UB. Hopefully 't' is a runtime exception. 69 UncheckedThrow.throwAnyException(t); 70 } catch (IllegalAccessException e) { 71 // Impossible 72 Log.wtf(TAG, "IllegalAccessException while invoking " + method, e); 73 } catch (IllegalArgumentException e) { 74 // Impossible 75 Log.wtf(TAG, "IllegalArgumentException while invoking " + method, e); 76 } catch (Throwable e) { 77 UncheckedThrow.throwAnyException(e); 78 } 79 } 80 }); 81 82 // TODO handle primitive return values that would avoid NPE if unboxed 83 return null; 84 } 85} 86