1 /* 2 * Copyright (C) 2008 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 17 package com.android.tools.layoutlib.create; 18 19 import java.util.HashMap; 20 21 /** 22 * Allows stub methods from LayoutLib to be overriden at runtime. 23 * <p/> 24 * Implementation note: all types required by this class(inner/outer classes & interfaces) 25 * must be referenced by the injectClass argument to {@link AsmGenerator} in Main.java; 26 * Otherwise they won't be accessible in layoutlib.jar at runtime. 27 */ 28 public final class OverrideMethod { 29 30 /** Map of method overridden. */ 31 private static HashMap<String, MethodListener> sMethods = new HashMap<>(); 32 /** Default listener for all method not listed in sMethods. Nothing if null. */ 33 private static MethodListener sDefaultListener = null; 34 35 /** 36 * Sets the default listener for all methods not specifically handled. 37 * Null means to do nothing. 38 */ 39 @SuppressWarnings("UnusedDeclaration") // Used by Bridge by reflection for debug purposes. setDefaultListener(MethodListener listener)40 public static void setDefaultListener(MethodListener listener) { 41 sDefaultListener = listener; 42 } 43 44 /** 45 * Defines or reset a listener for the given method signature. 46 * 47 * @param signature The signature of the method being invoked, composed of the 48 * binary class name followed by the method descriptor (aka argument 49 * types). Example: "com/foo/MyClass/InnerClass/printInt(I)V" 50 * @param listener The new listener. Removes it if null. 51 */ setMethodListener(String signature, MethodListener listener)52 public static void setMethodListener(String signature, MethodListener listener) { 53 if (listener == null) { 54 sMethods.remove(signature); 55 } else { 56 sMethods.put(signature, listener); 57 } 58 } 59 60 /** 61 * Invokes the specific listener for the given signature or the default one if defined. 62 * <p/> 63 * This version invokes the method listener for the void return type. 64 * <p/> 65 * Note: this is not intended to be used by the LayoutLib Bridge. It is intended to be called 66 * by the stubbed methods generated by the LayoutLib_create tool. 67 * 68 * @param signature The signature of the method being invoked, composed of the 69 * binary class name followed by the method descriptor (aka argument 70 * types). Example: "com/foo/MyClass/InnerClass/printInt(I)V". 71 * @param isNative True if the method was a native method. 72 * @param caller The calling object. Null for static methods, "this" for instance methods. 73 */ invokeV(String signature, boolean isNative, Object caller)74 public static void invokeV(String signature, boolean isNative, Object caller) { 75 MethodListener i = sMethods.get(signature); 76 if (i != null) { 77 i.onInvokeV(signature, isNative, caller); 78 } else if (sDefaultListener != null) { 79 sDefaultListener.onInvokeV(signature, isNative, caller); 80 } 81 } 82 83 /** 84 * Invokes the specific listener for the int return type. 85 * @see #invokeV(String, boolean, Object) 86 */ invokeI(String signature, boolean isNative, Object caller)87 public static int invokeI(String signature, boolean isNative, Object caller) { 88 MethodListener i = sMethods.get(signature); 89 if (i != null) { 90 return i.onInvokeI(signature, isNative, caller); 91 } else if (sDefaultListener != null) { 92 return sDefaultListener.onInvokeI(signature, isNative, caller); 93 } 94 return 0; 95 } 96 97 /** 98 * Invokes the specific listener for the long return type. 99 * @see #invokeV(String, boolean, Object) 100 */ invokeL(String signature, boolean isNative, Object caller)101 public static long invokeL(String signature, boolean isNative, Object caller) { 102 MethodListener i = sMethods.get(signature); 103 if (i != null) { 104 return i.onInvokeL(signature, isNative, caller); 105 } else if (sDefaultListener != null) { 106 return sDefaultListener.onInvokeL(signature, isNative, caller); 107 } 108 return 0; 109 } 110 111 /** 112 * Invokes the specific listener for the float return type. 113 * @see #invokeV(String, boolean, Object) 114 */ invokeF(String signature, boolean isNative, Object caller)115 public static float invokeF(String signature, boolean isNative, Object caller) { 116 MethodListener i = sMethods.get(signature); 117 if (i != null) { 118 return i.onInvokeF(signature, isNative, caller); 119 } else if (sDefaultListener != null) { 120 return sDefaultListener.onInvokeF(signature, isNative, caller); 121 } 122 return 0; 123 } 124 125 /** 126 * Invokes the specific listener for the double return type. 127 * @see #invokeV(String, boolean, Object) 128 */ invokeD(String signature, boolean isNative, Object caller)129 public static double invokeD(String signature, boolean isNative, Object caller) { 130 MethodListener i = sMethods.get(signature); 131 if (i != null) { 132 return i.onInvokeD(signature, isNative, caller); 133 } else if (sDefaultListener != null) { 134 return sDefaultListener.onInvokeD(signature, isNative, caller); 135 } 136 return 0; 137 } 138 139 /** 140 * Invokes the specific listener for the object return type. 141 * @see #invokeV(String, boolean, Object) 142 */ invokeA(String signature, boolean isNative, Object caller)143 public static Object invokeA(String signature, boolean isNative, Object caller) { 144 MethodListener i = sMethods.get(signature); 145 if (i != null) { 146 return i.onInvokeA(signature, isNative, caller); 147 } else if (sDefaultListener != null) { 148 return sDefaultListener.onInvokeA(signature, isNative, caller); 149 } 150 return null; 151 } 152 } 153