All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.lucasr.probe.internal.ViewProxyGenerator.groovy Maven / Gradle / Ivy

There is a newer version: 0.1.3
Show newest version
/*
 * Copyright (C) 2014 Lucas Rocha
 *
 * 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.lucasr.probe.internal

import com.android.annotations.NonNull;
import com.squareup.javawriter.JavaWriter

import javax.lang.model.element.Modifier

import static javax.lang.model.element.Modifier.FINAL
import static javax.lang.model.element.Modifier.PRIVATE
import static javax.lang.model.element.Modifier.PROTECTED
import static javax.lang.model.element.Modifier.PUBLIC

class ViewProxyGenerator {
    private static final String[] PROXY_IMPORTS = [
        "android.content.Context",
        "android.graphics.Canvas",
        "android.util.AttributeSet",
        "org.lucasr.probe.Interceptor",
        "org.lucasr.probe.InterceptableView"
    ]

    private static final String FIELD_INTERCEPTOR = "mInterceptor"

    private static final String METHOD_SET_INTERCEPTOR = "setInterceptor"
    private static final String METHOD_ON_MEASURE = "onMeasure"
    private static final String METHOD_ON_LAYOUT = "onLayout"
    private static final String METHOD_DRAW = "draw"
    private static final String METHOD_ON_DRAW = "onDraw"
    private static final String METHOD_REQUEST_LAYOUT = "requestLayout"

    // setInterceptor(Interceptor)
    private static final String PARAM_INTERCEPTOR = "interceptor"

    // onMeasure(int, int)
    private static final String PARAM_WIDTH_SPEC = "widthMeasureSpec"
    private static final String PARAM_HEIGHT_SPEC = "heightMeasureSpec"

    // onLayout(boolean, int, int, int, int)
    private static final String PARAM_CHANGED = "changed"
    private static final String PARAM_LEFT = "left"
    private static final String PARAM_TOP = "top"
    private static final String PARAM_RIGHT = "right"
    private static final String PARAM_BOTTOM = "bottom"

    // draw(Canvas) and onDraw(Canvas)
    private static final String PARAM_CANVAS = "canvas"

    // setMeasuredDimension(Canvas)
    private static final String PARAM_WIDTH = "width"
    private static final String PARAM_HEIGHT = "height"

    private ViewProxyGenerator() {
    }

    static String filenameForClassName(String className) {
        return "${generateProxyName(className)}.java"
    }

    static void generate(@NonNull Writer writer, @NonNull String className,
                         @NonNull String packageName) {
        def proxyName = generateProxyName(className)

        JavaWriter javaWriter = new JavaWriter(writer)
        generatePackage(javaWriter, packageName)
        generateImports(javaWriter, className)
        generateClass(javaWriter, className, proxyName)
    }

    private static String generateProxyName(String className) {
        return "ProbeProxy\$${className.replace('.', '_')}"
    }

    private static void generatePackage(JavaWriter javaWriter, String packageName) {
        javaWriter.emitPackage(packageName)
    }

    private static void generateImports(JavaWriter javaWriter, String className) {
        javaWriter.emitImports(PROXY_IMPORTS)
        javaWriter.emitImports(className)
    }

    private static void generateClass(JavaWriter javaWriter, String className,
                                      String proxyName) {
        javaWriter.beginType(proxyName, "class", EnumSet.of(PUBLIC, FINAL),
                className, "InterceptableView")

        generateFields(javaWriter)
        generateConstructor(javaWriter)
        generateInterceptorSetter(javaWriter)
        generateOnMeasureMethod(javaWriter)
        generateOnLayoutMethod(javaWriter)
        generateDrawMethods(javaWriter)
        generateRequestLayoutMethod(javaWriter)
        generateSetMeasuredDimensionMethod(javaWriter)

        javaWriter.endType()
    }

    private static void generateFields(JavaWriter javaWriter) {
        javaWriter.emitField("Interceptor", FIELD_INTERCEPTOR, EnumSet.of(PRIVATE))
    }

    private static void generateConstructor(JavaWriter javaWriter) {
        javaWriter.beginConstructor(EnumSet.of(PUBLIC),
                "Context", "context", "AttributeSet", "attrs")
        javaWriter.emitStatement("super(context, attrs)")
        javaWriter.endConstructor()
    }

    private static void generateInterceptorSetter(JavaWriter javaWriter) {
        javaWriter.beginMethod("void", METHOD_SET_INTERCEPTOR, EnumSet.of(PUBLIC),
                "Interceptor", PARAM_INTERCEPTOR)
        javaWriter.emitStatement("%s = %s", FIELD_INTERCEPTOR, PARAM_INTERCEPTOR)
        javaWriter.endMethod()
    }

    private static String generateCommaSeparatedArgs(String... args) {
        def sb = new StringBuilder()

        for (int i = 0; i < args.length; i++) {
            if (i > 0) {
                sb.append(", ")
            }

            sb.append(args[i])
        }

        return sb.toString()
    }

    private static void generateInterceptorConditional(JavaWriter javaWriter,
                                                       String methodName,
                                                       String... args) {
        def methodArgs = generateCommaSeparatedArgs(args)

        javaWriter.beginControlFlow("if (%s != null)", FIELD_INTERCEPTOR)
        if (methodArgs.length() != 0) {
            javaWriter.emitStatement("%s.%s(this, %s)", FIELD_INTERCEPTOR, methodName, methodArgs)
        } else {
            javaWriter.emitStatement("%s.%s(this)", FIELD_INTERCEPTOR, methodName)
        }
        javaWriter.endControlFlow()
        javaWriter.beginControlFlow("else")
        javaWriter.emitStatement("super.%s(%s)", methodName, methodArgs)
        javaWriter.endControlFlow()
    }

    private static void beginOnMeasureMethod(JavaWriter javaWriter, String methodName,
                                             Modifier modifier) {
        javaWriter.beginMethod("void", methodName, EnumSet.of(modifier),
                "int", PARAM_WIDTH_SPEC, "int", PARAM_HEIGHT_SPEC)
    }

    private static void generateOnMeasureMethod(JavaWriter javaWriter) {
        beginOnMeasureMethod(javaWriter, METHOD_ON_MEASURE, PROTECTED)
        generateInterceptorConditional(javaWriter, METHOD_ON_MEASURE, PARAM_WIDTH_SPEC,
                PARAM_HEIGHT_SPEC)
        javaWriter.endMethod()

        beginOnMeasureMethod(javaWriter, "superOnMeasure", PUBLIC)
        javaWriter.emitStatement("super.%s(%s, %s)", METHOD_ON_MEASURE, PARAM_WIDTH_SPEC,
                PARAM_HEIGHT_SPEC)
        javaWriter.endMethod()
    }

    private static void beginOnLayoutMethod(JavaWriter javaWriter, String methodName,
                                            Modifier modifier) {
        javaWriter.beginMethod("void", methodName, EnumSet.of(modifier),
                "boolean", PARAM_CHANGED, "int", PARAM_LEFT, "int", PARAM_TOP,
                        "int", PARAM_RIGHT, "int", PARAM_BOTTOM)
    }

    private static void generateOnLayoutMethod(JavaWriter javaWriter) {
        beginOnLayoutMethod(javaWriter, METHOD_ON_LAYOUT, PROTECTED)
        generateInterceptorConditional(javaWriter, METHOD_ON_LAYOUT, PARAM_CHANGED,
                PARAM_LEFT, PARAM_TOP, PARAM_RIGHT, PARAM_BOTTOM)
        javaWriter.endMethod()

        beginOnLayoutMethod(javaWriter, "superOnLayout", PUBLIC)
        javaWriter.emitStatement("super.%s(%s, %s, %s, %s, %s)", METHOD_ON_LAYOUT,
                PARAM_CHANGED, PARAM_LEFT, PARAM_TOP, PARAM_RIGHT, PARAM_BOTTOM)
        javaWriter.endMethod()
    }

    private static void beginDrawMethod(JavaWriter javaWriter, String methodName,
                                        Modifier modifier) {
        javaWriter.beginMethod("void", methodName, EnumSet.of(modifier),
                "Canvas", PARAM_CANVAS)
    }

    private static void generateDrawMethods(JavaWriter javaWriter) {
        beginDrawMethod(javaWriter, METHOD_DRAW, PUBLIC)
        generateInterceptorConditional(javaWriter, METHOD_DRAW, PARAM_CANVAS)
        javaWriter.endMethod()

        beginDrawMethod(javaWriter, "superDraw", PUBLIC)
        javaWriter.emitStatement("super.%s(%s)", METHOD_DRAW, PARAM_CANVAS)
        javaWriter.endMethod()

        beginDrawMethod(javaWriter, METHOD_ON_DRAW, PROTECTED)
        generateInterceptorConditional(javaWriter, METHOD_ON_DRAW, PARAM_CANVAS)
        javaWriter.endMethod()

        beginDrawMethod(javaWriter, "superOnDraw", PUBLIC)
        javaWriter.emitStatement("super.%s(%s)", METHOD_ON_DRAW, PARAM_CANVAS)
        javaWriter.endMethod()
    }

    private static void beginRequestLayoutMethod(JavaWriter javaWriter, String methodName) {
        javaWriter.beginMethod("void", methodName, EnumSet.of(PUBLIC))
    }

    private static void generateRequestLayoutMethod(JavaWriter javaWriter) {
        beginRequestLayoutMethod(javaWriter, METHOD_REQUEST_LAYOUT)
        generateInterceptorConditional(javaWriter, METHOD_REQUEST_LAYOUT)
        javaWriter.endMethod()

        beginRequestLayoutMethod(javaWriter, "superRequestLayout")
        javaWriter.emitStatement("super.%s()", METHOD_REQUEST_LAYOUT)
        javaWriter.endMethod()
    }

    private static void generateSetMeasuredDimensionMethod(JavaWriter javaWriter) {
        javaWriter.beginMethod("void", "superSetMeasuredDimension", EnumSet.of(PUBLIC),
                "int", PARAM_WIDTH, "int", PARAM_HEIGHT)
        javaWriter.emitStatement("super.setMeasuredDimension(%s, %s)", PARAM_WIDTH,
                PARAM_HEIGHT)
        javaWriter.endMethod()
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy