<|start_filename|>barrage/src/main/java/com/android/liuzhuang/library/model/Actor.java<|end_filename|>
package com.android.liuzhuang.library.model;

import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.text.TextUtils;

import com.android.liuzhuang.library.Constants;
import com.android.liuzhuang.library.util.LogUtil;

/**
 * The actor of each item, it stores the current position and validation of item.
 * Created by liuzhuang on 16/4/8.
 */
public final class Actor {
    private BarrageDo barrageDo;
    private boolean isValid;
    private int currentPosition;
    private int realVelocity;
    private int realAcceleration;
    private Paint paint;
    private int width;
    private int height;
    private int SPACE = 100;

    public Actor(BarrageDo barrageDo, int width, int height) {
        if (barrageDo == null) {
            throw new NullPointerException("BarrageDo can not be null");
        }
        if (width <= 0 || height <= 0) {
            throw new IllegalArgumentException("width or height can not be 0");
        }
        this.barrageDo = barrageDo;
        this.width = width;
        this.height = height;
        initPositionByBoundDirection();
    }

    private void initPositionByBoundDirection() {
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(barrageDo.getTextColor());
        paint.setTextSize(barrageDo.getTextSize());
        int imageSize = 0;
        switch (barrageDo.getDirection()) {
            case Constants.RIGHT_LEFT:
            default:
                currentPosition = width;
                realVelocity = -barrageDo.getVelocity();
                realAcceleration = -barrageDo.getAcceleration();
                break;
            case Constants.TOP_DOWN:
                if (barrageDo.getImage() != null && barrageDo.getImageConfig() != null) {
                    imageSize = barrageDo.getImageConfig().height + 2 * barrageDo.getImageConfig().margin2text;
                }
                currentPosition = - 2 * (getLength(barrageDo.getText()) + imageSize);
                realVelocity = barrageDo.getVelocity();
                realAcceleration = barrageDo.getAcceleration();
                break;
            case Constants.LEFT_RIGHT:
                if (barrageDo.getImage() != null && barrageDo.getImageConfig() != null) {
                    imageSize = barrageDo.getImageConfig().width + 2 * barrageDo.getImageConfig().margin2text;
                }
                currentPosition = - 2 * (getLength(barrageDo.getText()) + imageSize);
                realVelocity = barrageDo.getVelocity();
                realAcceleration = barrageDo.getAcceleration();
                break;
            case Constants.DOWN_TOP:
                currentPosition = height;
                realVelocity = -barrageDo.getVelocity();
                realAcceleration = -barrageDo.getAcceleration();
                break;
        }
    }

    private boolean isOutOfBound() {
        boolean isOutOfBound = true;
        int imageSize = 0;
        switch (barrageDo.getDirection()) {
            case Constants.RIGHT_LEFT:
            default:
                if (barrageDo.getImage() != null && barrageDo.getImageConfig() != null) {
                    imageSize = barrageDo.getImageConfig().width + 2 * barrageDo.getImageConfig().margin2text;
                }
                if (currentPosition < - (getLength(barrageDo.getText()) + imageSize + SPACE)) {
                    isOutOfBound = true;
                } else {
                    isOutOfBound = false;
                }
                break;
            case Constants.TOP_DOWN:
                if (currentPosition > height + SPACE) {
                    isOutOfBound = true;
                } else {
                    isOutOfBound = false;
                }
                break;
            case Constants.LEFT_RIGHT:
                if (currentPosition > width + SPACE) {
                    isOutOfBound = true;
                } else {
                    isOutOfBound = false;
                }
                break;
            case Constants.DOWN_TOP:
                if (barrageDo.getImage() != null && barrageDo.getImageConfig() != null) {
                    imageSize = barrageDo.getImageConfig().height + 2 * barrageDo.getImageConfig().margin2text;
                }
                if (currentPosition < - (getLength(barrageDo.getText()) + imageSize + SPACE)) {
                    isOutOfBound = true;
                } else {
                    isOutOfBound = false;
                }
                break;
        }
        return isOutOfBound;
    }

    private int getLength(String text) {
        if (TextUtils.isEmpty(text)) {
            return 0;
        }
        return (int) paint.measureText(text);
    }

    public boolean checkValid(long duringMilliseconds) {
        if (barrageDo == null) {
            isValid = false;
        } else if ((duringMilliseconds >= barrageDo.getMillisecondFromStart() || barrageDo.getMillisecondFromStart() == -1)
                && !isOutOfBound()) {
            isValid = true;
        } else {
            isValid = false;
        }
        return isValid;
    }

    public void drawSelf(Canvas canvas) {
        if (canvas != null && barrageDo != null) {
            int dividePosition = 0;
            int nextPosition = currentPosition;

            if (barrageDo.getImage() != null && barrageDo.getImageConfig() != null &&
                    barrageDo.getImageConfig().position >= 0) {
                dividePosition = barrageDo.getImageConfig().position;
                if (barrageDo.getImageConfig().position > barrageDo.getText().length()) {
                    dividePosition = barrageDo.getText().length();
                }
                // draw first part
                nextPosition = drawText(canvas, barrageDo.getText().substring(0, dividePosition), barrageDo.getDirection(), nextPosition);
                // draw bitmap
                nextPosition = drawBitmap(canvas, nextPosition, barrageDo.getDirection());
            }

            if (dividePosition < barrageDo.getText().length()) {
                drawText(canvas, barrageDo.getText().substring(dividePosition), barrageDo.getDirection(), nextPosition);
            }

            // actor moves
            currentPosition += realVelocity;
            if (barrageDo.getAcceleration() > 0) {
                realVelocity += realAcceleration;
            }
            if (LogUtil.isShow()) {
                StringBuilder builder = new StringBuilder();
                builder.append(" text: " + barrageDo.getText())
                        .append(" currentPos: "+currentPosition)
                        .append(" realVelocity: " + realVelocity)
                        .append(" acce: " + realAcceleration);
                LogUtil.d("actor", builder.toString());
            }
        }
    }

    private int drawText(Canvas canvas, String text, int direction, int startPosition) {
        int result;
        switch (direction) {
            case Constants.RIGHT_LEFT:
            case Constants.LEFT_RIGHT:
            default:
                canvas.drawText(text, startPosition, barrageDo.getOffsetFromMargin() + barrageDo.getTextSize() / 2, paint);
                result = startPosition + getLength(text);
                break;
            case Constants.DOWN_TOP:
            case Constants.TOP_DOWN:
                canvas.save();
                canvas.rotate(90, barrageDo.getOffsetFromMargin() - barrageDo.getTextSize() / 2, startPosition);
                canvas.drawText(text, barrageDo.getOffsetFromMargin() - barrageDo.getTextSize() / 2, startPosition, paint);
                canvas.restore();
                result = startPosition + getLength(text);
                break;
        }
        return result;
    }

    private int drawBitmap(Canvas canvas, int startPosition, int direction) {
        BarrageDo.ImageConfig config = barrageDo.getImageConfig();
        Rect dest;
        startPosition += config.margin2text;
        int result;
        switch (direction) {
            case Constants.RIGHT_LEFT:
            case Constants.LEFT_RIGHT:
            default:
                dest = new Rect(startPosition, barrageDo.getOffsetFromMargin() - config.height / 2,
                        startPosition + config.width, barrageDo.getOffsetFromMargin() + config.height / 2);
                canvas.drawBitmap(barrageDo.getImage(), null, dest, null);
                result = startPosition + config.width + config.margin2text;
                break;
            case Constants.TOP_DOWN:
            case Constants.DOWN_TOP:
                dest = new Rect(barrageDo.getOffsetFromMargin() - config.width / 2, startPosition,
                        barrageDo.getOffsetFromMargin() + config.width / 2, startPosition + config.height);
                if (barrageDo.isRotateImage()) {
                    canvas.save();
                    canvas.rotate(90, barrageDo.getOffsetFromMargin(), startPosition + config.height / 2);
                    canvas.drawBitmap(barrageDo.getImage(), null, dest, null);
                    canvas.restore();
                } else {
                    canvas.drawBitmap(barrageDo.getImage(), null, dest, null);
                }
                result = startPosition + config.height + config.margin2text;
                break;
        }
        return result;
    }
}


<|start_filename|>barrage/src/main/java/com/android/liuzhuang/library/controller/Director.java<|end_filename|>
package com.android.liuzhuang.library.controller;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PorterDuff;

import com.android.liuzhuang.library.model.Actor;
import com.android.liuzhuang.library.model.BarrageDo;
import com.android.liuzhuang.library.ui.BarrageView;
import com.android.liuzhuang.library.util.LogUtil;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * The director of Barrage. This class will direct witch barrage item will show at the time.
 * Created by liuzhuang on 16/4/8.
 */
public final class Director {
    private List<Actor> allActors;
    private List<Actor> showingActors;

    private BarrageView barrageView;
    private long duringMilliseconds;
    private long startTime;

    public Director() {
        allActors = Collections.synchronizedList(new ArrayList<Actor>());
        showingActors = Collections.synchronizedList(new ArrayList<Actor>());
    }

    public void setBarrageView(BarrageView barrageView) {
        this.barrageView = barrageView;
        if (barrageView == null) {
            throw new NullPointerException("BarrageView can not be null!");
        }
    }

    public void addDataList(List<BarrageDo> dataList) {
        if (dataList != null && !dataList.isEmpty()) {
            for (int i = 0; i < dataList.size(); i++) {
                addData(dataList.get(i));
            }
        }
    }

    public void addData(BarrageDo barrageDo) {
        if (barrageDo != null) {
            Actor actor = new Actor(barrageDo, barrageView.getWidth(), barrageView.getHeight());
            allActors.add(actor);
        }
    }

    public synchronized boolean drawOnce() {
        filterActors();
        return drawOnceInner();
    }

    /**
     * select actors need to show now.
     */
    // TODO: 16/4/14 不要每次都遍历
    private void filterActors() {
        duringMilliseconds = System.currentTimeMillis() - startTime;
        showingActors.clear();
        for (int i = 0; i < allActors.size(); i++) {
            if (allActors.get(i).checkValid(duringMilliseconds)) {
                showingActors.add(allActors.get(i));
            }
        }
        LogUtil.d("showing_actor_size", showingActors.size());
    }

    private boolean drawOnceInner() {
        if (showingActors.isEmpty()) { // if no actors, then wait for a while.
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return true;
        }
        Canvas canvas = barrageView.getHolder().lockCanvas();
        if (canvas != null) {
            canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
            if (!showingActors.isEmpty()) {
                synchronized (barrageView.getHolder()) {
                    for (int i = 0; i < showingActors.size(); i++) {
                        showingActors.get(i).drawSelf(canvas);
                    }
                }
            }
            barrageView.getHolder().unlockCanvasAndPost(canvas);
            return true;
        }
        return false;
    }

    public void onStop() {
        duringMilliseconds = 0;
        clearData();
    }

    public void onStart() {
        duringMilliseconds = 0;
        startTime = System.currentTimeMillis();
    }

    public void clearData() {
        allActors.clear();
        showingActors.clear();
        barrageView.clearStage();
    }
}


<|start_filename|>barrage/src/main/java/com/android/liuzhuang/library/util/DeviceUtil.java<|end_filename|>
package com.android.liuzhuang.library.util;

import android.content.Context;
import android.content.res.Resources;
import android.util.DisplayMetrics;

/**
 * Created by liuzhuang on 16/4/8.
 */
public final class DeviceUtil {
    /**
     * This method converts dp unit to equivalent pixels, depending on device density.
     *
     * @param dp A value in dp (density independent pixels) unit. Which we need to convert into pixels
     * @param context Context to get resources and device specific display metrics
     * @return A int value to represent px equivalent to dp depending on device density
     */
    public static int dp2px(int dp, Context context){
        Resources resources = context.getResources();
        DisplayMetrics metrics = resources.getDisplayMetrics();
        int px = dp * (metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT);
        return px;
    }

    /**
     * This method converts device specific pixels to density independent pixels.
     *
     * @param px A value in px (pixels) unit. Which we need to convert into db
     * @param context Context to get resources and device specific display metrics
     * @return A int value to represent dp equivalent to px value
     */
    public static int px2dp(int px, Context context){
        Resources resources = context.getResources();
        DisplayMetrics metrics = resources.getDisplayMetrics();
        int dp = px / (metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT);
        return dp;
    }
}


<|start_filename|>barrage/src/main/java/com/android/liuzhuang/library/Barrage.java<|end_filename|>
package com.android.liuzhuang.library;

import android.content.Context;

import com.android.liuzhuang.library.controller.Director;
import com.android.liuzhuang.library.model.BarrageDo;
import com.android.liuzhuang.library.ui.BarrageView;
import com.android.liuzhuang.library.util.ContextUtil;

import java.lang.ref.WeakReference;
import java.util.List;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * The face of whole system.
 * Created by liuzhuang on 16/4/7.
 */
public final class Barrage {
    private WeakReference<Context> contextWeakReference;
    private Director director;
    private DrawRunnable drawRunnable;

    private ThreadPoolExecutor executor = new ThreadPoolExecutor(0, 2, 120, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>());


    public Barrage(Context context, BarrageView barrageView) {
        if (context == null) {
            throw new NullPointerException("Context can not be null!");
        }
        if (barrageView == null) {
            throw new NullPointerException("BarrageView can not be null!");
        }
        contextWeakReference = new WeakReference<Context>(context);
        init(barrageView);
        ContextUtil.init(context);
    }

    private void init(BarrageView barrageView) {
        this.director = new Director();
        this.director.setBarrageView(barrageView);
    }

    public void start() {
        if (drawRunnable == null) {
            drawRunnable = new DrawRunnable(director);
        }
        drawRunnable.startRunning();
        director.onStart();
        executor.execute(drawRunnable);
    }

    public void stop() {
        if (drawRunnable != null) {
            director.onStop();
            drawRunnable.stopRunning();
            if (executor != null) {
                executor.remove(drawRunnable);
            }
        }
    }

    public void addDataList(List<BarrageDo> dataList) {
        director.addDataList(dataList);
    }

    public void addData(BarrageDo barrageDo) {
        director.addData(barrageDo);
    }

    private static class DrawRunnable implements Runnable {
        Director director;
        boolean running = true;

        public DrawRunnable(Director director) {
            this.director = director;
        }

        public void startRunning() {
            running = true;
        }

        public void stopRunning() {
            running = false;
        }

        @Override
        public void run() {
            if (director != null) {
                while (running) {
                    // if failed, stop all.
                    if (!director.drawOnce()) {
                        stopRunning();
                    }
                }
            }
        }
    }
}


<|start_filename|>barrage/src/main/java/com/android/liuzhuang/library/ui/BarrageView.java<|end_filename|>
package com.android.liuzhuang.library.ui;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.util.AttributeSet;
import android.view.SurfaceView;

/**
 * BarrageView rendered by SurfaceView
 * Created by liuzhuang on 16/4/6.
 */
public class BarrageView extends SurfaceView {
    public BarrageView(Context context) {
        super(context);
        init();
    }

    public BarrageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public BarrageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        setZOrderOnTop(true);
        getHolder().setFormat(PixelFormat.TRANSPARENT);
    }

    public void clearStage() {
        Canvas canvas = getHolder().lockCanvas();
        if (canvas != null) {
            canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
            getHolder().unlockCanvasAndPost(canvas);
        }
    }
}


<|start_filename|>barrage/src/main/java/com/android/liuzhuang/library/model/BarrageDo.java<|end_filename|>
package com.android.liuzhuang.library.model;

import android.graphics.Bitmap;
import android.graphics.Color;

import com.android.liuzhuang.library.Constants;
import com.android.liuzhuang.library.util.ContextUtil;
import com.android.liuzhuang.library.util.DeviceUtil;

/**
 * The base data Object of barrage
 * Created by liuzhuang on 16/4/7.
 */
public class BarrageDo {

    private String text = "";
    private int textColor = Color.BLACK;
    private int textSize = DeviceUtil.dp2px(24, ContextUtil.getApplicationContext());
    private Bitmap image;
    private ImageConfig imageConfig;
    private int velocity;
    private int acceleration;
    private int direction = Constants.RIGHT_LEFT;

    /**The during millisecond when this item shows since starting. If -1, it will show immediately.*/
    private long millisecondFromStart;

    /**The offset from margin of this item. If horizontal margin top, if vertical margin left*/
    private int offsetFromMargin;

    /**how many times has be shown*/
    private int shownTime;

    /**rotate the image or not when direction is TOP_DOWN or DOWN_TOP*/
    private boolean rotateImage = true;

    private BarrageDo(Builder builder) {
        text = builder.text;
        textColor = builder.textColor;
        textSize = builder.textSize;
        image = builder.image;
        imageConfig = builder.imageConfig;
        velocity = builder.velocity;
        millisecondFromStart = builder.millisecondFromStart;
        offsetFromMargin = builder.offsetFromMargin;
        direction = builder.direction;
        acceleration = builder.acceleration;
        rotateImage = builder.rotateImage;
    }

    public boolean isRotateImage() {
        return rotateImage;
    }

    public int getShownTime() {
        return shownTime;
    }

    public void showOnce() {
        shownTime ++;
    }

    public String getText() {
        return text;
    }

    public int getTextColor() {
        return textColor;
    }

    public int getTextSize() {
        return textSize;
    }

    public Bitmap getImage() {
        return image;
    }

    public ImageConfig getImageConfig() {
        return imageConfig;
    }

    public int getVelocity() {
        return velocity;
    }

    public long getMillisecondFromStart() {
        return millisecondFromStart;
    }

    public int getOffsetFromMargin() {
        return offsetFromMargin;
    }

    public int getDirection() {
        return direction;
    }

    public int getAcceleration() {
        return acceleration;
    }

    public static class Builder {
        private String text = "";
        private int textColor = Color.BLACK;
        private int textSize = DeviceUtil.dp2px(32, ContextUtil.getApplicationContext());
        private Bitmap image;
        private ImageConfig imageConfig = new ImageConfig(DeviceUtil.dp2px(64, ContextUtil.getApplicationContext()),
                DeviceUtil.dp2px(64, ContextUtil.getApplicationContext()), 0, DeviceUtil.dp2px(2, ContextUtil.getApplicationContext()));
        private int velocity = DeviceUtil.dp2px(3, ContextUtil.getApplicationContext());
        private int acceleration = 0;
        /**when will the item show, if -1, it will show immediately.*/
        private long millisecondFromStart = -1;
        private int offsetFromMargin = DeviceUtil.dp2px(50, ContextUtil.getApplicationContext());
        private int direction = Constants.RIGHT_LEFT;
        /**rotate the image or not when direction is TOP_DOWN or DOWN_TOP*/
        private boolean rotateImage = true;

        public Builder setText(String text) {
            this.text = text;
            return this;
        }

        public Builder setTextColor(int textColor) {
            this.textColor = textColor;
            return this;
        }

        public Builder setTextSize(int textSize) {
            this.textSize = textSize;
            return this;
        }

        public Builder setImage(Bitmap image) {
            this.image = image;
            return this;
        }

        public Builder setImageConfig(ImageConfig imageConfig) {
            this.imageConfig = imageConfig;
            return this;
        }

        public Builder setVelocity(int velocity) {
            this.velocity = velocity;
            return this;
        }

        public Builder setMillisecondFromStart(long millisecondFromStart) {
            this.millisecondFromStart = millisecondFromStart;
            return this;
        }

        public Builder setAcceleration(int acceleration) {
            this.acceleration = acceleration;
            return this;
        }

        public Builder setRotateImage(boolean rotateImage) {
            this.rotateImage = rotateImage;
            return this;
        }

        public Builder setDirection(int direction) {
            if (direction == Constants.RIGHT_LEFT ||
                    direction == Constants.LEFT_RIGHT ||
                    direction == Constants.TOP_DOWN ||
                    direction == Constants.DOWN_TOP) {
                this.direction = direction;
            } else {
                throw new IllegalArgumentException("direction is illegal!");
            }
            return this;
        }

        public Builder setOffsetFromMargin(int offsetFromMargin) {
            this.offsetFromMargin = offsetFromMargin;
            return this;
        }

        public BarrageDo build() {
            return new BarrageDo(this);
        }
    }

    public static class ImageConfig {
        /**The width of ImageView*/
        public int width;
        /**The width of ImageView*/
        public int height;
        /**The position of ImageView relative to text, if 0, the first position, if text.length the last position*/
        public int position;

        public int margin2text;

        public ImageConfig(int width, int height, int position, int margin2text) {
            this.width = width;
            this.height = height;
            this.position = position;
            this.margin2text = margin2text;
        }
    }
}


<|start_filename|>barrage/src/main/java/com/android/liuzhuang/library/util/ContextUtil.java<|end_filename|>
package com.android.liuzhuang.library.util;

import android.app.Application;
import android.content.Context;

/**
 * Created by liuzhuang on 16/4/15.
 */
public class ContextUtil {
    private static Context applicationContext;

    public static void init(Context context) {
        applicationContext = context.getApplicationContext();
    }

    public static Context getApplicationContext() {
        if (applicationContext == null) {
            throw new NullPointerException("applicationContext can not be null. You should init first.");
        }
        return applicationContext;
    }
}


<|start_filename|>barrage/src/main/java/com/android/liuzhuang/library/util/LogUtil.java<|end_filename|>
package com.android.liuzhuang.library.util;

import android.text.TextUtils;
import android.util.Log;

public class LogUtil {

    public static boolean isShow(){
        return false;
    }

    public static boolean isShow(Object msg){
        return isShow() && msg != null && !TextUtils.isEmpty(msg.toString());
    }

    public static void d(String tag, Object msg) {
        if (isShow(msg)) {
            Log.d(tag,msg.toString());
        }
    }

    public static void i(String tag, Object msg) {
        if (isShow(msg)) {
            Log.i(tag, msg.toString());
        }
    }

    public static void w(String tag, Object msg) {
        if (isShow(msg)) {
            Log.w(tag, msg.toString());
        }
    }

    public static void e(String tag, Object msg) {
        if (isShow(msg)) {
            Log.e(tag, msg.toString());
        }
    }
}


<|start_filename|>barrage/src/main/java/com/android/liuzhuang/library/Constants.java<|end_filename|>
package com.android.liuzhuang.library;

/**
 * Created by liuzhuang on 16/4/8.
 */
public final class Constants {
    public static final int LEFT_RIGHT = 0;
    public static final int RIGHT_LEFT = 1;
    public static final int TOP_DOWN = 2;
    public static final int DOWN_TOP = 3;
}


<|start_filename|>app/src/main/java/com/android/liuzhuang/barrage/MainActivity.java<|end_filename|>
package com.android.liuzhuang.barrage;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;

import com.android.liuzhuang.library.Barrage;
import com.android.liuzhuang.library.Constants;
import com.android.liuzhuang.library.model.BarrageDo;
import com.android.liuzhuang.library.ui.BarrageView;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    Barrage barrage;
    int[] colors = new int[]{
            Color.parseColor("#F44336"),
            Color.parseColor("#E91E63"),
            Color.parseColor("#9C27B0"),
            Color.parseColor("#EA80FC"),
            Color.parseColor("#FF80AB"),
            Color.parseColor("#673AB7"),
            Color.parseColor("#311B92"),
            Color.parseColor("#00BCD4"),
            Color.parseColor("#009688"),
            Color.parseColor("#4CAF50")
    };
    Bitmap coinBitmap;
    Bitmap balloonBitmap;
    Random random = new Random();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        barrage = new Barrage(this, (BarrageView) findViewById(R.id.barrage));
        coinBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.coin);
        balloonBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.balloon);
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.right_left) {
            createByDirection(Constants.RIGHT_LEFT);
        } else if (v.getId() == R.id.left_right) {
            createByDirection(Constants.LEFT_RIGHT);
        } else if (v.getId() == R.id.top_down) {
            createByDirection(Constants.TOP_DOWN);
        } else if (v.getId() == R.id.down_top) {
            createByDirection(Constants.DOWN_TOP);
        } else if (v.getId() == R.id.stop) {
            barrage.stop();
        } else if (v.getId() == R.id.create) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    barrage.addData(new BarrageDo.Builder()
                            .setText("I am a new text")
                            .setTextColor(Color.BLACK)
                            .setTextSize(70)
                            .setOffsetFromMargin(random.nextInt(500))
                            .setAcceleration(0)
                            .setVelocity(10)
                            .setImage(coinBitmap)
                            .setImageConfig(new BarrageDo.ImageConfig(200, 200, random.nextInt(15), 30))
                            .setRotateImage(true)
                            .setDirection(random.nextInt(4))
                            .setMillisecondFromStart(-1)
                            .build());
                }
            }).start();
        } else if (v.getId() == R.id.coins) {
            List<BarrageDo> data = new ArrayList<>();
            for (int i = 0; i < 50; i++) {
                int size = 200 + random.nextInt(100);
                data.add(new BarrageDo.Builder()
                        .setMillisecondFromStart(random.nextInt(5000))
                        .setOffsetFromMargin(random.nextInt(1000))
                        .setVelocity(random.nextInt(5))
                        .setImage(coinBitmap)
                        .setImageConfig(new BarrageDo.ImageConfig(size, size, 0, 0))
                        .setRotateImage(false)
                        .setAcceleration(random.nextInt(5) + 1)
                        .setDirection(Constants.TOP_DOWN)
                        .build());
            }
            barrage.addDataList(data);
            barrage.start();
        } else if (v.getId() == R.id.balloons) {
            List<BarrageDo> data = new ArrayList<>();
            for (int i = 0; i < 50; i++) {
                int size = 200 + random.nextInt(100);
                data.add(new BarrageDo.Builder()
                        .setMillisecondFromStart(random.nextInt(5000))
                        .setOffsetFromMargin(random.nextInt(1000))
                        .setVelocity(random.nextInt(30) + 20)
                        .setImage(balloonBitmap)
                        .setImageConfig(new BarrageDo.ImageConfig(size, size, 0, 0))
                        .setRotateImage(false)
                        .setAcceleration(0)
                        .setDirection(Constants.DOWN_TOP)
                        .build());
            }
            barrage.addDataList(data);
            barrage.start();
        }

    }

    private void createByDirection(int direction) {
        barrage.stop();
        List<BarrageDo> data = new ArrayList<>();
        for (int i = 0; i < 50; i++) {
            data.add(new BarrageDo.Builder()
                    .setText("text" + i)
                    .setTextColor(colors[random.nextInt(10)])
                    .setMillisecondFromStart(1000*random.nextInt(5))
                    .setTextSize(50 + random.nextInt(10))
                    .setOffsetFromMargin(100 + random.nextInt(1000))
                    .setVelocity(random.nextInt(20) + 10)
                    .setAcceleration(0)
                    .setDirection(direction)
                    .build());
        }
        barrage.addDataList(data);
        barrage.start();
    }
}
