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 */ 16 package android.hardware.camera2.dispatch; 17 18 import java.lang.reflect.Method; 19 20 import static com.android.internal.util.Preconditions.*; 21 22 /** 23 * A dispatcher that replaces one argument with another; replaces any argument at an index 24 * with another argument. 25 * 26 * <p>For example, we can override an {@code void onSomething(int x)} calls to have {@code x} always 27 * equal to 1. Or, if using this with a duck typing dispatcher, we could even overwrite {@code x} to 28 * be something 29 * that's not an {@code int}.</p> 30 * 31 * @param <T> 32 * source dispatch type, whose methods with {@link #dispatch} will be called 33 * @param <TArg> 34 * argument replacement type, args in {@link #dispatch} matching {@code argumentIndex} 35 * will be overriden to objects of this type 36 */ 37 public class ArgumentReplacingDispatcher<T, TArg> implements Dispatchable<T> { 38 39 private final Dispatchable<T> mTarget; 40 private final int mArgumentIndex; 41 private final TArg mReplaceWith; 42 43 /** 44 * Create a new argument replacing dispatcher; dispatches are forwarded to {@code target} 45 * after the argument is replaced. 46 * 47 * <p>For example, if a method {@code onAction(T1 a, Integer b, T2 c)} is invoked, and we wanted 48 * to replace all occurrences of {@code b} with {@code 0xDEADBEEF}, we would set 49 * {@code argumentIndex = 1} and {@code replaceWith = 0xDEADBEEF}.</p> 50 * 51 * <p>If a method dispatched has less arguments than {@code argumentIndex}, it is 52 * passed through with the arguments unchanged.</p> 53 * 54 * @param target destination dispatch type, methods will be redirected to this dispatcher 55 * @param argumentIndex the numeric index of the argument {@code >= 0} 56 * @param replaceWith arguments matching {@code argumentIndex} will be replaced with this object 57 */ ArgumentReplacingDispatcher(Dispatchable<T> target, int argumentIndex, TArg replaceWith)58 public ArgumentReplacingDispatcher(Dispatchable<T> target, int argumentIndex, 59 TArg replaceWith) { 60 mTarget = checkNotNull(target, "target must not be null"); 61 mArgumentIndex = checkArgumentNonnegative(argumentIndex, 62 "argumentIndex must not be negative"); 63 mReplaceWith = checkNotNull(replaceWith, "replaceWith must not be null"); 64 } 65 66 @Override dispatch(Method method, Object[] args)67 public Object dispatch(Method method, Object[] args) throws Throwable { 68 69 if (args.length > mArgumentIndex) { 70 args = arrayCopy(args); // don't change in-place since it can affect upstream dispatches 71 args[mArgumentIndex] = mReplaceWith; 72 } 73 74 return mTarget.dispatch(method, args); 75 } 76 arrayCopy(Object[] array)77 private static Object[] arrayCopy(Object[] array) { 78 int length = array.length; 79 Object[] newArray = new Object[length]; 80 for (int i = 0; i < length; ++i) { 81 newArray[i] = array[i]; 82 } 83 return newArray; 84 } 85 } 86