/* * Copyright (C) 2016 Google Inc. All Rights Reserved. * * 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 com.google.android.apps.santatracker.presentquest.ui; import android.content.Context; import android.os.Handler; import android.support.v4.content.ContextCompat; import com.google.android.gms.maps.model.Circle; import com.google.android.apps.santatracker.presentquest.MapsActivity; import com.google.android.apps.santatracker.presentquest.R; /** * Animate a {@link Circle} that pulses and fades. */ public class CirclePulseAnimator { private static final int STEP_TIME_MS = 32; private static final double MIN_ACTION_RADIUS = 10.0f; private static final double ACTION_RADIUS_STEP = 1.2f; private final double MAX_ACTION_RADIUS; private static final int ACTION_OPACITY_STEP = 2; private Context mContext; private Circle mCircle; public CirclePulseAnimator(Context context, Circle circle, int reachableRadius) { mContext = context; mCircle = circle; // Multiply by 1.2 so that it appears to "reach" all reachable icons MAX_ACTION_RADIUS = reachableRadius * 1.2f; } private Handler mHorizonAnimationHandler = new Handler(); private Runnable mPulseHorizonsRunnable = new Runnable() { @Override public void run() { // Calculate new radius double newRadius = mCircle.getRadius() + ACTION_RADIUS_STEP; // Calculate new colors (change opacity) int strokeColor = mCircle.getStrokeColor(); int newStrokeOpacity = Math.max(getOpacity(strokeColor) - ACTION_OPACITY_STEP, 0); int newStrokeColor = setOpacity(strokeColor, newStrokeOpacity); int fillColor = mCircle.getFillColor(); int newFillOpacity = Math.max(getOpacity(fillColor) - ACTION_OPACITY_STEP, 0); int newFillColor = setOpacity(fillColor, newFillOpacity); if (newRadius <= MAX_ACTION_RADIUS) { // Set to new values mCircle.setRadius(newRadius); mCircle.setStrokeColor(newStrokeColor); mCircle.setFillColor(newFillColor); } else { // Reset mCircle.setRadius(MIN_ACTION_RADIUS); mCircle.setStrokeColor(ContextCompat.getColor(mContext, R.color.action_horizon_stroke)); mCircle.setFillColor(ContextCompat.getColor(mContext, R.color.action_horizon_fill)); } // Reschedule mHorizonAnimationHandler.postDelayed(this, STEP_TIME_MS); } }; public void start() { mHorizonAnimationHandler.removeCallbacksAndMessages(null); mHorizonAnimationHandler.post(mPulseHorizonsRunnable); } public void stop() { mHorizonAnimationHandler.removeCallbacksAndMessages(null); } /** * Change the opacity of a hexadecimal color. * @param color the color. * @param opacity a new opacity value, 0 to 255. * @return the new color. */ private int setOpacity(int color, int opacity) { // Remove opacity int currentOpacity = ((color >> 24) & 0xFF) << 24; color = (color - currentOpacity); // Add new opacity color = color + (opacity << 24); return color; } /** * Get the current opacity of a hexadecimal color. * @param color the color. * @return the opacity, 0 to 255. */ private int getOpacity(int color) { return (color >> 24) & 0xFF; } }