me.oriley.vista.VistaEdgeEffectHelper.java Source code

Java tutorial

Introduction

Here is the source code for me.oriley.vista.VistaEdgeEffectHelper.java

Source

/*
 * Copyright (C) 2016 Kane O'Riley
 *
 * 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 me.oriley.vista;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.support.annotation.CheckResult;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.widget.EdgeEffectCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

@SuppressWarnings("WeakerAccess")
public final class VistaEdgeEffectHelper {

    @Nullable
    private static final Field EDGE_EFFECT_COMPAT_DELEGATE;

    static {
        EDGE_EFFECT_COMPAT_DELEGATE = getField(EdgeEffectCompat.class, "mEdgeEffect");
    }

    private static final String TAG = VistaEdgeEffectHelper.class.getSimpleName();
    private static final float DEFAULT_THICKNESS_SCALE = 0.5f;
    private static final float DEFAULT_EDGE_SCALE = 0.5f;

    public enum Side {
        LEFT, RIGHT, TOP, BOTTOM
    }

    @NonNull
    private final VistaEdgeEffectHost mHost;

    @NonNull
    private final HashMap<Side, VistaEdgeEffect> mEdges = new HashMap<>();

    private final float mThicknessScale;

    private final float mEdgeScale;

    @ColorInt
    private final int mInitialColor;

    private final boolean mDisableHotspot;

    public VistaEdgeEffectHelper(@NonNull VistaEdgeEffectHost customEdgeEffectHost, @NonNull Context context,
            @Nullable AttributeSet attrs) {
        mHost = customEdgeEffectHost;

        float thicknessScale = DEFAULT_THICKNESS_SCALE;
        float edgeScale = DEFAULT_EDGE_SCALE;
        boolean disableHotspot = false;

        boolean customColor = false;
        int initialColor = Color.WHITE;

        if (attrs != null) {
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.VistaView);
            if (a.hasValue(R.styleable.VistaView_vistaColor)) {
                customColor = true;
                initialColor = a.getColor(R.styleable.VistaView_vistaColor, initialColor);
            }
            disableHotspot = a.getBoolean(R.styleable.VistaView_vistaDisableHotspot, false);
            thicknessScale = a.getFloat(R.styleable.VistaView_vistaThicknessScale, DEFAULT_THICKNESS_SCALE);
            edgeScale = a.getFloat(R.styleable.VistaView_vistaEdgeScale, DEFAULT_EDGE_SCALE);
            a.recycle();
        }

        // Couldn't get from attribute, try app compat accent color
        if (!customColor) {
            TypedValue typedValue = new TypedValue();
            TypedArray a = context.obtainStyledAttributes(typedValue.data, new int[] { R.attr.colorAccent });
            initialColor = a.getColor(0, Color.WHITE);
            a.recycle();
        }

        mInitialColor = initialColor;
        mDisableHotspot = disableHotspot;
        mThicknessScale = thicknessScale;
        mEdgeScale = edgeScale;
    }

    public void refreshEdges(@NonNull Map<Side, Field> fields, boolean isCompat) {
        Context context = mHost.getContext();
        for (Map.Entry<Side, Field> entry : fields.entrySet()) {
            VistaEdgeEffect edgeEffect = mEdges.get(entry.getKey());
            if (edgeEffect == null) {
                edgeEffect = new VistaEdgeEffect(context);
                edgeEffect.updateValues(mInitialColor, mThicknessScale, mEdgeScale, mDisableHotspot);
            }

            if (replaceEdgeEffect(context, entry.getValue(), edgeEffect, isCompat)) {
                mEdges.put(entry.getKey(), edgeEffect);
            }
        }
    }

    @CheckResult
    private boolean replaceEdgeEffect(@NonNull Context context, @NonNull Field field,
            @NonNull VistaEdgeEffect edgeEffect, boolean isCompat) {
        if (isCompat) {
            return replaceEdgeEffectCompat(context, field, edgeEffect);
        } else {
            return replaceEdgeEffect(field, edgeEffect);
        }
    }

    @CheckResult
    private boolean replaceEdgeEffectCompat(@NonNull Context context, @NonNull Field field,
            @NonNull VistaEdgeEffect edgeEffect) {
        if (EDGE_EFFECT_COMPAT_DELEGATE == null) {
            Log.e(TAG, "Unable to find edge effect delegate field");
            return false;
        }

        try {
            EdgeEffectCompat edgeEffectCompat = new EdgeEffectCompat(context);
            EDGE_EFFECT_COMPAT_DELEGATE.set(edgeEffectCompat, edgeEffect);

            field.set(mHost, edgeEffectCompat);
            edgeEffectCompat.setSize(mHost.getMeasuredWidth(), mHost.getMeasuredHeight());
            Log.d(TAG, "Replaced edge effect " + field + " in " + mHost);
            return true;
        } catch (Exception e) {
            Log.e(TAG, "Error replacing edge effect " + field + " in " + mHost);
            e.printStackTrace();
            return false;
        }
    }

    @CheckResult
    private boolean replaceEdgeEffect(@NonNull Field field, @NonNull VistaEdgeEffect edgeEffect) {
        try {
            field.set(mHost, edgeEffect);
            edgeEffect.setSize(mHost.getMeasuredWidth(), mHost.getMeasuredHeight());
            Log.d(TAG, "Replaced edge effect " + field + " in " + mHost);
            return true;
        } catch (Exception e) {
            Log.e(TAG, "Error replacing edge effect " + field + " in " + mHost);
            e.printStackTrace();
            return false;
        }
    }

    public static void addEdgeEffectFieldIfFound(@NonNull Map<Side, Field> map, @NonNull Class viewClass,
            @NonNull Side side, @NonNull String fieldName) {
        Field edge = getField(viewClass, fieldName);
        if (edge != null) {
            map.put(side, edge);
        }
    }

    @Nullable
    private static Field getField(@NonNull Class<?> clazz, @NonNull String name) {
        try {
            Field field = clazz.getDeclaredField(name);
            if (field == null) {
                return null;
            }
            field.setAccessible(true);
            return field;
        } catch (Throwable e) {
            Log.e(TAG, "Failed to get field " + name + " from class " + clazz.getCanonicalName(), e);
            return null;
        }
    }

    public void setEdgeEffectColors(@ColorInt int color) {
        for (Side side : Side.values()) {
            setEdgeEffectColor(side, color);
        }
    }

    public void setEdgeEffectColor(@NonNull Side side, @ColorInt int color) {
        VistaEdgeEffect edgeEffect = mEdges.get(side);
        if (edgeEffect != null) {
            edgeEffect.setColor(color);
        }
    }
}