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.view.View; 20d6107a3170df61d9e776fcd5666acfc9135c6f16George Mountimport android.view.ViewGroup; 21d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount 22d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount/** 23d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * A propagation that varies with the distance to the epicenter of the Transition 24d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * or center of the scene if no epicenter exists. When a View is visible in the 25d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * start of the transition, Views farther from the epicenter will transition 26d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * sooner than Views closer to the epicenter. When a View is not in the start 27d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * of the transition or is not visible at the start of the transition, it will 28d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * transition sooner when closer to the epicenter and later when farther from 29d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * the epicenter. This is the default TransitionPropagation used with 30d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * {@link android.transition.Explode}. 31d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount */ 32d6107a3170df61d9e776fcd5666acfc9135c6f16George Mountpublic class CircularPropagation extends VisibilityPropagation { 33d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount private static final String TAG = "CircularPropagation"; 34d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount 35265f209d551092a08f2969ec5fed94292d7741b6George Mount private float mPropagationSpeed = 3.0f; 36d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount 37d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount /** 38d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * Sets the speed at which transition propagation happens, relative to the duration of the 39d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * Transition. A <code>propagationSpeed</code> of 1 means that a View centered farthest from 40d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * the epicenter and View centered at the epicenter will have a difference 41d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * in start delay of approximately the duration of the Transition. A speed of 2 means the 42d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * start delay difference will be approximately half of the duration of the transition. A 43d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * value of 0 is illegal, but negative values will invert the propagation. 44d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * 45d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * @param propagationSpeed The speed at which propagation occurs, relative to the duration 46d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * of the transition. A speed of 4 means it works 4 times as fast 47d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * as the duration of the transition. May not be 0. 48d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount */ 49d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount public void setPropagationSpeed(float propagationSpeed) { 50d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount if (propagationSpeed == 0) { 51d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount throw new IllegalArgumentException("propagationSpeed may not be 0"); 52d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount } 53d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount mPropagationSpeed = propagationSpeed; 54d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount } 55d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount 56d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount @Override 57d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount public long getStartDelay(ViewGroup sceneRoot, Transition transition, 58d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount TransitionValues startValues, TransitionValues endValues) { 59d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount if (startValues == null && endValues == null) { 60d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount return 0; 61d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount } 62d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount int directionMultiplier = 1; 63d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount TransitionValues positionValues; 64d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount if (endValues == null || getViewVisibility(startValues) == View.VISIBLE) { 65d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount positionValues = startValues; 66d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount directionMultiplier = -1; 67d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount } else { 68d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount positionValues = endValues; 69d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount } 70d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount 71d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount int viewCenterX = getViewX(positionValues); 72d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount int viewCenterY = getViewY(positionValues); 73d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount 74d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount Rect epicenter = transition.getEpicenter(); 75d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount int epicenterX; 76d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount int epicenterY; 77d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount if (epicenter != null) { 78d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount epicenterX = epicenter.centerX(); 79d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount epicenterY = epicenter.centerY(); 80d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount } else { 81d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount int[] loc = new int[2]; 82d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount sceneRoot.getLocationOnScreen(loc); 83d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount epicenterX = Math.round(loc[0] + (sceneRoot.getWidth() / 2) 84d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount + sceneRoot.getTranslationX()); 85d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount epicenterY = Math.round(loc[1] + (sceneRoot.getHeight() / 2) 86d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount + sceneRoot.getTranslationY()); 87d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount } 88e573aa9371fc507075219cd078117f96ba8b3b02Neil Fuller double distance = distance(viewCenterX, viewCenterY, epicenterX, epicenterY); 89e573aa9371fc507075219cd078117f96ba8b3b02Neil Fuller double maxDistance = distance(0, 0, sceneRoot.getWidth(), sceneRoot.getHeight()); 90e573aa9371fc507075219cd078117f96ba8b3b02Neil Fuller double distanceFraction = distance/maxDistance; 91d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount 92265f209d551092a08f2969ec5fed94292d7741b6George Mount long duration = transition.getDuration(); 93265f209d551092a08f2969ec5fed94292d7741b6George Mount if (duration < 0) { 94265f209d551092a08f2969ec5fed94292d7741b6George Mount duration = 300; 95265f209d551092a08f2969ec5fed94292d7741b6George Mount } 96265f209d551092a08f2969ec5fed94292d7741b6George Mount 97265f209d551092a08f2969ec5fed94292d7741b6George Mount return Math.round(duration * directionMultiplier / mPropagationSpeed * distanceFraction); 98d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount } 99d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount 100e573aa9371fc507075219cd078117f96ba8b3b02Neil Fuller private static double distance(float x1, float y1, float x2, float y2) { 101e573aa9371fc507075219cd078117f96ba8b3b02Neil Fuller double x = x2 - x1; 102e573aa9371fc507075219cd078117f96ba8b3b02Neil Fuller double y = y2 - y1; 103e573aa9371fc507075219cd078117f96ba8b3b02Neil Fuller return Math.hypot(x, y); 104d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount } 105d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount} 106