blob: 9393792f67c9185f00ff20e5ec5a127fd967c71e [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.android.uipreview;
import org.jetbrains.org.objectweb.asm.*;
import static org.jetbrains.org.objectweb.asm.Opcodes.*;
/**
* Some constants that are needed to render the RecyclerView correctly.
*/
@SuppressWarnings("SpellCheckingInspection")
public class RecyclerViewHelper {
public static final String PACKAGE_NAME = "com.android.layoutlib.bridge.android.support";
public static final String CN_CUSTOM_ADAPTER = PACKAGE_NAME + ".Adapter";
public static final String CN_CUSTOM_VIEW_HOLDER = PACKAGE_NAME + ".Adapter$ViewHolder";
public static final String CN_RECYCLER_VIEW = "android.support.v7.widget.RecyclerView";
public static final String CN_RV_ADAPTER = CN_RECYCLER_VIEW + "$Adapter";
public static final String CN_RV_LAYOUT_MANAGER = CN_RECYCLER_VIEW + "$LayoutManager";
// Lazily initialized.
private static byte[] ourAdapterClass;
private static byte[] ourViewHolder;
public static byte[] getAdapterClass() {
if (ourAdapterClass == null) {
ourAdapterClass = getAdapterClassDump();
}
return ourAdapterClass;
}
public static byte[] getViewHolder() {
if (ourViewHolder == null) {
ourViewHolder = getViewHolderDump();
}
return ourViewHolder;
}
// See comment at the end of the file for how this method was generated.
@SuppressWarnings("unused") // Generated code.
private static byte[] getAdapterClassDump() {
ClassWriter cw = new ClassWriter(0);
FieldVisitor fv;
MethodVisitor mv;
AnnotationVisitor av0;
cw.visit(V1_6, ACC_PUBLIC + ACC_SUPER, "com/android/layoutlib/bridge/android/support/Adapter",
"Landroid/support/v7/widget/RecyclerView$Adapter<Landroid/support/v7/widget/RecyclerView$ViewHolder;>;",
"android/support/v7/widget/RecyclerView$Adapter", null);
cw.visitInnerClass("com/android/layoutlib/bridge/android/support/Adapter$ViewHolder",
"com/android/layoutlib/bridge/android/support/Adapter", "ViewHolder", ACC_PRIVATE + ACC_STATIC);
cw.visitInnerClass("android/support/v7/widget/RecyclerView$ViewHolder", "android/support/v7/widget/RecyclerView", "ViewHolder",
ACC_PUBLIC + ACC_STATIC + ACC_ABSTRACT);
cw.visitInnerClass("android/support/v7/widget/RecyclerView$Adapter", "android/support/v7/widget/RecyclerView", "Adapter",
ACC_PUBLIC + ACC_STATIC + ACC_ABSTRACT);
{
fv = cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC, "ITEM_COUNT", "I", null, new Integer(10));
fv.visitEnd();
}
{
fv = cw.visitField(ACC_PRIVATE, "mId", "I", null, null);
fv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "android/support/v7/widget/RecyclerView$Adapter", "<init>", "()V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
{
mv =
cw.visitMethod(ACC_PUBLIC, "onCreateViewHolder", "(Landroid/view/ViewGroup;I)Landroid/support/v7/widget/RecyclerView$ViewHolder;",
null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, "com/android/layoutlib/bridge/android/support/Adapter", "mId", "I");
Label l0 = new Label();
mv.visitJumpInsn(IFLE, l0);
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKEVIRTUAL, "android/view/ViewGroup", "getContext", "()Landroid/content/Context;", false);
mv.visitMethodInsn(INVOKESTATIC, "android/view/LayoutInflater", "from", "(Landroid/content/Context;)Landroid/view/LayoutInflater;",
false);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, "com/android/layoutlib/bridge/android/support/Adapter", "mId", "I");
mv.visitVarInsn(ALOAD, 1);
mv.visitInsn(ICONST_0);
mv.visitMethodInsn(INVOKEVIRTUAL, "android/view/LayoutInflater", "inflate", "(ILandroid/view/ViewGroup;Z)Landroid/view/View;", false);
mv.visitVarInsn(ASTORE, 3);
Label l1 = new Label();
mv.visitJumpInsn(GOTO, l1);
mv.visitLabel(l0);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
mv.visitTypeInsn(NEW, "android/widget/TextView");
mv.visitInsn(DUP);
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKEVIRTUAL, "android/view/ViewGroup", "getContext", "()Landroid/content/Context;", false);
mv.visitMethodInsn(INVOKESPECIAL, "android/widget/TextView", "<init>", "(Landroid/content/Context;)V", false);
mv.visitVarInsn(ASTORE, 3);
mv.visitLabel(l1);
mv.visitFrame(Opcodes.F_APPEND,1, new Object[] {"android/view/View"}, 0, null);
mv.visitTypeInsn(NEW, "com/android/layoutlib/bridge/android/support/Adapter$ViewHolder");
mv.visitInsn(DUP);
mv.visitVarInsn(ALOAD, 3);
mv.visitMethodInsn(INVOKESPECIAL, "com/android/layoutlib/bridge/android/support/Adapter$ViewHolder", "<init>",
"(Landroid/view/View;)V", false);
mv.visitInsn(ARETURN);
mv.visitMaxs(4, 4);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC, "onBindViewHolder", "(Landroid/support/v7/widget/RecyclerView$ViewHolder;I)V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 1);
mv.visitFieldInsn(GETFIELD, "android/support/v7/widget/RecyclerView$ViewHolder", "itemView", "Landroid/view/View;");
mv.visitVarInsn(ASTORE, 3);
mv.visitTypeInsn(NEW, "java/util/ArrayList");
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, "java/util/ArrayList", "<init>", "()V", false);
mv.visitVarInsn(ASTORE, 4);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 3);
mv.visitVarInsn(ALOAD, 4);
mv.visitTypeInsn(NEW, "java/util/LinkedList");
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, "java/util/LinkedList", "<init>", "()V", false);
mv.visitMethodInsn(INVOKESPECIAL, "com/android/layoutlib/bridge/android/support/Adapter", "findTextViews",
"(Landroid/view/View;Ljava/util/ArrayList;Ljava/util/LinkedList;)V", false);
mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V", false);
mv.visitLdcInsn("Item ");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
mv.visitVarInsn(ILOAD, 2);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(I)Ljava/lang/StringBuilder;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false);
mv.visitVarInsn(ASTORE, 5);
mv.visitInsn(ICONST_0);
mv.visitVarInsn(ISTORE, 6);
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitFrame(Opcodes.F_FULL, 7, new Object[]{"com/android/layoutlib/bridge/android/support/Adapter",
"android/support/v7/widget/RecyclerView$ViewHolder", Opcodes.INTEGER, "android/view/View", "java/util/ArrayList",
"java/lang/String", Opcodes.INTEGER}, 0, new Object[]{});
mv.visitVarInsn(ILOAD, 6);
mv.visitVarInsn(ALOAD, 4);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/ArrayList", "size", "()I", false);
Label l1 = new Label();
mv.visitJumpInsn(IF_ICMPGE, l1);
mv.visitVarInsn(ALOAD, 4);
mv.visitVarInsn(ILOAD, 6);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/ArrayList", "get", "(I)Ljava/lang/Object;", false);
mv.visitTypeInsn(CHECKCAST, "android/widget/TextView");
mv.visitVarInsn(ALOAD, 5);
mv.visitMethodInsn(INVOKEVIRTUAL, "android/widget/TextView", "setText", "(Ljava/lang/CharSequence;)V", false);
mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V", false);
mv.visitLdcInsn("Sub");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
mv.visitVarInsn(ALOAD, 5);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false);
mv.visitVarInsn(ASTORE, 5);
mv.visitIincInsn(6, 1);
mv.visitJumpInsn(GOTO, l0);
mv.visitLabel(l1);
mv.visitFrame(Opcodes.F_CHOP, 1, null, 0, null);
mv.visitInsn(RETURN);
mv.visitMaxs(5, 7);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC, "getItemCount", "()I", null, null);
mv.visitCode();
mv.visitIntInsn(BIPUSH, 10);
mv.visitInsn(IRETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC, "setLayoutId", "(I)V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ILOAD, 1);
mv.visitFieldInsn(PUTFIELD, "com/android/layoutlib/bridge/android/support/Adapter", "mId", "I");
mv.visitInsn(RETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PRIVATE, "findTextViews", "(Landroid/view/View;Ljava/util/ArrayList;Ljava/util/LinkedList;)V",
"(Landroid/view/View;Ljava/util/ArrayList<Landroid/widget/TextView;>;Ljava/util/LinkedList<Landroid/view/View;>;)V",
null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(INSTANCEOF, "android/widget/TextView");
Label l0 = new Label();
mv.visitJumpInsn(IFEQ, l0);
mv.visitVarInsn(ALOAD, 2);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, "android/widget/TextView");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/ArrayList", "add", "(Ljava/lang/Object;)Z", false);
mv.visitInsn(POP);
Label l1 = new Label();
mv.visitJumpInsn(GOTO, l1);
mv.visitLabel(l0);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(INSTANCEOF, "android/view/ViewGroup");
mv.visitJumpInsn(IFEQ, l1);
mv.visitInsn(ICONST_0);
mv.visitVarInsn(ISTORE, 4);
Label l2 = new Label();
mv.visitLabel(l2);
mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, 0, null);
mv.visitVarInsn(ILOAD, 4);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, "android/view/ViewGroup");
mv.visitMethodInsn(INVOKEVIRTUAL, "android/view/ViewGroup", "getChildCount", "()I", false);
mv.visitJumpInsn(IF_ICMPGE, l1);
mv.visitVarInsn(ALOAD, 3);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, "android/view/ViewGroup");
mv.visitVarInsn(ILOAD, 4);
mv.visitMethodInsn(INVOKEVIRTUAL, "android/view/ViewGroup", "getChildAt", "(I)Landroid/view/View;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/LinkedList", "add", "(Ljava/lang/Object;)V", false);
mv.visitIincInsn(4, 1);
mv.visitJumpInsn(GOTO, l2);
mv.visitLabel(l1);
mv.visitFrame(Opcodes.F_CHOP, 1, null, 0, null);
mv.visitVarInsn(ALOAD, 3);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/LinkedList", "isEmpty", "()Z", false);
Label l3 = new Label();
mv.visitJumpInsn(IFNE, l3);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 3);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/LinkedList", "remove", "()Ljava/lang/Object;", false);
mv.visitTypeInsn(CHECKCAST, "android/view/View");
mv.visitVarInsn(ALOAD, 2);
mv.visitVarInsn(ALOAD, 3);
mv.visitMethodInsn(INVOKESPECIAL, "com/android/layoutlib/bridge/android/support/Adapter", "findTextViews",
"(Landroid/view/View;Ljava/util/ArrayList;Ljava/util/LinkedList;)V", false);
mv.visitLabel(l3);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
mv.visitInsn(RETURN);
mv.visitMaxs(4, 5);
mv.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
}
// See comment at the end of the file for how this method was generated.
@SuppressWarnings("unused") // Generated code.
private static byte[] getViewHolderDump() {
ClassWriter cw = new ClassWriter(0);
FieldVisitor fv;
MethodVisitor mv;
AnnotationVisitor av0;
cw.visit(V1_6, ACC_SUPER, "com/android/layoutlib/bridge/android/support/Adapter$ViewHolder", null,
"android/support/v7/widget/RecyclerView$ViewHolder", null);
cw.visitInnerClass("com/android/layoutlib/bridge/android/support/Adapter$ViewHolder",
"com/android/layoutlib/bridge/android/support/Adapter", "ViewHolder", ACC_PRIVATE + ACC_STATIC);
cw.visitInnerClass("android/support/v7/widget/RecyclerView$ViewHolder", "android/support/v7/widget/RecyclerView", "ViewHolder",
ACC_PUBLIC + ACC_STATIC + ACC_ABSTRACT);
{
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "(Landroid/view/View;)V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKESPECIAL, "android/support/v7/widget/RecyclerView$ViewHolder", "<init>", "(Landroid/view/View;)V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
}
// The above dump methods were obtained by compiling the following class and running ASMifier on both Adapter and Adapter$ViewHolder.
// $ echo com.android.layoutlib.bridge.android.support.Adapter com.android.layoutlib.bridge.android.support.Adapter\$ViewHolder \
// | xargs -n 1 java -classpath asm-debug-all-5.0.2.jar:. org.objectweb.asm.util.ASMifier
//
//package com.android.layoutlib.bridge.android.support;
//
//import android.support.v7.widget.RecyclerView;
//import android.view.LayoutInflater;
//import android.view.View;
//import android.view.ViewGroup;
//import android.widget.TextView;
//
//import java.util.ArrayList;
//import java.util.LinkedList;
//
//public class Adapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
//
// private static final int ITEM_COUNT = 10;
// private int mId;
//
// @Override
// public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent,
// int viewType) {
// View view;
// if (mId > 0) {
// view = LayoutInflater.from(parent.getContext()).inflate(mId, parent, false);
// } else {
// view = new TextView(parent.getContext());
// }
// return new ViewHolder(view);
// }
//
// @Override
// public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
// View view = holder.itemView;
// ArrayList<TextView> textViews = new ArrayList<TextView>();
// findTextViews(view, textViews, new LinkedList<View>());
// String text = "Item " + position;
// for (int i = 0; i < textViews.size(); i++) {
// textViews.get(i).setText(text);
// text = "Sub" + text;
// }
// }
//
// @Override
// public int getItemCount() {
// return ITEM_COUNT;
// }
//
// public void setLayoutId(int id) {
// mId = id;
// }
//
// private void findTextViews(View view, ArrayList<TextView> out, LinkedList<View> queue) {
// if (view instanceof TextView) {
// out.add((TextView) view);
// } else if (view instanceof ViewGroup) {
// for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
// queue.add(((ViewGroup) view).getChildAt(i));
// }
// }
// if (!queue.isEmpty()) {
// findTextViews(queue.remove(), out, queue);
// }
// }
//
// private static class ViewHolder extends RecyclerView.ViewHolder {
// public ViewHolder(View itemView) {
// super(itemView);
// }
// }
//}
}