Add alpha layer to tab carousel on contact card
- Introduce CarouselTab class to handle the
alpha layer and touch interceptor
- Clicking anywhere on the tab will select that
tab
- Remove split style action bar on contact card
so favorites star will be in upper right corner
Bug: 5081735
Bug: 5042660
Change-Id: I54088b49c928297dbfc523752258ceaa97cce445
diff --git a/res/layout/carousel_about_tab.xml b/res/layout/carousel_about_tab.xml
index dfcf0da..e902c8e 100644
--- a/res/layout/carousel_about_tab.xml
+++ b/res/layout/carousel_about_tab.xml
@@ -14,8 +14,9 @@
limitations under the License.
-->
-<RelativeLayout
+<view
xmlns:android="http://schemas.android.com/apk/res/android"
+ class="com.android.contacts.detail.CarouselTab"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -51,4 +52,22 @@
android:textColor="@color/detail_tab_carousel_tab_label_color"
style="@android:style/Widget.Holo.ActionBar.TabView" />
-</RelativeLayout>
+ <View
+ android:id="@+id/alpha_overlay"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:background="@android:color/black"
+ android:alpha="0"
+ android:visibility="gone"/>
+
+ <View
+ android:id="@+id/touch_intercept_overlay"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:background="?android:attr/selectableItemBackground"
+ android:visibility="gone"/>
+</view>
diff --git a/res/layout/carousel_updates_tab.xml b/res/layout/carousel_updates_tab.xml
index b036523..689e17b 100644
--- a/res/layout/carousel_updates_tab.xml
+++ b/res/layout/carousel_updates_tab.xml
@@ -14,8 +14,13 @@
limitations under the License.
-->
-<RelativeLayout
+<!--
+ TODO: Collapse carousel_about_tab with carousel_updates_tab into 1 XML that
+ handles all cases when updates fragment is more finalized.
+-->
+<view
xmlns:android="http://schemas.android.com/apk/res/android"
+ class="com.android.contacts.detail.CarouselTab"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -68,4 +73,23 @@
android:textStyle="bold"
android:maxLines="3"/>
-</RelativeLayout>
+ <View
+ android:id="@+id/alpha_overlay"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:background="@android:color/black"
+ android:alpha="0"
+ android:visibility="gone"/>
+
+ <View
+ android:id="@+id/touch_intercept_overlay"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:background="?android:attr/selectableItemBackground"
+ android:visibility="gone"/>
+
+</view>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index e98175d..c23d99d 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -73,7 +73,7 @@
<item name="call_log_voicemail_status_text_color">#000000</item>
</style>
- <style name="ContactDetailActivityTheme" parent="@android:style/Theme.Holo.Light.SolidActionBar.Inverse.SplitActionBarWhenNarrow">
+ <style name="ContactDetailActivityTheme" parent="@android:style/Theme.Holo.Light.SolidActionBar.Inverse">
<item name="android:actionBarStyle">@style/ContactsActionBarStyle</item>
<item name="android:windowContentOverlay">@null</item>
</style>
diff --git a/src/com/android/contacts/detail/CarouselTab.java b/src/com/android/contacts/detail/CarouselTab.java
new file mode 100644
index 0000000..9b8efd5
--- /dev/null
+++ b/src/com/android/contacts/detail/CarouselTab.java
@@ -0,0 +1,101 @@
+/*
+ * 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 com.android.contacts.R;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+/**
+ * This is a tab in the {@link ContactDetailTabCarousel}.
+ */
+public class CarouselTab extends RelativeLayout implements ViewOverlay {
+
+ private static final String TAG = CarouselTab.class.getSimpleName();
+
+ private TextView mLabelView;
+
+ /**
+ * This view adds an alpha layer over the entire tab.
+ */
+ private View mAlphaLayer;
+
+ /**
+ * This view adds a layer over the entire tab so that when visible, it intercepts all touch
+ * events on the tab.
+ */
+ private View mTouchInterceptLayer;
+
+ public CarouselTab(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ mLabelView = (TextView) findViewById(R.id.label);
+ mLabelView.setClickable(true);
+
+ mAlphaLayer = findViewById(R.id.alpha_overlay);
+ mTouchInterceptLayer = findViewById(R.id.touch_intercept_overlay);
+ }
+
+ public void setLabel(String label) {
+ mLabelView.setText(label);
+ }
+
+ public void showSelectedState() {
+ mLabelView.setSelected(true);
+ }
+
+ public void showDeselectedState() {
+ mLabelView.setSelected(false);
+ }
+
+ @Override
+ public void disableTouchInterceptor() {
+ // This shouldn't be called because there is no need to disable the touch interceptor if
+ // there is no content within the tab that needs to be clicked.
+ }
+
+ @Override
+ public void enableAlphaLayer() {
+ if (mAlphaLayer != null) {
+ mAlphaLayer.setVisibility(View.VISIBLE);
+ }
+ }
+
+ @Override
+ public void enableTouchInterceptor(OnClickListener clickListener) {
+ if (mTouchInterceptLayer != null) {
+ mTouchInterceptLayer.setVisibility(View.VISIBLE);
+ mTouchInterceptLayer.setOnClickListener(clickListener);
+ }
+ }
+
+ @Override
+ public void setAlphaLayerValue(float alpha) {
+ if (mAlphaLayer != null) {
+ mAlphaLayer.setAlpha(alpha);
+ }
+ }
+}
diff --git a/src/com/android/contacts/detail/ContactDetailFragment.java b/src/com/android/contacts/detail/ContactDetailFragment.java
index 1dae19f..41324f8 100644
--- a/src/com/android/contacts/detail/ContactDetailFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailFragment.java
@@ -116,7 +116,7 @@
import java.util.List;
import java.util.Map;
-public class ContactDetailFragment extends Fragment implements FragmentKeyListener, FragmentOverlay,
+public class ContactDetailFragment extends Fragment implements FragmentKeyListener, ViewOverlay,
OnItemClickListener, SelectAccountDialogFragment.Listener {
private static final String TAG = "ContactDetailFragment";
diff --git a/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java b/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java
index da64c34..95cf055 100644
--- a/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java
+++ b/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java
@@ -46,8 +46,8 @@
private int mCurrentPage = ABOUT_PAGE;
private int mLastScrollPosition;
- private FragmentOverlay mAboutFragment;
- private FragmentOverlay mUpdatesFragment;
+ private ViewOverlay mAboutFragment;
+ private ViewOverlay mUpdatesFragment;
private static final float MAX_ALPHA = 0.5f;
@@ -69,7 +69,7 @@
setOnTouchListener(this);
}
- public void setAboutFragment(FragmentOverlay fragment) {
+ public void setAboutFragment(ViewOverlay fragment) {
// TODO: We can't always assume the "about" page will be the current page.
mAboutFragment = fragment;
mAboutFragment.enableAlphaLayer();
@@ -77,7 +77,7 @@
mAboutFragment.disableTouchInterceptor();
}
- public void setUpdatesFragment(FragmentOverlay fragment) {
+ public void setUpdatesFragment(ViewOverlay fragment) {
mUpdatesFragment = fragment;
mUpdatesFragment.enableAlphaLayer();
mUpdatesFragment.setAlphaLayerValue(MAX_ALPHA);
diff --git a/src/com/android/contacts/detail/ContactDetailTabCarousel.java b/src/com/android/contacts/detail/ContactDetailTabCarousel.java
index 26987f6..79ac5fb 100644
--- a/src/com/android/contacts/detail/ContactDetailTabCarousel.java
+++ b/src/com/android/contacts/detail/ContactDetailTabCarousel.java
@@ -24,6 +24,7 @@
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;
@@ -49,15 +50,22 @@
private Listener mListener;
- private final View[] mTabs = new View[TAB_COUNT];
+ private int mCurrentTab = TAB_INDEX_ABOUT;
+
+ private CarouselTab mAboutTab;
+ private CarouselTab mUpdatesTab;
private int mTabWidth;
private int mTabHeight;
private int mTabDisplayLabelHeight;
+ private int mLastScrollPosition;
+
private int mAllowedHorizontalScrollLength = Integer.MIN_VALUE;
private int mAllowedVerticalScrollLength = Integer.MIN_VALUE;
+ private static final float MAX_ALPHA = 0.5f;
+
/**
* Interface for callbacks invoked when the user interacts with the carousel.
*/
@@ -83,40 +91,28 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- View aboutView = findViewById(R.id.tab_about);
- View updateView = findViewById(R.id.tab_update);
+ mAboutTab = (CarouselTab) findViewById(R.id.tab_about);
+ mAboutTab.setLabel(mContext.getString(R.string.contactDetailAbout));
- TextView aboutTab = (TextView) aboutView.findViewById(R.id.label);
- aboutTab.setText(mContext.getString(R.string.contactDetailAbout));
- aboutTab.setClickable(true);
- aboutTab.setSelected(true);
+ mUpdatesTab = (CarouselTab) findViewById(R.id.tab_update);
+ mUpdatesTab.setLabel(mContext.getString(R.string.contactDetailUpdates));
- TextView updatesTab = (TextView) updateView.findViewById(R.id.label);
- updatesTab.setText(mContext.getString(R.string.contactDetailUpdates));
- updatesTab.setClickable(true);
+ // TODO: We can't always assume the "about" page will be the current page.
+ mAboutTab.showSelectedState();
+ mAboutTab.enableAlphaLayer();
+ mAboutTab.setAlphaLayerValue(0);
+ mAboutTab.enableTouchInterceptor(mAboutTabTouchInterceptListener);
- aboutTab.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- mListener.onTabSelected(TAB_INDEX_ABOUT);
- }
- });
- updatesTab.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- mListener.onTabSelected(TAB_INDEX_ABOUT);
- }
- });
-
- mTabs[TAB_INDEX_ABOUT] = aboutTab;
- mTabs[TAB_INDEX_UPDATES] = updatesTab;
+ mUpdatesTab.enableAlphaLayer();
+ mUpdatesTab.setAlphaLayerValue(MAX_ALPHA);
+ mUpdatesTab.enableTouchInterceptor(mUpdatesTabTouchInterceptListener);
// Retrieve the photo view for the "about" tab
- mPhotoView = (ImageView) aboutView.findViewById(R.id.photo);
+ mPhotoView = (ImageView) mAboutTab.findViewById(R.id.photo);
// Retrieve the social update views for the "updates" tab
- mStatusView = (TextView) updateView.findViewById(R.id.status);
- mStatusPhotoView = (ImageView) updateView.findViewById(R.id.status_photo);
+ mStatusView = (TextView) mUpdatesTab.findViewById(R.id.status);
+ mStatusPhotoView = (ImageView) mUpdatesTab.findViewById(R.id.status_photo);
}
@Override
@@ -143,10 +139,33 @@
}
}
+ private final OnClickListener mAboutTabTouchInterceptListener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mListener.onTabSelected(TAB_INDEX_ABOUT);
+ }
+ };
+
+ private final OnClickListener mUpdatesTabTouchInterceptListener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mListener.onTabSelected(TAB_INDEX_UPDATES);
+ }
+ };
+
+ private void updateAlphaLayers() {
+ mAboutTab.setAlphaLayerValue(mLastScrollPosition * MAX_ALPHA /
+ mAllowedHorizontalScrollLength);
+ mUpdatesTab.setAlphaLayerValue(MAX_ALPHA - mLastScrollPosition * MAX_ALPHA /
+ mAllowedVerticalScrollLength);
+ }
+
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
mListener.onScrollChanged(l, t, oldl, oldt);
+ mLastScrollPosition = l;
+ updateAlphaLayers();
}
/**
@@ -168,24 +187,21 @@
* Updates the tab selection.
*/
public void setCurrentTab(int position) {
- if (position < 0 || position > mTabs.length) {
- throw new IllegalStateException("Invalid position in array of tabs: " + position);
- }
// TODO: Handle device rotation (saving and restoring state of the selected tab)
// This will take more work because there is no tab carousel in phone landscape
- if (mTabs[position] == null) {
- return;
+ switch (position) {
+ case TAB_INDEX_ABOUT:
+ mAboutTab.showSelectedState();
+ mUpdatesTab.showDeselectedState();
+ break;
+ case TAB_INDEX_UPDATES:
+ mUpdatesTab.showSelectedState();
+ mAboutTab.showDeselectedState();
+ break;
+ default:
+ throw new IllegalStateException("Invalid tab position " + position);
}
- mTabs[position].setSelected(true);
- unselectAllOtherTabs(position);
- }
-
- private void unselectAllOtherTabs(int position) {
- for (int i = 0; i < mTabs.length; i++) {
- if (position != i) {
- mTabs[i].setSelected(false);
- }
- }
+ mCurrentTab = position;
}
/**
@@ -197,6 +213,8 @@
return;
}
+ // TODO: Move this into the {@link CarouselTab} class when the updates fragment code is more
+ // finalized
ContactDetailDisplayUtils.setPhoto(mContext, contactData, mPhotoView);
ContactDetailDisplayUtils.setSocialSnippet(mContext, contactData, mStatusView,
mStatusPhotoView);
diff --git a/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java b/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
index daeae00..602958d 100644
--- a/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
@@ -31,7 +31,7 @@
import android.widget.TextView;
public class ContactDetailUpdatesFragment extends Fragment
- implements FragmentKeyListener, FragmentOverlay {
+ implements FragmentKeyListener, ViewOverlay {
private static final String TAG = "ContactDetailUpdatesFragment";
diff --git a/src/com/android/contacts/detail/FragmentOverlay.java b/src/com/android/contacts/detail/ViewOverlay.java
similarity index 88%
rename from src/com/android/contacts/detail/FragmentOverlay.java
rename to src/com/android/contacts/detail/ViewOverlay.java
index 6ef0846..4c14460 100644
--- a/src/com/android/contacts/detail/FragmentOverlay.java
+++ b/src/com/android/contacts/detail/ViewOverlay.java
@@ -19,12 +19,12 @@
import android.view.View.OnClickListener;
/**
- * This is implemented by {@link Fragment}s that contain an alpha layer and touch interceptor layer.
+ * This is implemented by {@link View}s that contain an alpha layer and touch interceptor layer.
* The alpha layer covers the entire fragment and has an alpha value which makes the fragment
* contents appear "dimmed" out. The touch interceptor layer covers the entire fragment so that
- * when visible, it intercepts all touch events on the {@link Fragment}.
+ * when visible, it intercepts all touch events on the {@link View}.
*/
-public interface FragmentOverlay {
+public interface ViewOverlay {
/**
* Sets the alpha value on the alpha layer (if there is one).