summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--res/drawable-hdpi/active_page.pngbin1295 -> 1223 bytes
-rw-r--r--res/drawable-hdpi/inactive_page.pngbin1402 -> 1275 bytes
-rw-r--r--res/drawable-mdpi/active_page.pngbin1186 -> 1225 bytes
-rw-r--r--res/drawable-mdpi/inactive_page.pngbin1268 -> 1189 bytes
-rw-r--r--res/drawable-xhdpi/active_page.pngbin1367 -> 1225 bytes
-rw-r--r--res/drawable-xhdpi/inactive_page.pngbin1450 -> 1235 bytes
-rw-r--r--res/layout/page_indicator.xml3
-rw-r--r--res/values/attrs.xml7
-rw-r--r--res/values/config.xml3
-rw-r--r--src/com/android/launcher3/PageIndicator.java149
-rw-r--r--src/com/android/launcher3/PageIndicatorMarker.java44
11 files changed, 180 insertions, 26 deletions
diff --git a/res/drawable-hdpi/active_page.png b/res/drawable-hdpi/active_page.png
index ce2d5b169..58aa7f9ee 100644
--- a/res/drawable-hdpi/active_page.png
+++ b/res/drawable-hdpi/active_page.png
Binary files differ
diff --git a/res/drawable-hdpi/inactive_page.png b/res/drawable-hdpi/inactive_page.png
index 2186f519a..b70d9f418 100644
--- a/res/drawable-hdpi/inactive_page.png
+++ b/res/drawable-hdpi/inactive_page.png
Binary files differ
diff --git a/res/drawable-mdpi/active_page.png b/res/drawable-mdpi/active_page.png
index 9e23eccb0..296a9a6b0 100644
--- a/res/drawable-mdpi/active_page.png
+++ b/res/drawable-mdpi/active_page.png
Binary files differ
diff --git a/res/drawable-mdpi/inactive_page.png b/res/drawable-mdpi/inactive_page.png
index 9468a62ed..2225d250b 100644
--- a/res/drawable-mdpi/inactive_page.png
+++ b/res/drawable-mdpi/inactive_page.png
Binary files differ
diff --git a/res/drawable-xhdpi/active_page.png b/res/drawable-xhdpi/active_page.png
index c43e67c40..a1cfc354b 100644
--- a/res/drawable-xhdpi/active_page.png
+++ b/res/drawable-xhdpi/active_page.png
Binary files differ
diff --git a/res/drawable-xhdpi/inactive_page.png b/res/drawable-xhdpi/inactive_page.png
index ae3f9885b..177b25305 100644
--- a/res/drawable-xhdpi/inactive_page.png
+++ b/res/drawable-xhdpi/inactive_page.png
Binary files differ
diff --git a/res/layout/page_indicator.xml b/res/layout/page_indicator.xml
index 8aae752c5..14eff75d0 100644
--- a/res/layout/page_indicator.xml
+++ b/res/layout/page_indicator.xml
@@ -16,5 +16,6 @@
<com.android.launcher3.PageIndicator
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3"
- android:animateLayoutChanges="true">
+ android:animateLayoutChanges="true"
+ launcher:windowSize="@integer/config_maxNumberOfPageIndicatorsToShow">
</com.android.launcher3.PageIndicator>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 154508379..09b880420 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -32,6 +32,13 @@
<attr name="drawIdentifier" format="string" />
</declare-styleable>
+ <!-- Page Indicator specific attributes. These attributes are used to customize
+ the cling in XML files. -->
+ <declare-styleable name="PageIndicator">
+ <!-- Used to identify how to draw the cling bg -->
+ <attr name="windowSize" format="integer" />
+ </declare-styleable>
+
<!-- Workspace specific attributes. These attributes are used to customize
the workspace in XML files. -->
<declare-styleable name="Workspace">
diff --git a/res/values/config.xml b/res/values/config.xml
index 6aaca1ad5..cc3d4f0bf 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -3,6 +3,9 @@
<bool name="is_large_screen">false</bool>
<bool name="allow_rotation">false</bool>
+ <!-- Max number of page indicators to show -->
+ <integer name="config_maxNumberOfPageIndicatorsToShow">21</integer>
+
<!-- DragController -->
<integer name="config_flingToDeleteMinVelocity">-1500</integer>
diff --git a/src/com/android/launcher3/PageIndicator.java b/src/com/android/launcher3/PageIndicator.java
index ecaa8f544..d7778fb1a 100644
--- a/src/com/android/launcher3/PageIndicator.java
+++ b/src/com/android/launcher3/PageIndicator.java
@@ -19,6 +19,7 @@ package com.android.launcher3;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.LayoutTransition;
+import android.animation.TimeInterpolator;
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Configuration;
@@ -37,8 +38,22 @@ import java.util.ArrayList;
public class PageIndicator extends LinearLayout {
@SuppressWarnings("unused")
private static final String TAG = "PageIndicator";
+ // Want this to look good? Keep it odd
+ private static final boolean MODULATE_ALPHA_ENABLED = false;
private LayoutInflater mLayoutInflater;
+ private int[] mWindowRange = new int[2];
+ private int mMaxWindowSize;
+
+ private ArrayList<PageIndicatorMarker> mMarkers =
+ new ArrayList<PageIndicatorMarker>();
+ private int mActiveMarkerIndex;
+
+ private TimeInterpolator mAlphaInterpolator = new TimeInterpolator() {
+ public float getInterpolation(float t) {
+ return t;
+ }
+ };
public PageIndicator(Context context) {
this(context, null);
@@ -50,16 +65,110 @@ public class PageIndicator extends LinearLayout {
public PageIndicator(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
+ TypedArray a = context.obtainStyledAttributes(attrs,
+ R.styleable.PageIndicator, defStyle, 0);
+ mMaxWindowSize = a.getInteger(R.styleable.PageIndicator_windowSize, 15);
+ mWindowRange[0] = 0;
+ mWindowRange[1] = 0;
mLayoutInflater = LayoutInflater.from(context);
+ a.recycle();
+
+ // Set the layout transition properties
+ LayoutTransition transition = getLayoutTransition();
+ transition.setDuration(175);
+ }
+
+ private void enableLayoutTransitions() {
+ LayoutTransition transition = getLayoutTransition();
+ transition.enableTransitionType(LayoutTransition.APPEARING);
+ transition.enableTransitionType(LayoutTransition.DISAPPEARING);
+ transition.enableTransitionType(LayoutTransition.CHANGE_APPEARING);
+ transition.enableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
+ }
+ private void disableLayoutTransitions() {
LayoutTransition transition = getLayoutTransition();
- transition.setDuration(250);
+ transition.disableTransitionType(LayoutTransition.APPEARING);
+ transition.disableTransitionType(LayoutTransition.DISAPPEARING);
+ transition.disableTransitionType(LayoutTransition.CHANGE_APPEARING);
+ transition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
+ }
+
+ void offsetWindowCenterTo(int activeIndex, boolean allowAnimations) {
+ if (activeIndex < 0) {
+ new Throwable().printStackTrace();
+ }
+ int windowSize = Math.min(mMarkers.size(), mMaxWindowSize);
+ int hWindowSize = (int) windowSize / 2;
+ float hfWindowSize = windowSize / 2f;
+ int windowStart = Math.max(0, activeIndex - hWindowSize);
+ int windowEnd = Math.min(mMarkers.size(), windowStart + mMaxWindowSize);
+ windowStart = windowEnd - Math.min(mMarkers.size(), windowSize);
+ int windowMid = windowStart + (windowEnd - windowStart) / 2;
+ boolean windowAtStart = (windowStart == 0);
+ boolean windowAtEnd = (windowEnd == mMarkers.size());
+ boolean windowMoved = (mWindowRange[0] != windowStart) ||
+ (mWindowRange[1] != windowEnd);
+
+ if (!allowAnimations) {
+ disableLayoutTransitions();
+ }
+
+ // Remove all the previous children that are no longer in the window
+ for (int i = getChildCount() - 1; i >= 0; --i) {
+ PageIndicatorMarker marker = (PageIndicatorMarker) getChildAt(i);
+ int markerIndex = mMarkers.indexOf(marker);
+ if (markerIndex < windowStart || markerIndex >= windowEnd) {
+ removeView(marker);
+ }
+ }
+
+ // Add all the new children that belong in the window
+ for (int i = 0; i < mMarkers.size(); ++i) {
+ PageIndicatorMarker marker = (PageIndicatorMarker) mMarkers.get(i);
+ if (windowStart <= i && i < windowEnd) {
+ if (indexOfChild(marker) < 0) {
+ addView(marker, i - windowStart);
+ }
+ if (i == activeIndex) {
+ marker.activate(windowMoved);
+ } else {
+ marker.inactivate(windowMoved);
+ }
+ } else {
+ marker.inactivate(true);
+ }
+
+ if (MODULATE_ALPHA_ENABLED) {
+ // Update the marker's alpha
+ float alpha = 1f;
+ if (mMarkers.size() > windowSize) {
+ if ((windowAtStart && i > hWindowSize) ||
+ (windowAtEnd && i < (mMarkers.size() - hWindowSize)) ||
+ (!windowAtStart && !windowAtEnd)) {
+ alpha = 1f - Math.abs((i - windowMid) / hfWindowSize);
+ }
+ }
+ marker.animate().alpha(alpha).setDuration(500).start();
+ }
+ }
+
+ if (!allowAnimations) {
+ enableLayoutTransitions();
+ }
+
+ mWindowRange[0] = windowStart;
+ mWindowRange[1] = windowEnd;
}
void addMarker(int index) {
- index = Math.max(0, Math.min(index, getChildCount()));
- View marker = mLayoutInflater.inflate(R.layout.page_indicator_marker, this, false);
- addView(marker, index);
+ index = Math.max(0, Math.min(index, mMarkers.size()));
+
+ int mLayoutId = R.layout.page_indicator_marker;
+ PageIndicatorMarker marker =
+ (PageIndicatorMarker) mLayoutInflater.inflate(mLayoutId, this, false);
+ mMarkers.add(index, marker);
+ offsetWindowCenterTo(mActiveMarkerIndex, true);
}
void addMarkers(int count) {
for (int i = 0; i < count; ++i) {
@@ -68,25 +177,37 @@ public class PageIndicator extends LinearLayout {
}
void removeMarker(int index) {
- if (getChildCount() > 0) {
- index = Math.max(0, Math.min(index, getChildCount() - 1));
- removeViewAt(index);
+ if (mMarkers.size() > 0) {
+ index = Math.max(0, Math.min(mMarkers.size() - 1, index));
+ mMarkers.remove(index);
+ offsetWindowCenterTo(mActiveMarkerIndex, true);
}
}
void removeAllMarkers() {
- while (getChildCount() > 0) {
+ while (mMarkers.size() > 0) {
removeMarker(Integer.MAX_VALUE);
}
}
void setActiveMarker(int index) {
+ // Center the active marker
+ mActiveMarkerIndex = index;
+ offsetWindowCenterTo(index, false);
+ }
+
+ void dumpState(String txt) {
+ System.out.println(txt);
+ System.out.println("\tmMarkers: " + mMarkers.size());
+ for (int i = 0; i < mMarkers.size(); ++i) {
+ PageIndicatorMarker m = mMarkers.get(i);
+ System.out.println("\t\t(" + i + ") " + m);
+ }
+ System.out.println("\twindow: [" + mWindowRange[0] + ", " + mWindowRange[1] + "]");
+ System.out.println("\tchildren: " + getChildCount());
for (int i = 0; i < getChildCount(); ++i) {
- PageIndicatorMarker marker = (PageIndicatorMarker) getChildAt(i);
- if (index == i) {
- marker.activate();
- } else {
- marker.inactivate();
- }
+ PageIndicatorMarker m = (PageIndicatorMarker) getChildAt(i);
+ System.out.println("\t\t(" + i + ") " + m);
}
+ System.out.println("\tactive: " + mActiveMarkerIndex);
}
}
diff --git a/src/com/android/launcher3/PageIndicatorMarker.java b/src/com/android/launcher3/PageIndicatorMarker.java
index 852ee518f..f64c14fdc 100644
--- a/src/com/android/launcher3/PageIndicatorMarker.java
+++ b/src/com/android/launcher3/PageIndicatorMarker.java
@@ -16,6 +16,7 @@
package com.android.launcher3;
+import android.animation.AnimatorListenerAdapter;
import android.animation.LayoutTransition;
import android.content.Context;
import android.util.AttributeSet;
@@ -29,10 +30,11 @@ public class PageIndicatorMarker extends FrameLayout {
@SuppressWarnings("unused")
private static final String TAG = "PageIndicator";
- private static final int MARKER_FADE_DURATION = 150;
+ private static final int MARKER_FADE_DURATION = 175;
private View mActiveMarker;
private View mInactiveMarker;
+ private boolean mIsActive = false;
public PageIndicatorMarker(Context context) {
this(context, null);
@@ -51,16 +53,36 @@ public class PageIndicatorMarker extends FrameLayout {
mInactiveMarker = findViewById(R.id.inactive);
}
- public void activate() {
- mActiveMarker.animate().alpha(1f)
- .setDuration(MARKER_FADE_DURATION).start();
- mInactiveMarker.animate().alpha(0f)
- .setDuration(MARKER_FADE_DURATION).start();
+ void activate(boolean immediate) {
+ if (immediate) {
+ mActiveMarker.animate().cancel();
+ mActiveMarker.setAlpha(1f);
+ mInactiveMarker.animate().cancel();
+ mInactiveMarker.setAlpha(0f);
+ } else {
+ mActiveMarker.animate().alpha(1f)
+ .setDuration(MARKER_FADE_DURATION).start();
+ mInactiveMarker.animate().alpha(0f)
+ .setDuration(MARKER_FADE_DURATION).start();
+ }
+ mIsActive = true;
}
- public void inactivate() {
- mInactiveMarker.animate().alpha(1f)
- .setDuration(MARKER_FADE_DURATION).start();
- mActiveMarker.animate().alpha(0f)
- .setDuration(MARKER_FADE_DURATION).start();
+ void inactivate(boolean immediate) {
+ if (immediate) {
+ mInactiveMarker.animate().cancel();
+ mInactiveMarker.setAlpha(1f);
+ mActiveMarker.animate().cancel();
+ mActiveMarker.setAlpha(0f);
+ } else {
+ mInactiveMarker.animate().alpha(1f)
+ .setDuration(MARKER_FADE_DURATION).start();
+ mActiveMarker.animate().alpha(0f)
+ .setDuration(MARKER_FADE_DURATION).start();
+ }
+ mIsActive = false;
+ }
+
+ boolean isActive() {
+ return mIsActive;
}
}