Home | History | Annotate | Download | only in launcher3
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.launcher3;
     18 
     19 import android.animation.TimeInterpolator;
     20 import android.content.Context;
     21 import android.util.AttributeSet;
     22 import android.view.View;
     23 import android.view.ViewDebug;
     24 import android.view.ViewGroup;
     25 import android.view.ViewPropertyAnimator;
     26 import android.view.accessibility.AccessibilityManager;
     27 import android.view.animation.AccelerateInterpolator;
     28 import android.widget.LinearLayout;
     29 
     30 import com.android.launcher3.dragndrop.DragController;
     31 import com.android.launcher3.dragndrop.DragOptions;
     32 
     33 /*
     34  * The top bar containing various drop targets: Delete/App Info/Uninstall.
     35  */
     36 public class DropTargetBar extends LinearLayout implements DragController.DragListener {
     37 
     38     protected static final int DEFAULT_DRAG_FADE_DURATION = 175;
     39     protected static final TimeInterpolator DEFAULT_INTERPOLATOR = new AccelerateInterpolator();
     40 
     41     private final Runnable mFadeAnimationEndRunnable = new Runnable() {
     42 
     43         @Override
     44         public void run() {
     45             AccessibilityManager am = (AccessibilityManager)
     46                     getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
     47             boolean accessibilityEnabled = am.isEnabled();
     48             AlphaUpdateListener.updateVisibility(DropTargetBar.this, accessibilityEnabled);
     49         }
     50     };
     51 
     52     @ViewDebug.ExportedProperty(category = "launcher")
     53     protected boolean mDeferOnDragEnd;
     54 
     55     @ViewDebug.ExportedProperty(category = "launcher")
     56     protected boolean mVisible = false;
     57 
     58     private ViewPropertyAnimator mCurrentAnimation;
     59 
     60     public DropTargetBar(Context context, AttributeSet attrs) {
     61         super(context, attrs);
     62     }
     63 
     64     public DropTargetBar(Context context, AttributeSet attrs, int defStyle) {
     65         super(context, attrs, defStyle);
     66     }
     67 
     68     @Override
     69     protected void onFinishInflate() {
     70         super.onFinishInflate();
     71 
     72         // Initialize with hidden state
     73         setAlpha(0f);
     74     }
     75 
     76     public void setup(DragController dragController) {
     77         dragController.addDragListener(this);
     78         setupButtonDropTarget(this, dragController);
     79     }
     80 
     81     @Override
     82     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
     83         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     84 
     85         boolean hideText = hideTextHelper(false /* shouldUpdateText */, false /* no-op */);
     86         if (hideTextHelper(true /* shouldUpdateText */, hideText)) {
     87             // Text has changed, so we need to re-measure.
     88             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     89         }
     90     }
     91 
     92     /**
     93      * Helper method that iterates through the children and returns whether any of the visible
     94      * {@link ButtonDropTarget} has truncated text.
     95      *
     96      * @param shouldUpdateText If True, updates the text of all children.
     97      * @param hideText If True and {@param shouldUpdateText} is True, clears the text of all
     98      *                 children; otherwise it sets the original text value.
     99      *
    100      *
    101      * @return If shouldUpdateText is True, returns whether any of the children updated their text.
    102      *         Else, returns whether any of the children have truncated their text.
    103      */
    104     private boolean hideTextHelper(boolean shouldUpdateText, boolean hideText) {
    105         boolean result = false;
    106         View visibleView;
    107         ButtonDropTarget dropTarget;
    108         for (int i = getChildCount() - 1; i >= 0; --i) {
    109             if (getChildAt(i) instanceof ButtonDropTarget) {
    110                 visibleView = dropTarget = (ButtonDropTarget) getChildAt(i);
    111             } else if (getChildAt(i) instanceof ViewGroup) {
    112                 // The Drop Target is wrapped in a FrameLayout.
    113                 visibleView = getChildAt(i);
    114                 dropTarget = (ButtonDropTarget) ((ViewGroup) visibleView).getChildAt(0);
    115             } else {
    116                 // Ignore other views.
    117                 continue;
    118             }
    119 
    120             if (visibleView.getVisibility() == View.VISIBLE) {
    121                 if (shouldUpdateText) {
    122                     result |= dropTarget.updateText(hideText);
    123                 } else if (dropTarget.isTextTruncated()) {
    124                     result = true;
    125                     break;
    126                 }
    127             }
    128         }
    129 
    130         return result;
    131     }
    132 
    133     private void setupButtonDropTarget(View view, DragController dragController) {
    134         if (view instanceof ButtonDropTarget) {
    135             ButtonDropTarget bdt = (ButtonDropTarget) view;
    136             bdt.setDropTargetBar(this);
    137             dragController.addDragListener(bdt);
    138             dragController.addDropTarget(bdt);
    139         } else if (view instanceof ViewGroup) {
    140             ViewGroup vg = (ViewGroup) view;
    141             for (int i = vg.getChildCount() - 1; i >= 0; i--) {
    142                 setupButtonDropTarget(vg.getChildAt(i), dragController);
    143             }
    144         }
    145     }
    146 
    147     private void animateToVisibility(boolean isVisible) {
    148         if (mVisible != isVisible) {
    149             mVisible = isVisible;
    150 
    151             // Cancel any existing animation
    152             if (mCurrentAnimation != null) {
    153                 mCurrentAnimation.cancel();
    154                 mCurrentAnimation = null;
    155             }
    156 
    157             float finalAlpha = mVisible ? 1 : 0;
    158             if (Float.compare(getAlpha(), finalAlpha) != 0) {
    159                 setVisibility(View.VISIBLE);
    160                 mCurrentAnimation = animate().alpha(finalAlpha)
    161                         .setInterpolator(DEFAULT_INTERPOLATOR)
    162                         .setDuration(DEFAULT_DRAG_FADE_DURATION)
    163                         .withEndAction(mFadeAnimationEndRunnable);
    164             }
    165 
    166         }
    167     }
    168 
    169     /*
    170      * DragController.DragListener implementation
    171      */
    172     @Override
    173     public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
    174         animateToVisibility(true);
    175     }
    176 
    177     /**
    178      * This is called to defer hiding the delete drop target until the drop animation has completed,
    179      * instead of hiding immediately when the drag has ended.
    180      */
    181     protected void deferOnDragEnd() {
    182         mDeferOnDragEnd = true;
    183     }
    184 
    185     @Override
    186     public void onDragEnd() {
    187         if (!mDeferOnDragEnd) {
    188             animateToVisibility(false);
    189         } else {
    190             mDeferOnDragEnd = false;
    191         }
    192     }
    193 }
    194