package com.android.launcher; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.SystemClock; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class HolderLayout extends ViewGroup { //ADW: Animation vars private final static int CLOSED=1; private final static int OPEN=2; private final static int CLOSING=3; private final static int OPENING=4; private int mStatus=OPEN; private boolean isAnimating; private long startTime; private float mScaleFactor; private int mIconSize=0; private Paint mPaint; private Paint mLabelPaint; private int mBgAlpha=255; private boolean shouldDrawLabels=false; private int mAnimationDuration=800; private boolean mDrawLabels=true; private boolean mFadeDrawLabels=false; private float mLabelFactor; private long mCurrentTime; private float mPorcentajeScale; //ADW: listener to dispatch open/close animation events private OnFadingListener mOnFadingListener; private int distH; private int distV; private float x; private float y; private float width; private float height; private Rect rl1=new Rect(); private Rect rl2=new Rect(); private float scale; private Rect r3=new Rect(); private int xx; public HolderLayout(Context context) { super(context); // TODO Auto-generated constructor stub mPaint=new Paint(); mPaint.setDither(false); mLabelPaint=new Paint(); mLabelPaint.setDither(false); setWillNotDraw(false); updateLabelVars(context); } public HolderLayout(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub mPaint=new Paint(); mPaint.setDither(false); mLabelPaint=new Paint(); mLabelPaint.setDither(false); setWillNotDraw(false); updateLabelVars(context); } public HolderLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub mPaint=new Paint(); mPaint.setDither(false); mLabelPaint=new Paint(); mLabelPaint.setDither(false); setWillNotDraw(false); updateLabelVars(context); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // TODO Auto-generated method stub } @Override protected boolean addViewInLayout(View child, int index, LayoutParams params, boolean preventRequestLayout) { // TODO Auto-generated method stub return super.addViewInLayout(child, index, params, preventRequestLayout); } @Override protected void attachViewToParent(View child, int index, LayoutParams params) { // TODO Auto-generated method stub super.attachViewToParent(child, index, params); } @Override protected void dispatchSetPressed(boolean pressed) { // TODO Auto-generated method stub //super.dispatchSetPressed(pressed); } @Override public void dispatchSetSelected(boolean selected) { // TODO Auto-generated method stub super.dispatchSetSelected(selected); } /*@Override public void requestChildFocus(View child, View focused) { super.requestChildFocus(child, focused); if (child != null) { Rect r = new Rect(); child.getDrawingRect(r); requestRectangleOnScreen(r); } }*/ @Override protected void setChildrenDrawingCacheEnabled(boolean enabled) { final int count = getChildCount(); for (int i = 0; i < count; i++) { final View view = getChildAt(i); view.setDrawingCacheEnabled(enabled); // Update the drawing caches view.buildDrawingCache(true); } } @Override protected void setChildrenDrawnWithCacheEnabled(boolean enabled) { super.setChildrenDrawnWithCacheEnabled(enabled); } @Override protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) { // TODO Auto-generated method stub //super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { //Log.d("HolderLayout","INTERCEPT"); return true; } @Override public boolean onTouchEvent(MotionEvent ev) { //Log.d("HolderLayout","TOUCH"); return true; } /** * ADW: easing functions for animation */ static float easeOut (float time, float begin, float end, float duration) { float change=end- begin; return change*((time=time/duration-1)*time*time + 1) + begin; } static float easeIn (float time, float begin, float end, float duration) { float change=end- begin; return change*(time/=duration)*time*time + begin; } static float easeInOut (float time, float begin, float end, float duration) { float change=end- begin; if ((time/=duration/2.0f) < 1) return change/2.0f*time*time*time + begin; return change/2.0f*((time-=2.0f)*time*time + 2.0f) + begin; } /** * ADW: Override drawing methods to do animation */ @Override public void draw(Canvas canvas) { if (isAnimating) { if (startTime == 0) { startTime = SystemClock.uptimeMillis(); mCurrentTime = 0; } else { mCurrentTime = SystemClock.uptimeMillis() - startTime; } if (mStatus == OPENING) { mScaleFactor = easeOut(mCurrentTime, 3.0f, 1.0f, mAnimationDuration); mLabelFactor = easeOut(mCurrentTime, -1.0f, 1.0f, mAnimationDuration); } else if (mStatus == CLOSING) { mScaleFactor = easeIn(mCurrentTime, 1.0f, 3.0f, mAnimationDuration); mLabelFactor = easeIn(mCurrentTime, 1.0f, -1.0f, mAnimationDuration); } if (mLabelFactor < 0) mLabelFactor = 0; if (mCurrentTime >= mAnimationDuration) { isAnimating = false; if (mStatus == OPENING) { mStatus = OPEN; dispatchFadingEvent(OnFadingListener.OPEN); } else if (mStatus == CLOSING) { mStatus = CLOSED; dispatchFadingEvent(OnFadingListener.CLOSE); } } } if(mStatus!=CLOSED){ shouldDrawLabels = mFadeDrawLabels && mDrawLabels && (mStatus == OPENING || mStatus == CLOSING); mPorcentajeScale = 1.0f; if (isAnimating) { mPorcentajeScale = 1.0f - ((mScaleFactor - 1) / 3.0f); if (mPorcentajeScale > 0.9f) mPorcentajeScale = 1f; if (mPorcentajeScale < 0) mPorcentajeScale = 0; dispatchFadingAlphaEvent(mPorcentajeScale); mBgAlpha = (int) (mPorcentajeScale * 255); } mPaint.setAlpha(mBgAlpha); super.draw(canvas); } } @Override protected boolean drawChild(Canvas canvas, View child, long drawingTime) { int saveCount = canvas.save(); Drawable[] tmp=((TextView)child).getCompoundDrawables(); if(mIconSize==0){ mIconSize=tmp[1].getIntrinsicHeight()+child.getPaddingTop(); } if(isAnimating){ postInvalidate(); //float x; //float y; distH=(child.getLeft()+(child.getWidth()/2))-(getWidth()/2); distV=(child.getTop()+(child.getHeight()/2))-(getHeight()/2); x=child.getLeft()+(distH*(mScaleFactor-1))*(mScaleFactor); y=child.getTop()+(distV*(mScaleFactor-1))*(mScaleFactor); width=child.getWidth()*mScaleFactor; height=(child.getHeight()-(child.getHeight()-mIconSize))*mScaleFactor; if(shouldDrawLabels)child.setDrawingCacheEnabled(true); if(shouldDrawLabels && child.getDrawingCache()!=null){ //ADW: try to manually draw labels rl1.set(0,mIconSize,child.getDrawingCache().getWidth(),child.getDrawingCache().getHeight()); rl2.set(child.getLeft(),child.getTop()+mIconSize,child.getLeft()+child.getDrawingCache().getWidth(),child.getTop()+child.getDrawingCache().getHeight()); mLabelPaint.setAlpha((int) (mLabelFactor*255)); canvas.drawBitmap(child.getDrawingCache(), rl1, rl2, mLabelPaint); } scale=((width)/child.getWidth()); r3 = tmp[1].getBounds(); xx=(child.getWidth()/2)-(r3.width()/2); canvas.save(); canvas.translate(x+xx, y+child.getPaddingTop()); canvas.scale(scale, scale); tmp[1].draw(canvas); canvas.restore(); }else{ if(mDrawLabels){ child.setDrawingCacheEnabled(true); if(child.getDrawingCache()!=null){ mPaint.setAlpha(255); canvas.drawBitmap(child.getDrawingCache(), child.getLeft(), child.getTop(), mPaint); }else{ canvas.save(); canvas.translate(child.getLeft(), child.getTop()); child.draw(canvas); canvas.restore(); } }else{ r3 = tmp[1].getBounds(); int xx=(child.getWidth()/2)-(r3.width()/2); canvas.save(); canvas.translate(child.getLeft()+xx, child.getTop()+child.getPaddingTop()); tmp[1].draw(canvas); canvas.restore(); } } canvas.restoreToCount(saveCount); return true; } /** * Open/close public methods */ public void open(boolean animate, int speed){ if(mStatus!=OPENING){ mAnimationDuration=speed; if(animate){ isAnimating=true; mStatus=OPENING; }else{ isAnimating=false; mStatus=OPEN; dispatchFadingEvent(OnFadingListener.OPEN); } startTime=0; invalidate(); } } public void close(boolean animate, int speed){ if(mStatus!=CLOSING){ mAnimationDuration=speed; if(animate){ mStatus=CLOSING; isAnimating=true; }else{ mStatus=CLOSED; isAnimating=false; dispatchFadingEvent(OnFadingListener.CLOSE); } startTime=0; invalidate(); } } /** * Interface definition for a callback to be invoked when an open/close animation * starts/ends */ public interface OnFadingListener { public static final int OPEN=1; public static final int CLOSE=2; void onUpdate(int Status); void onAlphaChange(float alphaPercent); } public void setOnFadingListener(OnFadingListener listener) { mOnFadingListener = listener; } /** * Dispatches a trigger event to listener. Ignored if a listener is not set. * @param whichHandle the handle that triggered the event. */ private void dispatchFadingEvent(int status) { if (mOnFadingListener != null) { mOnFadingListener.onUpdate(status); } } /** * Dispatches a trigger event to listener. Ignored if a listener is not set. * @param whichHandle the handle that triggered the event. */ private void dispatchFadingAlphaEvent(float alphaPercent) { if (mOnFadingListener != null) { mOnFadingListener.onAlphaChange(alphaPercent); } } public void updateLabelVars(Context context){ mDrawLabels=AlmostNexusSettingsHelper.getDrawerLabels(context); mFadeDrawLabels=AlmostNexusSettingsHelper.getFadeDrawerLabels(context); } }