Merge "Throw exception if there's a contact loader error"
diff --git a/res/layout-sw580dp/contact_detail_updates_fragment.xml b/res/layout-sw580dp/contact_detail_updates_fragment.xml
index 6002151..3bcb01c 100644
--- a/res/layout-sw580dp/contact_detail_updates_fragment.xml
+++ b/res/layout-sw580dp/contact_detail_updates_fragment.xml
@@ -24,7 +24,6 @@
<ListView android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@color/background_social_updates"
android:fadingEdge="none"
android:divider="@null"/>
diff --git a/res/layout-w470dp/contact_detail_updates_fragment.xml b/res/layout-w470dp/contact_detail_updates_fragment.xml
index 44207fc..50536de 100644
--- a/res/layout-w470dp/contact_detail_updates_fragment.xml
+++ b/res/layout-w470dp/contact_detail_updates_fragment.xml
@@ -23,7 +23,6 @@
<ListView android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@color/background_social_updates"
android:fadingEdge="none"
android:divider="@null"/>
diff --git a/res/layout/carousel_updates_tab.xml b/res/layout/carousel_updates_tab.xml
index 9148651..91a72d3 100644
--- a/res/layout/carousel_updates_tab.xml
+++ b/res/layout/carousel_updates_tab.xml
@@ -27,7 +27,8 @@
android:background="@drawable/bg_people_updates_holo">
<ImageView android:id="@+id/status_photo"
- android:layout_width="wrap_content"
+ android:scaleType="centerCrop"
+ android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
diff --git a/res/layout/contact_detail_updates_fragment.xml b/res/layout/contact_detail_updates_fragment.xml
index a949cd8..4c056a8 100644
--- a/res/layout/contact_detail_updates_fragment.xml
+++ b/res/layout/contact_detail_updates_fragment.xml
@@ -18,7 +18,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:ex="http://schemas.android.com/apk/res/com.android.contacts"
android:id="@android:id/list"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@color/background_social_updates"
- android:divider="@null"/>
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/background_primary"
+ android:divider="@null"/>
diff --git a/src/com/android/contacts/detail/ContactDetailDisplayUtils.java b/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
index 86cb7fa..6bca80d 100644
--- a/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
+++ b/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
@@ -56,6 +56,7 @@
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.LinearLayout;
+import android.widget.ListView;
import android.widget.TextView;
import java.util.List;
@@ -500,4 +501,44 @@
view.setBackgroundColor((int) (alpha * 255) << 24);
}
}
+
+ /**
+ * Returns the top coordinate of the first item in the {@link ListView}. If the first item
+ * in the {@link ListView} is not visible or there are no children in the list, then return
+ * Integer.MIN_VALUE. Note that the returned value will be <= 0 because the first item in the
+ * list cannot have a positive offset.
+ */
+ public static int getFirstListItemOffset(ListView listView) {
+ if (listView == null || listView.getChildCount() == 0 ||
+ listView.getFirstVisiblePosition() != 0) {
+ return Integer.MIN_VALUE;
+ }
+ return listView.getChildAt(0).getTop();
+ }
+
+ /**
+ * Tries to scroll the first item in the list to the given offset (this can be a no-op if the
+ * list is already in the correct position).
+ * @param listView that should be scrolled
+ * @param offset which should be <= 0
+ */
+ public static void requestToMoveToOffset(ListView listView, int offset) {
+ // We try to offset the list if the first item in the list is showing (which is presumed
+ // to have a larger height than the desired offset). If the first item in the list is not
+ // visible, then we simply do not scroll the list at all (since it can get complicated to
+ // compute how many items in the list will equal the given offset). Potentially
+ // some animation elsewhere will make the transition smoother for the user to compensate
+ // for this simplification.
+ if (listView == null || listView.getChildCount() == 0 ||
+ listView.getFirstVisiblePosition() != 0 || offset > 0) {
+ return;
+ }
+
+ // As an optimization, check if the first item is already at the given offset.
+ if (listView.getChildAt(0).getTop() == offset) {
+ return;
+ }
+
+ listView.setSelectionFromTop(0, offset);
+ }
}
diff --git a/src/com/android/contacts/detail/ContactDetailFragment.java b/src/com/android/contacts/detail/ContactDetailFragment.java
index 4d50a39..daf8229 100644
--- a/src/com/android/contacts/detail/ContactDetailFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailFragment.java
@@ -377,6 +377,25 @@
bindData();
}
+ /**
+ * Returns the top coordinate of the first item in the {@link ListView}. If the first item
+ * in the {@link ListView} is not visible or there are no children in the list, then return
+ * Integer.MIN_VALUE. Note that the returned value will be <= 0 because the first item in the
+ * list cannot have a positive offset.
+ */
+ public int getFirstListItemOffset() {
+ return ContactDetailDisplayUtils.getFirstListItemOffset(mListView);
+ }
+
+ /**
+ * Tries to scroll the first item to the given offset (this can be a no-op if the list is
+ * already in the correct position).
+ * @param offset which should be <= 0
+ */
+ public void requestToMoveToOffset(int offset) {
+ ContactDetailDisplayUtils.requestToMoveToOffset(mListView, offset);
+ }
+
protected void bindData() {
if (mView == null) {
return;
diff --git a/src/com/android/contacts/detail/ContactDetailLayoutController.java b/src/com/android/contacts/detail/ContactDetailLayoutController.java
index a10431b..579d7bf 100644
--- a/src/com/android/contacts/detail/ContactDetailLayoutController.java
+++ b/src/com/android/contacts/detail/ContactDetailLayoutController.java
@@ -20,6 +20,7 @@
import com.android.contacts.R;
import com.android.contacts.activities.ContactDetailActivity.FragmentKeyListener;
+import android.animation.ObjectAnimator;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Context;
@@ -28,7 +29,9 @@
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
+import android.view.animation.AnimationUtils;
+import android.widget.AbsListView;
+import android.widget.AbsListView.OnScrollListener;
/**
* Determines the layout of the contact card.
@@ -38,6 +41,9 @@
private static final String KEY_CONTACT_HAS_UPDATES = "contactHasUpdates";
private static final String KEY_CURRENT_PAGE_INDEX = "currentPageIndex";
+ private static final int TAB_INDEX_DETAIL = 0;
+ private static final int TAB_INDEX_UPDATES = 1;
+
/**
* There are 3 possible layouts for the contact detail screen:
* 1. TWO_COLUMN - Tall and wide screen so the 2 pages can be shown side-by-side
@@ -48,6 +54,7 @@
TWO_COLUMN, VIEW_PAGER_AND_TAB_CAROUSEL, FRAGMENT_CAROUSEL,
}
+ private final Context mContext;
private final LayoutInflater mLayoutInflater;
private final FragmentManager mFragmentManager;
@@ -58,10 +65,11 @@
private View mUpdatesFragmentView;
private final ViewPager mViewPager;
- private final ContactDetailTabCarousel mTabCarousel;
private ContactDetailViewPagerAdapter mViewPagerAdapter;
+ private int mViewPagerState;
- private ContactDetailFragmentCarousel mFragmentCarousel;
+ private final ContactDetailTabCarousel mTabCarousel;
+ private final ContactDetailFragmentCarousel mFragmentCarousel;
private ContactDetailFragment.Listener mContactDetailFragmentListener;
@@ -80,6 +88,7 @@
+ "without a non-null FragmentManager");
}
+ mContext = context;
mLayoutInflater = (LayoutInflater) context.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
mFragmentManager = fragmentManager;
@@ -139,17 +148,17 @@
// which will in turn be the parents to the mDetailFragment and mUpdatesFragment
// since the fragments must have the same parent view IDs in both landscape and
// portrait layouts.
- ViewGroup detailContainer = (ViewGroup) mLayoutInflater.inflate(
+ mDetailFragmentView = mLayoutInflater.inflate(
R.layout.contact_detail_about_fragment_container, mViewPager, false);
- ViewGroup updatesContainer = (ViewGroup) mLayoutInflater.inflate(
+ mUpdatesFragmentView = mLayoutInflater.inflate(
R.layout.contact_detail_updates_fragment_container, mViewPager, false);
mViewPagerAdapter = new ContactDetailViewPagerAdapter();
- mViewPagerAdapter.setAboutFragmentView(detailContainer);
- mViewPagerAdapter.setUpdatesFragmentView(updatesContainer);
+ mViewPagerAdapter.setAboutFragmentView(mDetailFragmentView);
+ mViewPagerAdapter.setUpdatesFragmentView(mUpdatesFragmentView);
- mViewPager.addView(detailContainer);
- mViewPager.addView(updatesContainer);
+ mViewPager.addView(mDetailFragmentView);
+ mViewPager.addView(mUpdatesFragmentView);
mViewPager.setAdapter(mViewPagerAdapter);
mViewPager.setOnPageChangeListener(mOnPageChangeListener);
@@ -164,7 +173,10 @@
}
mTabCarousel.setListener(mTabCarouselListener);
- TabCarouselScrollManager.bind(mTabCarousel, mDetailFragment, mUpdatesFragment);
+ mDetailFragment.setVerticalScrollListener(
+ new VerticalScrollListener(TAB_INDEX_DETAIL));
+ mUpdatesFragment.setVerticalScrollListener(
+ new VerticalScrollListener(TAB_INDEX_UPDATES));
mViewPager.setCurrentItem(currentPageIndex);
break;
}
@@ -239,8 +251,9 @@
break;
}
case VIEW_PAGER_AND_TAB_CAROUSEL: {
- // Update and show the tab carousel
+ // Update and show the tab carousel (also restore its last saved position)
mTabCarousel.loadData(mContactData);
+ mTabCarousel.restoreYCoordinate();
mTabCarousel.setVisibility(View.VISIBLE);
// Update ViewPager to allow swipe between all the fragments (to see updates)
mViewPagerAdapter.enableSwipe(true);
@@ -320,7 +333,9 @@
outState.putInt(KEY_CURRENT_PAGE_INDEX, getCurrentPageIndex());
}
- private OnPageChangeListener mOnPageChangeListener = new OnPageChangeListener() {
+ private final OnPageChangeListener mOnPageChangeListener = new OnPageChangeListener() {
+
+ private ObjectAnimator mTabCarouselAnimator;
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
@@ -338,17 +353,102 @@
@Override
public void onPageSelected(int position) {
- // Since a new page has been selected by the {@link ViewPager},
- // update the tab selection in the carousel.
+ // Since the {@link ViewPager} has committed to a new page now (but may not have
+ // finished scrolling yet), update the tab selection in the carousel.
mTabCarousel.setCurrentTab(position);
}
@Override
- public void onPageScrollStateChanged(int state) {}
+ public void onPageScrollStateChanged(int state) {
+ if (mViewPagerState == ViewPager.SCROLL_STATE_IDLE) {
+ // If we are leaving the IDLE state, we are starting a swipe.
+ // First cancel any pending animations on the tab carousel.
+ cancelTabCarouselAnimator();
+
+ // Sync the two lists because the list on the other page will start to show as
+ // we swipe over more.
+ syncScrollStateBetweenLists(mViewPager.getCurrentItem());
+
+ } else if (state == ViewPager.SCROLL_STATE_IDLE) {
+
+ // Otherwise if the {@link ViewPager} is idle now, a page has been selected and
+ // scrolled into place. Perform an animation of the tab carousel is needed.
+ int currentPageIndex = mViewPager.getCurrentItem();
+ int tabCarouselOffset = (int) mTabCarousel.getY();
+ boolean shouldAnimateTabCarousel;
+
+ // Find the offset position of the first item in the list of the current page.
+ int listOffset = getOffsetOfFirstItemInList(currentPageIndex);
+
+ // If the list was able to successfully offset by the tab carousel amount, then
+ // log this as the new Y coordinate for that page, and no animation is needed.
+ if (listOffset == tabCarouselOffset) {
+ mTabCarousel.storeYCoordinate(currentPageIndex, tabCarouselOffset);
+ shouldAnimateTabCarousel = false;
+ } else if (listOffset == Integer.MIN_VALUE) {
+ // If the offset of the first item in the list is unknown (i.e. the item
+ // is no longer visible on screen) then just animate the tab carousel to the
+ // previously logged position.
+ shouldAnimateTabCarousel = true;
+ } else if (Math.abs(listOffset) < Math.abs(tabCarouselOffset)) {
+ // If the list could not offset the full amount of the tab carousel offset (i.e.
+ // the list can only be scrolled a tiny amount), then animate the carousel down
+ // to compensate.
+ mTabCarousel.storeYCoordinate(currentPageIndex, listOffset);
+ shouldAnimateTabCarousel = true;
+ } else {
+ // By default, animate back to the Y coordinate of the tab carousel the last
+ // time the other page was selected.
+ shouldAnimateTabCarousel = true;
+ }
+
+ if (shouldAnimateTabCarousel) {
+ float desiredOffset = mTabCarousel.getStoredYCoordinateForTab(currentPageIndex);
+ if (desiredOffset != tabCarouselOffset) {
+ createTabCarouselAnimator(desiredOffset);
+ mTabCarouselAnimator.start();
+ }
+ }
+ }
+ mViewPagerState = state;
+ }
+
+ private void createTabCarouselAnimator(float desiredValue) {
+ mTabCarouselAnimator = ObjectAnimator.ofFloat(
+ mTabCarousel, "y", desiredValue).setDuration(75);
+ mTabCarouselAnimator.setInterpolator(AnimationUtils.loadInterpolator(
+ mContext, android.R.anim.accelerate_decelerate_interpolator));
+ }
+
+ private void cancelTabCarouselAnimator() {
+ if (mTabCarouselAnimator != null) {
+ mTabCarouselAnimator.cancel();
+ mTabCarouselAnimator = null;
+ }
+ }
};
- private ContactDetailTabCarousel.Listener mTabCarouselListener =
+ private void syncScrollStateBetweenLists(int currentPageIndex) {
+ // Since the user interacted with the currently visible page, we need to sync the
+ // list on the other page (i.e. if the updates page is the current page, modify the
+ // list in the details page).
+ if (currentPageIndex == TAB_INDEX_UPDATES) {
+ mDetailFragment.requestToMoveToOffset((int) mTabCarousel.getY());
+ } else {
+ mUpdatesFragment.requestToMoveToOffset((int) mTabCarousel.getY());
+ }
+ }
+
+ private int getOffsetOfFirstItemInList(int currentPageIndex) {
+ if (currentPageIndex == TAB_INDEX_DETAIL) {
+ return mDetailFragment.getFirstListItemOffset();
+ } else {
+ return mUpdatesFragment.getFirstListItemOffset();
+ }
+ }
+
+ private final ContactDetailTabCarousel.Listener mTabCarouselListener =
new ContactDetailTabCarousel.Listener() {
@Override
@@ -385,4 +485,52 @@
mViewPager.setCurrentItem(position);
}
};
+
+ private final class VerticalScrollListener implements OnScrollListener {
+
+ private final int mPageIndex;
+
+ public VerticalScrollListener(int pageIndex) {
+ mPageIndex = pageIndex;
+ }
+
+ @Override
+ public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
+ int totalItemCount) {
+ int currentPageIndex = mViewPager.getCurrentItem();
+ // Don't move the carousel if: 1) the contact does not have social updates because then
+ // tab carousel must not be visible, 2) if the view pager is still being scrolled, or
+ // 3) if the current page being viewed is not this one.
+ if (!mContactHasUpdates || mViewPagerState != ViewPager.SCROLL_STATE_IDLE ||
+ mPageIndex != currentPageIndex) {
+ return;
+ }
+ // If the FIRST item is not visible on the screen, then the carousel must be pinned
+ // at the top of the screen.
+ if (firstVisibleItem != 0) {
+ mTabCarousel.moveToYCoordinate(mPageIndex,
+ -mTabCarousel.getAllowedVerticalScrollLength());
+ return;
+ }
+ View topView = view.getChildAt(firstVisibleItem);
+ if (topView == null) {
+ return;
+ }
+ int amtToScroll = Math.max((int) view.getChildAt(firstVisibleItem).getY(),
+ -mTabCarousel.getAllowedVerticalScrollLength());
+ mTabCarousel.moveToYCoordinate(mPageIndex, amtToScroll);
+ }
+
+ @Override
+ public void onScrollStateChanged(AbsListView view, int scrollState) {
+ // Once the list has become IDLE, check if we need to sync the scroll position of
+ // the other list now. This will make swiping faster by doing the re-layout now
+ // (instead of at the start of a swipe). However, there will still be another check
+ // when we start swiping if the scroll positions are correct (to catch the edge case
+ // where the user flings and immediately starts a swipe so we never get the idle state).
+ if (scrollState == SCROLL_STATE_IDLE) {
+ syncScrollStateBetweenLists(mPageIndex);
+ }
+ }
+ }
}
diff --git a/src/com/android/contacts/detail/ContactDetailTabCarousel.java b/src/com/android/contacts/detail/ContactDetailTabCarousel.java
index bb30f7e..8a51d81 100644
--- a/src/com/android/contacts/detail/ContactDetailTabCarousel.java
+++ b/src/com/android/contacts/detail/ContactDetailTabCarousel.java
@@ -24,7 +24,6 @@
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
-import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
@@ -59,6 +58,9 @@
private CarouselTab mAboutTab;
private CarouselTab mUpdatesTab;
+ /** Last Y coordinate of the carousel when the tab at the given index was selected */
+ private final float[] mYCoordinateArray = new float[TAB_COUNT];
+
private int mTabDisplayLabelHeight;
private int mLastScrollPosition;
@@ -172,6 +174,39 @@
}
/**
+ * Restore the Y position of this view to the last manually requested value. This can be done
+ * after the parent has been re-laid out again, where this view's position could have been
+ * lost if the view laid outside its parent's bounds.
+ */
+ public void restoreYCoordinate() {
+ setY(getStoredYCoordinateForTab(mCurrentTab));
+ }
+
+ /**
+ * Request that the view move to the given Y coordinate. Also store the Y coordinate as the
+ * last requested Y coordinate for the given tabIndex.
+ */
+ public void moveToYCoordinate(int tabIndex, float y) {
+ setY(y);
+ storeYCoordinate(tabIndex, y);
+ }
+
+ /**
+ * Store this information as the last requested Y coordinate for the given tabIndex.
+ */
+ public void storeYCoordinate(int tabIndex, float y) {
+ mYCoordinateArray[tabIndex] = y;
+ }
+
+ /**
+ * Returns the stored Y coordinate of this view the last time the user was on the selected
+ * tab given by tabIndex.
+ */
+ public float getStoredYCoordinateForTab(int tabIndex) {
+ return mYCoordinateArray[tabIndex];
+ }
+
+ /**
* Returns the number of pixels that this view can be scrolled horizontally.
*/
public int getAllowedHorizontalScrollLength() {
diff --git a/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java b/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
index 99766f2..afe159b 100644
--- a/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
@@ -23,7 +23,6 @@
import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
import com.android.contacts.util.StreamItemEntry;
-import com.android.contacts.util.StreamItemPhotoEntry;
import android.app.ListFragment;
import android.content.ContentUris;
@@ -31,12 +30,12 @@
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract.StreamItems;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AbsListView.OnScrollListener;
+import android.widget.ListView;
public class ContactDetailUpdatesFragment extends ListFragment
implements FragmentKeyListener, ViewOverlay {
@@ -194,4 +193,22 @@
mVerticalScrollListener = listener;
}
+ /**
+ * Returns the top coordinate of the first item in the {@link ListView}. If the first item
+ * in the {@link ListView} is not visible or there are no children in the list, then return
+ * Integer.MIN_VALUE. Note that the returned value will be <= 0 because the first item in the
+ * list cannot have a positive offset.
+ */
+ public int getFirstListItemOffset() {
+ return ContactDetailDisplayUtils.getFirstListItemOffset(getListView());
+ }
+
+ /**
+ * Tries to scroll the first item to the given offset (this can be a no-op if the list is
+ * already in the correct position).
+ * @param offset which should be <= 0
+ */
+ public void requestToMoveToOffset(int offset) {
+ ContactDetailDisplayUtils.requestToMoveToOffset(getListView(), offset);
+ }
}
diff --git a/src/com/android/contacts/detail/ContactDetailViewPagerAdapter.java b/src/com/android/contacts/detail/ContactDetailViewPagerAdapter.java
index 40e391d..e0ed5e9 100644
--- a/src/com/android/contacts/detail/ContactDetailViewPagerAdapter.java
+++ b/src/com/android/contacts/detail/ContactDetailViewPagerAdapter.java
@@ -36,17 +36,17 @@
private int mFragmentViewCount = MAX_FRAGMENT_VIEW_COUNT;
- private ViewGroup mAboutFragmentView;
- private ViewGroup mUpdatesFragmentView;
+ private View mAboutFragmentView;
+ private View mUpdatesFragmentView;
public ContactDetailViewPagerAdapter() {
}
- public void setAboutFragmentView(ViewGroup view) {
+ public void setAboutFragmentView(View view) {
mAboutFragmentView = view;
}
- public void setUpdatesFragmentView(ViewGroup view) {
+ public void setUpdatesFragmentView(View view) {
mUpdatesFragmentView = view;
}
diff --git a/src/com/android/contacts/detail/TabCarouselScrollManager.java b/src/com/android/contacts/detail/TabCarouselScrollManager.java
deleted file mode 100644
index 2415b50..0000000
--- a/src/com/android/contacts/detail/TabCarouselScrollManager.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.contacts.detail;
-
-import android.view.View;
-import android.widget.AbsListView;
-import android.widget.AbsListView.OnScrollListener;
-
-/**
- * Takes care of managing scrolling for the side-by-side views using the tab carousel.
- */
-public class TabCarouselScrollManager {
- private final ContactDetailTabCarousel mTabCarousel;
- private final ContactDetailFragment mAboutFragment;
- private final ContactDetailUpdatesFragment mUpdatesFragment;
- private final OnScrollListener mVerticalScrollListener = new OnScrollListener() {
- @Override
- public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
- int totalItemCount) {
- if (mTabCarousel == null) {
- return;
- }
- // If the FIRST item is not visible on the screen, then the carousel must be pinned
- // at the top of the screen.
- if (firstVisibleItem != 0) {
- mTabCarousel.setY(-mTabCarousel.getAllowedVerticalScrollLength());
- return;
- }
- View topView = view.getChildAt(firstVisibleItem);
- if (topView == null) {
- return;
- }
- int amtToScroll = Math.max((int) view.getChildAt(firstVisibleItem).getY(),
- -mTabCarousel.getAllowedVerticalScrollLength());
- mTabCarousel.setY(amtToScroll);
- }
-
- @Override
- public void onScrollStateChanged(AbsListView view, int scrollState) {}
- };
-
- private TabCarouselScrollManager(ContactDetailTabCarousel tabCarousel,
- ContactDetailFragment aboutFragment, ContactDetailUpdatesFragment updatesFragment) {
- mTabCarousel = tabCarousel;
- mAboutFragment = aboutFragment;
- mUpdatesFragment = updatesFragment;
- }
-
- public void bind() {
- mAboutFragment.setVerticalScrollListener(mVerticalScrollListener);
- mUpdatesFragment.setVerticalScrollListener(mVerticalScrollListener);
- }
-
- public static void bind(ContactDetailTabCarousel tabCarousel,
- ContactDetailFragment aboutFragment, ContactDetailUpdatesFragment updatesFragment) {
- TabCarouselScrollManager scrollManager =
- new TabCarouselScrollManager(tabCarousel, aboutFragment, updatesFragment);
- scrollManager.bind();
- }
-}