Merge "Fix handling of android:onClick for ContextWrapper" into mnc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
f8fdf87c06
@@ -30,6 +30,7 @@ import android.annotation.Nullable;
|
||||
import android.annotation.Size;
|
||||
import android.content.ClipData;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.Intent;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Configuration;
|
||||
@@ -4016,37 +4017,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
|
||||
final String handlerName = a.getString(attr);
|
||||
if (handlerName != null) {
|
||||
setOnClickListener(new OnClickListener() {
|
||||
private Method mHandler;
|
||||
|
||||
public void onClick(View v) {
|
||||
if (mHandler == null) {
|
||||
try {
|
||||
mHandler = getContext().getClass().getMethod(handlerName,
|
||||
View.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
int id = getId();
|
||||
String idText = id == NO_ID ? "" : " with id '"
|
||||
+ getContext().getResources().getResourceEntryName(
|
||||
id) + "'";
|
||||
throw new IllegalStateException("Could not find a method " +
|
||||
handlerName + "(View) in the activity "
|
||||
+ getContext().getClass() + " for onClick handler"
|
||||
+ " on view " + View.this.getClass() + idText, e);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
mHandler.invoke(getContext(), View.this);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalStateException("Could not execute non "
|
||||
+ "public method of the activity", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new IllegalStateException("Could not execute "
|
||||
+ "method of the activity", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
setOnClickListener(new DeclaredOnClickListener(this, handlerName));
|
||||
}
|
||||
break;
|
||||
case R.styleable.View_overScrollMode:
|
||||
@@ -4237,6 +4208,66 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
computeOpaqueFlags();
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of OnClickListener that attempts to lazily load a
|
||||
* named click handling method from a parent or ancestor context.
|
||||
*/
|
||||
private static class DeclaredOnClickListener implements OnClickListener {
|
||||
private final View mHostView;
|
||||
private final String mMethodName;
|
||||
|
||||
private Method mMethod;
|
||||
|
||||
public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) {
|
||||
mHostView = hostView;
|
||||
mMethodName = methodName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(@NonNull View v) {
|
||||
if (mMethod == null) {
|
||||
mMethod = resolveMethod(mHostView.getContext(), mMethodName);
|
||||
}
|
||||
|
||||
try {
|
||||
mMethod.invoke(mHostView.getContext(), v);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalStateException(
|
||||
"Could not execute non-public method for android:onClick", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new IllegalStateException(
|
||||
"Could not execute method for android:onClick", e);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Method resolveMethod(@Nullable Context context, @NonNull String name) {
|
||||
while (context != null) {
|
||||
try {
|
||||
if (!context.isRestricted()) {
|
||||
return context.getClass().getMethod(mMethodName, View.class);
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
// Failed to find method, keep searching up the hierarchy.
|
||||
}
|
||||
|
||||
if (context instanceof ContextWrapper) {
|
||||
context = ((ContextWrapper) context).getBaseContext();
|
||||
} else {
|
||||
// Can't search up the hierarchy, null out and fail.
|
||||
context = null;
|
||||
}
|
||||
}
|
||||
|
||||
final int id = mHostView.getId();
|
||||
final String idText = id == NO_ID ? "" : " with id '"
|
||||
+ mHostView.getContext().getResources().getResourceEntryName(id) + "'";
|
||||
throw new IllegalStateException("Could not find method " + mMethodName
|
||||
+ "(View) in a parent or ancestor Context for android:onClick "
|
||||
+ "attribute defined on view " + mHostView.getClass() + idText);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Non-public constructor for use in testing
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user