1d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount/* 2d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * Copyright (C) 2014 The Android Open Source Project 3d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * 4d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * Licensed under the Apache License, Version 2.0 (the "License"); 5d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * you may not use this file except in compliance with the License. 6d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * You may obtain a copy of the License at 7d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * 8d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * http://www.apache.org/licenses/LICENSE-2.0 9d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * 10d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * Unless required by applicable law or agreed to in writing, software 11d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * distributed under the License is distributed on an "AS IS" BASIS, 12d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * See the License for the specific language governing permissions and 14d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * limitations under the License. 15d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount */ 16d6107a3170df61d9e776fcd5666acfc9135c6f16George Mountpackage android.transition; 17d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount 18d6107a3170df61d9e776fcd5666acfc9135c6f16George Mountimport android.graphics.Rect; 19d6107a3170df61d9e776fcd5666acfc9135c6f16George Mountimport android.util.FloatMath; 20d6107a3170df61d9e776fcd5666acfc9135c6f16George Mountimport android.util.Log; 21d6107a3170df61d9e776fcd5666acfc9135c6f16George Mountimport android.view.View; 22d6107a3170df61d9e776fcd5666acfc9135c6f16George Mountimport android.view.ViewGroup; 23d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount 24d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount/** 25d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * A propagation that varies with the distance to the epicenter of the Transition 26d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * or center of the scene if no epicenter exists. When a View is visible in the 27d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * start of the transition, Views farther from the epicenter will transition 28d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * sooner than Views closer to the epicenter. When a View is not in the start 29d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * of the transition or is not visible at the start of the transition, it will 30d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * transition sooner when closer to the epicenter and later when farther from 31d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * the epicenter. This is the default TransitionPropagation used with 32d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * {@link android.transition.Explode}. 33d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount */ 34d6107a3170df61d9e776fcd5666acfc9135c6f16George Mountpublic class CircularPropagation extends VisibilityPropagation { 35d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount private static final String TAG = "CircularPropagation"; 36d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount 37265f209d551092a08f2969ec5fed94292d7741b6George Mount private float mPropagationSpeed = 3.0f; 38d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount 39d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount /** 40d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * Sets the speed at which transition propagation happens, relative to the duration of the 41d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * Transition. A <code>propagationSpeed</code> of 1 means that a View centered farthest from 42d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * the epicenter and View centered at the epicenter will have a difference 43d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * in start delay of approximately the duration of the Transition. A speed of 2 means the 44d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * start delay difference will be approximately half of the duration of the transition. A 45d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * value of 0 is illegal, but negative values will invert the propagation. 46d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * 47d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * @param propagationSpeed The speed at which propagation occurs, relative to the duration 48d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * of the transition. A speed of 4 means it works 4 times as fast 49d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * as the duration of the transition. May not be 0. 50d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount */ 51d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount public void setPropagationSpeed(float propagationSpeed) { 52d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount if (propagationSpeed == 0) { 53d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount throw new IllegalArgumentException("propagationSpeed may not be 0"); 54d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount } 55d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount mPropagationSpeed = propagationSpeed; 56d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount } 57d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount 58d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount @Override 59d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount public long getStartDelay(ViewGroup sceneRoot, Transition transition, 60d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount TransitionValues startValues, TransitionValues endValues) { 61d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount if (startValues == null && endValues == null) { 62d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount return 0; 63d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount } 64d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount int directionMultiplier = 1; 65d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount TransitionValues positionValues; 66d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount if (endValues == null || getViewVisibility(startValues) == View.VISIBLE) { 67d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount positionValues = startValues; 68d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount directionMultiplier = -1; 69d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount } else { 70d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount positionValues = endValues; 71d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount } 72d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount 73d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount int viewCenterX = getViewX(positionValues); 74d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount int viewCenterY = getViewY(positionValues); 75d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount 76d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount Rect epicenter = transition.getEpicenter(); 77d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount int epicenterX; 78d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount int epicenterY; 79d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount if (epicenter != null) { 80d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount epicenterX = epicenter.centerX(); 81d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount epicenterY = epicenter.centerY(); 82d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount } else { 83d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount int[] loc = new int[2]; 84d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount sceneRoot.getLocationOnScreen(loc); 85d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount epicenterX = Math.round(loc[0] + (sceneRoot.getWidth() / 2) 86d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount + sceneRoot.getTranslationX()); 87d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount epicenterY = Math.round(loc[1] + (sceneRoot.getHeight() / 2) 88d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount + sceneRoot.getTranslationY()); 89d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount } 90d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount float distance = distance(viewCenterX, viewCenterY, epicenterX, epicenterY); 91d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount float maxDistance = distance(0, 0, sceneRoot.getWidth(), sceneRoot.getHeight()); 92d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount float distanceFraction = distance/maxDistance; 93d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount 94265f209d551092a08f2969ec5fed94292d7741b6George Mount long duration = transition.getDuration(); 95265f209d551092a08f2969ec5fed94292d7741b6George Mount if (duration < 0) { 96265f209d551092a08f2969ec5fed94292d7741b6George Mount duration = 300; 97265f209d551092a08f2969ec5fed94292d7741b6George Mount } 98265f209d551092a08f2969ec5fed94292d7741b6George Mount 99265f209d551092a08f2969ec5fed94292d7741b6George Mount return Math.round(duration * directionMultiplier / mPropagationSpeed * distanceFraction); 100d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount } 101d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount 102d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount private static float distance(float x1, float y1, float x2, float y2) { 103d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount float x = x2 - x1; 104d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount float y = y2 - y1; 105d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount return FloatMath.sqrt((x * x) + (y * y)); 106d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount } 107d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount} 108