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.Animator;
     20 import android.animation.AnimatorListenerAdapter;
     21 import android.animation.LayoutTransition;
     22 import android.animation.TimeInterpolator;
     23 import android.content.ComponentName;
     24 import android.content.Context;
     25 import android.content.res.Configuration;
     26 import android.content.res.Resources;
     27 import android.content.res.TypedArray;
     28 import android.util.AttributeSet;
     29 import android.util.Log;
     30 import android.view.LayoutInflater;
     31 import android.view.View;
     32 import android.view.ViewGroup;
     33 import android.widget.LinearLayout;
     34 import com.android.launcher3.R;
     35 
     36 import java.util.ArrayList;
     37 
     38 public class PageIndicator extends LinearLayout {
     39     @SuppressWarnings("unused")
     40     private static final String TAG = "PageIndicator";
     41     // Want this to look good? Keep it odd
     42     private static final boolean MODULATE_ALPHA_ENABLED = false;
     43 
     44     private LayoutInflater mLayoutInflater;
     45     private int[] mWindowRange = new int[2];
     46     private int mMaxWindowSize;
     47 
     48     private ArrayList<PageIndicatorMarker> mMarkers =
     49             new ArrayList<PageIndicatorMarker>();
     50     private int mActiveMarkerIndex;
     51 
     52     public static class PageMarkerResources {
     53         int activeId;
     54         int inactiveId;
     55 
     56         public PageMarkerResources() {
     57             activeId = R.drawable.ic_pageindicator_current;
     58             inactiveId = R.drawable.ic_pageindicator_default;
     59         }
     60         public PageMarkerResources(int aId, int iaId) {
     61             activeId = aId;
     62             inactiveId = iaId;
     63         }
     64     }
     65 
     66     public PageIndicator(Context context) {
     67         this(context, null);
     68     }
     69 
     70     public PageIndicator(Context context, AttributeSet attrs) {
     71         this(context, attrs, 0);
     72     }
     73 
     74     public PageIndicator(Context context, AttributeSet attrs, int defStyle) {
     75         super(context, attrs, defStyle);
     76         TypedArray a = context.obtainStyledAttributes(attrs,
     77                 R.styleable.PageIndicator, defStyle, 0);
     78         mMaxWindowSize = a.getInteger(R.styleable.PageIndicator_windowSize, 15);
     79         mWindowRange[0] = 0;
     80         mWindowRange[1] = 0;
     81         mLayoutInflater = LayoutInflater.from(context);
     82         a.recycle();
     83 
     84         // Set the layout transition properties
     85         LayoutTransition transition = getLayoutTransition();
     86         transition.setDuration(175);
     87     }
     88 
     89     private void enableLayoutTransitions() {
     90         LayoutTransition transition = getLayoutTransition();
     91         transition.enableTransitionType(LayoutTransition.APPEARING);
     92         transition.enableTransitionType(LayoutTransition.DISAPPEARING);
     93         transition.enableTransitionType(LayoutTransition.CHANGE_APPEARING);
     94         transition.enableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
     95     }
     96 
     97     private void disableLayoutTransitions() {
     98         LayoutTransition transition = getLayoutTransition();
     99         transition.disableTransitionType(LayoutTransition.APPEARING);
    100         transition.disableTransitionType(LayoutTransition.DISAPPEARING);
    101         transition.disableTransitionType(LayoutTransition.CHANGE_APPEARING);
    102         transition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
    103     }
    104 
    105     void offsetWindowCenterTo(int activeIndex, boolean allowAnimations) {
    106         if (activeIndex < 0) {
    107             new Throwable().printStackTrace();
    108         }
    109         int windowSize = Math.min(mMarkers.size(), mMaxWindowSize);
    110         int hWindowSize = (int) windowSize / 2;
    111         float hfWindowSize = windowSize / 2f;
    112         int windowStart = Math.max(0, activeIndex - hWindowSize);
    113         int windowEnd = Math.min(mMarkers.size(), windowStart + mMaxWindowSize);
    114         windowStart = windowEnd - Math.min(mMarkers.size(), windowSize);
    115         int windowMid = windowStart + (windowEnd - windowStart) / 2;
    116         boolean windowAtStart = (windowStart == 0);
    117         boolean windowAtEnd = (windowEnd == mMarkers.size());
    118         boolean windowMoved = (mWindowRange[0] != windowStart) ||
    119                 (mWindowRange[1] != windowEnd);
    120 
    121         if (!allowAnimations) {
    122             disableLayoutTransitions();
    123         }
    124 
    125         // Remove all the previous children that are no longer in the window
    126         for (int i = getChildCount() - 1; i >= 0; --i) {
    127             PageIndicatorMarker marker = (PageIndicatorMarker) getChildAt(i);
    128             int markerIndex = mMarkers.indexOf(marker);
    129             if (markerIndex < windowStart || markerIndex >= windowEnd) {
    130                 removeView(marker);
    131             }
    132         }
    133 
    134         // Add all the new children that belong in the window
    135         for (int i = 0; i < mMarkers.size(); ++i) {
    136             PageIndicatorMarker marker = (PageIndicatorMarker) mMarkers.get(i);
    137             if (windowStart <= i && i < windowEnd) {
    138                 if (indexOfChild(marker) < 0) {
    139                     addView(marker, i - windowStart);
    140                 }
    141                 if (i == activeIndex) {
    142                     marker.activate(windowMoved);
    143                 } else {
    144                     marker.inactivate(windowMoved);
    145                 }
    146             } else {
    147                 marker.inactivate(true);
    148             }
    149 
    150             if (MODULATE_ALPHA_ENABLED) {
    151                 // Update the marker's alpha
    152                 float alpha = 1f;
    153                 if (mMarkers.size() > windowSize) {
    154                     if ((windowAtStart && i > hWindowSize) ||
    155                         (windowAtEnd && i < (mMarkers.size() - hWindowSize)) ||
    156                         (!windowAtStart && !windowAtEnd)) {
    157                         alpha = 1f - Math.abs((i - windowMid) / hfWindowSize);
    158                     }
    159                 }
    160                 marker.animate().alpha(alpha).setDuration(500).start();
    161             }
    162         }
    163 
    164         if (!allowAnimations) {
    165             enableLayoutTransitions();
    166         }
    167 
    168         mWindowRange[0] = windowStart;
    169         mWindowRange[1] = windowEnd;
    170     }
    171 
    172     void addMarker(int index, PageMarkerResources marker, boolean allowAnimations) {
    173         index = Math.max(0, Math.min(index, mMarkers.size()));
    174 
    175         PageIndicatorMarker m =
    176             (PageIndicatorMarker) mLayoutInflater.inflate(R.layout.page_indicator_marker,
    177                     this, false);
    178         m.setMarkerDrawables(marker.activeId, marker.inactiveId);
    179 
    180         mMarkers.add(index, m);
    181         offsetWindowCenterTo(mActiveMarkerIndex, allowAnimations);
    182     }
    183     void addMarkers(ArrayList<PageMarkerResources> markers, boolean allowAnimations) {
    184         for (int i = 0; i < markers.size(); ++i) {
    185             addMarker(Integer.MAX_VALUE, markers.get(i), allowAnimations);
    186         }
    187     }
    188 
    189     void updateMarker(int index, PageMarkerResources marker) {
    190         PageIndicatorMarker m = mMarkers.get(index);
    191         m.setMarkerDrawables(marker.activeId, marker.inactiveId);
    192     }
    193 
    194     void removeMarker(int index, boolean allowAnimations) {
    195         if (mMarkers.size() > 0) {
    196             index = Math.max(0, Math.min(mMarkers.size() - 1, index));
    197             mMarkers.remove(index);
    198             offsetWindowCenterTo(mActiveMarkerIndex, allowAnimations);
    199         }
    200     }
    201     void removeAllMarkers(boolean allowAnimations) {
    202         while (mMarkers.size() > 0) {
    203             removeMarker(Integer.MAX_VALUE, allowAnimations);
    204         }
    205     }
    206 
    207     void setActiveMarker(int index) {
    208         // Center the active marker
    209         mActiveMarkerIndex = index;
    210         offsetWindowCenterTo(index, false);
    211     }
    212 
    213     void dumpState(String txt) {
    214         System.out.println(txt);
    215         System.out.println("\tmMarkers: " + mMarkers.size());
    216         for (int i = 0; i < mMarkers.size(); ++i) {
    217             PageIndicatorMarker m = mMarkers.get(i);
    218             System.out.println("\t\t(" + i + ") " + m);
    219         }
    220         System.out.println("\twindow: [" + mWindowRange[0] + ", " + mWindowRange[1] + "]");
    221         System.out.println("\tchildren: " + getChildCount());
    222         for (int i = 0; i < getChildCount(); ++i) {
    223             PageIndicatorMarker m = (PageIndicatorMarker) getChildAt(i);
    224             System.out.println("\t\t(" + i + ") " + m);
    225         }
    226         System.out.println("\tactive: " + mActiveMarkerIndex);
    227     }
    228 }
    229