diff options
-rw-r--r-- | res/drawable-hdpi/ic_arrow.png | bin | 0 -> 852 bytes | |||
-rw-r--r-- | res/drawable-hdpi/ic_cancel_holo_light.png | bin | 0 -> 393 bytes | |||
-rw-r--r-- | res/drawable-mdpi/ic_arrow.png | bin | 0 -> 697 bytes | |||
-rw-r--r-- | res/drawable-mdpi/ic_cancel_holo_light.png | bin | 0 -> 312 bytes | |||
-rw-r--r-- | res/drawable-xhdpi/ic_arrow.png | bin | 0 -> 1017 bytes | |||
-rw-r--r-- | res/drawable-xhdpi/ic_cancel_holo_light.png | bin | 0 -> 1477 bytes | |||
-rw-r--r-- | res/drawable-xxhdpi/ic_arrow.png | bin | 0 -> 1506 bytes | |||
-rw-r--r-- | res/drawable-xxhdpi/ic_cancel_holo_light.png | bin | 0 -> 1637 bytes | |||
-rw-r--r-- | res/layout/tile_interactions_teaser_view.xml | 63 | ||||
-rw-r--r-- | res/values/dimens.xml | 4 | ||||
-rw-r--r-- | res/values/styles.xml | 5 | ||||
-rw-r--r-- | src/com/android/dialer/list/PhoneFavoriteFragment.java | 9 | ||||
-rw-r--r-- | src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java | 63 | ||||
-rw-r--r-- | src/com/android/dialer/list/PhoneFavoritesTileAdapter.java | 6 | ||||
-rw-r--r-- | src/com/android/dialer/list/TileInteractionTeaserView.java | 153 |
15 files changed, 288 insertions, 15 deletions
diff --git a/res/drawable-hdpi/ic_arrow.png b/res/drawable-hdpi/ic_arrow.png Binary files differnew file mode 100644 index 000000000..8d0dfcd47 --- /dev/null +++ b/res/drawable-hdpi/ic_arrow.png diff --git a/res/drawable-hdpi/ic_cancel_holo_light.png b/res/drawable-hdpi/ic_cancel_holo_light.png Binary files differnew file mode 100644 index 000000000..d8cacb44a --- /dev/null +++ b/res/drawable-hdpi/ic_cancel_holo_light.png diff --git a/res/drawable-mdpi/ic_arrow.png b/res/drawable-mdpi/ic_arrow.png Binary files differnew file mode 100644 index 000000000..96440a2be --- /dev/null +++ b/res/drawable-mdpi/ic_arrow.png diff --git a/res/drawable-mdpi/ic_cancel_holo_light.png b/res/drawable-mdpi/ic_cancel_holo_light.png Binary files differnew file mode 100644 index 000000000..56705c333 --- /dev/null +++ b/res/drawable-mdpi/ic_cancel_holo_light.png diff --git a/res/drawable-xhdpi/ic_arrow.png b/res/drawable-xhdpi/ic_arrow.png Binary files differnew file mode 100644 index 000000000..889c33fce --- /dev/null +++ b/res/drawable-xhdpi/ic_arrow.png diff --git a/res/drawable-xhdpi/ic_cancel_holo_light.png b/res/drawable-xhdpi/ic_cancel_holo_light.png Binary files differnew file mode 100644 index 000000000..630f3fd4c --- /dev/null +++ b/res/drawable-xhdpi/ic_cancel_holo_light.png diff --git a/res/drawable-xxhdpi/ic_arrow.png b/res/drawable-xxhdpi/ic_arrow.png Binary files differnew file mode 100644 index 000000000..f8e7731d4 --- /dev/null +++ b/res/drawable-xxhdpi/ic_arrow.png diff --git a/res/drawable-xxhdpi/ic_cancel_holo_light.png b/res/drawable-xxhdpi/ic_cancel_holo_light.png Binary files differnew file mode 100644 index 000000000..c2f5b5e1c --- /dev/null +++ b/res/drawable-xxhdpi/ic_cancel_holo_light.png diff --git a/res/layout/tile_interactions_teaser_view.xml b/res/layout/tile_interactions_teaser_view.xml new file mode 100644 index 000000000..ee2b97495 --- /dev/null +++ b/res/layout/tile_interactions_teaser_view.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (c) 2013 Google Inc. --> +<com.android.dialer.list.TileInteractionTeaserView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@color/actionbar_background_color" + android:paddingBottom="@dimen/favorites_row_bottom_padding" + android:paddingTop="@dimen/favorites_row_top_padding"> + + <LinearLayout + android:id="@+id/swipeable_content" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="horizontal" > + + <ImageView + android:id="@+id/arrow" + android:layout_width="48dp" + android:layout_height="match_parent" + android:layout_marginBottom="12dp" + android:layout_marginLeft="16dp" + android:layout_marginRight="12dp" + android:duplicateParentState="true" + android:src="@drawable/ic_arrow" + android:visibility="invisible" /> + + <TextView + android:id="@+id/text" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_marginBottom="12dp" + android:layout_marginTop="12dp" + android:layout_weight="1" + android:duplicateParentState="true" + android:fontFamily="sans-serif-light" + android:text="@string/contact_tooltip" + android:textColor="@color/undo_dialogue_text_color" + android:textSize="16sp" /> + + <View + android:id="@+id/dismiss_separator" + android:layout_width="1dip" + android:layout_height="match_parent" + android:background="@color/undo_dialogue_text_color" + android:layout_marginTop="16dp" + android:layout_marginBottom="16dp" + android:layout_marginLeft="16dp"/> + + <ImageButton + android:id="@+id/dismiss_button" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:background="?android:attr/selectableItemBackground" + android:clickable="true" + android:scaleType="center" + android:src="@drawable/ic_cancel_holo_light" + style="@style/DismissButtonStyle" /> + + </LinearLayout> + +</com.android.dialer.list.TileInteractionTeaserView> diff --git a/res/values/dimens.xml b/res/values/dimens.xml index d1052d5c7..30adc43ed 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -73,4 +73,8 @@ <dimen name="favorites_row_end_padding">8dp</dimen> <dimen name="favorites_row_undo_text_side_padding">32dp</dimen> <dimen name="recent_call_log_item_padding">8dp</dimen> + + <!-- Padding for the tooltip --> + <dimen name="dismiss_button_padding_start">20dip</dimen> + <dimen name="dismiss_button_padding_end">28dip</dimen> </resources> diff --git a/res/values/styles.xml b/res/values/styles.xml index 791adf696..4e918975d 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -145,4 +145,9 @@ <item name="android:background">@null</item> <item name="android:textColorHint">@color/searchbox_text_color</item> </style> + + <style name="DismissButtonStyle"> + <item name="android:paddingLeft">@dimen/dismiss_button_padding_start</item> + <item name="android:paddingRight">@dimen/dismiss_button_padding_end</item> + </style> </resources> diff --git a/src/com/android/dialer/list/PhoneFavoriteFragment.java b/src/com/android/dialer/list/PhoneFavoriteFragment.java index 7e8ff0f59..73703a02c 100644 --- a/src/com/android/dialer/list/PhoneFavoriteFragment.java +++ b/src/com/android/dialer/list/PhoneFavoriteFragment.java @@ -199,6 +199,8 @@ public class PhoneFavoriteFragment extends Fragment implements OnItemClickListen private View mShowAllContactsInEmptyViewButton; private View mContactTileFrame; + private TileInteractionTeaserView mTileInteractionTeaserView; + private final HashMap<Long, Integer> mItemIdTopMap = new HashMap<Long, Integer>(); private final HashMap<Long, Integer> mItemIdLeftMap = new HashMap<Long, Integer>(); @@ -306,8 +308,13 @@ public class PhoneFavoriteFragment extends Fragment implements OnItemClickListen mContactTileFrame = mParentView.findViewById(R.id.contact_tile_frame); + mTileInteractionTeaserView = (TileInteractionTeaserView) inflater.inflate( + R.layout.tile_interactions_teaser_view, mListView, false); + mAdapter = new PhoneFavoriteMergedAdapter(getActivity(), this, mContactTileAdapter, - mCallLogAdapter, mShowAllContactsButton); + mCallLogAdapter, mShowAllContactsButton, mTileInteractionTeaserView); + + mTileInteractionTeaserView.setAdapter(mAdapter); mListView.setAdapter(mAdapter); diff --git a/src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java b/src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java index 1f577c194..daba39e6d 100644 --- a/src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java +++ b/src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java @@ -49,11 +49,14 @@ public class PhoneFavoriteMergedAdapter extends BaseAdapter { private static final String TAG = PhoneFavoriteMergedAdapter.class.getSimpleName(); + private static final int TILE_INTERACTION_TEASER_VIEW_POSITION = 2; + private static final int TILE_INTERACTION_TEASER_VIEW_ID = -2; private static final int ALL_CONTACTS_BUTTON_ITEM_ID = -1; private final PhoneFavoritesTileAdapter mContactTileAdapter; private final CallLogAdapter mCallLogAdapter; private final View mShowAllContactsButton; private final PhoneFavoriteFragment mFragment; + private final TileInteractionTeaserView mTileInteractionTeaserView; private final int mCallLogPadding; @@ -100,7 +103,8 @@ public class PhoneFavoriteMergedAdapter extends BaseAdapter { PhoneFavoriteFragment fragment, PhoneFavoritesTileAdapter contactTileAdapter, CallLogAdapter callLogAdapter, - View showAllContactsButton) { + View showAllContactsButton, + TileInteractionTeaserView tileInteractionTeaserView) { final Resources resources = context.getResources(); mContext = context; mFragment = fragment; @@ -111,6 +115,7 @@ public class PhoneFavoriteMergedAdapter extends BaseAdapter { mCallLogAdapter.registerDataSetObserver(mObserver); mContactTileAdapter.registerDataSetObserver(mObserver); mShowAllContactsButton = showAllContactsButton; + mTileInteractionTeaserView = tileInteractionTeaserView; mCallLogQueryHandler = new CallLogQueryHandler(mContext.getContentResolver(), mCallLogQueryHandlerListener); } @@ -118,7 +123,8 @@ public class PhoneFavoriteMergedAdapter extends BaseAdapter { @Override public int getCount() { if (mContactTileAdapter.getCount() > 0) { - return mContactTileAdapter.getCount() + mCallLogAdapter.getCount() + 1; + return mContactTileAdapter.getCount() + mCallLogAdapter.getCount() + 1 + + getTeaserViewCount(); } else { return mCallLogAdapter.getCount(); } @@ -132,9 +138,10 @@ public class PhoneFavoriteMergedAdapter extends BaseAdapter { if (position < callLogAdapterCount) { return mCallLogAdapter.getItem(position); } - // Set position to the position of the actual favorite contact in the favorites adapter - position = getAdjustedFavoritePosition(position, callLogAdapterCount); } + // Set position to the position of the actual favorite contact in the favorites adapter + position = getAdjustedFavoritePosition(position, callLogAdapterCount); + return mContactTileAdapter.getItem(position); } @@ -144,7 +151,8 @@ public class PhoneFavoriteMergedAdapter extends BaseAdapter { * * These are the ranges of IDs reserved for each item type. * - * -(N + 1) to -2: CallLogAdapterItems, where N is equal to the number of call log items + * -(N + 1) to -3: CallLogAdapterItems, where N is equal to the number of call log items + * -2: Teaser * -1: All contacts button * 0 to (N -1): Rows of tiled contacts, where N is equal to the max rows of tiled contacts * N to infinity: Rows of regular contacts. Their item id is calculated by N + contact_id, @@ -155,9 +163,14 @@ public class PhoneFavoriteMergedAdapter extends BaseAdapter { final int callLogAdapterCount = mCallLogAdapter.getCount(); if (position < callLogAdapterCount) { // Call log items are not animated, so reusing their position for IDs is fine. - return ALL_CONTACTS_BUTTON_ITEM_ID - 1 - position; - } else if (position < (callLogAdapterCount + mContactTileAdapter.getCount())) { - return mContactTileAdapter.getItemId(position - callLogAdapterCount); + return ALL_CONTACTS_BUTTON_ITEM_ID - 2 - position; + } else if (position == TILE_INTERACTION_TEASER_VIEW_POSITION + callLogAdapterCount && + mTileInteractionTeaserView.getShouldDisplayInList()){ + return TILE_INTERACTION_TEASER_VIEW_ID; + } else if (position < (callLogAdapterCount + mContactTileAdapter.getCount() + + getTeaserViewCount())) { + return mContactTileAdapter.getItemId( + getAdjustedFavoritePosition(position, callLogAdapterCount)); } else { // All contacts button return ALL_CONTACTS_BUTTON_ITEM_ID; @@ -171,7 +184,10 @@ public class PhoneFavoriteMergedAdapter extends BaseAdapter { @Override public int getViewTypeCount() { - return (mContactTileAdapter.getViewTypeCount() + mCallLogAdapter.getViewTypeCount() + 1); + return (mContactTileAdapter.getViewTypeCount() + /* Favorite and frequent */ + mCallLogAdapter.getViewTypeCount() + /* Recent call log */ + getTeaserViewCount() + /* Teaser */ + 1); /* Show all contacts button. */ } @Override @@ -182,6 +198,10 @@ public class PhoneFavoriteMergedAdapter extends BaseAdapter { // View type of the call log adapter is the last view type of the contact tile adapter // + 1 return mContactTileAdapter.getViewTypeCount(); + } else if (position == TILE_INTERACTION_TEASER_VIEW_POSITION + callLogAdapterCount && + mTileInteractionTeaserView.getShouldDisplayInList()) { + // View type of the teaser row is the last view type of the contact tile adapter + 3 + return mContactTileAdapter.getViewTypeCount() + 2; } else if (position < getCount() - 1) { return mContactTileAdapter.getItemViewType( getAdjustedFavoritePosition(position, callLogAdapterCount)); @@ -200,6 +220,12 @@ public class PhoneFavoriteMergedAdapter extends BaseAdapter { return mShowAllContactsButton; } + if (mTileInteractionTeaserView.getShouldDisplayInList()) { + if (position == TILE_INTERACTION_TEASER_VIEW_POSITION + callLogAdapterCount) { + return mTileInteractionTeaserView; + } + } + if (callLogAdapterCount > 0) { if (position == 0) { final SwipeableCallLogRow wrapper; @@ -224,11 +250,12 @@ public class PhoneFavoriteMergedAdapter extends BaseAdapter { wrapper.addView(view); return wrapper; } - // Set position to the position of the actual favorite contact in the - // favorites adapter - position = getAdjustedFavoritePosition(position, callLogAdapterCount); } + // Set position to the position of the actual favorite contact in the + // favorites adapter + position = getAdjustedFavoritePosition(position, callLogAdapterCount); + // Favorites section final View view = mContactTileAdapter.getView(position, convertView, parent); if (position >= mContactTileAdapter.getMaxTiledRows()) { @@ -259,7 +286,17 @@ public class PhoneFavoriteMergedAdapter extends BaseAdapter { } private int getAdjustedFavoritePosition(int position, int callLogAdapterCount) { - return position - callLogAdapterCount; + if (position - callLogAdapterCount > TILE_INTERACTION_TEASER_VIEW_POSITION && + mTileInteractionTeaserView.getShouldDisplayInList()) { + return position - callLogAdapterCount - 1; + } else { + return position - callLogAdapterCount; + } + } + + private int getTeaserViewCount() { + return (mContactTileAdapter.getCount() > TILE_INTERACTION_TEASER_VIEW_POSITION && + mTileInteractionTeaserView.getShouldDisplayInList() ? 1 : 0); } /** diff --git a/src/com/android/dialer/list/PhoneFavoritesTileAdapter.java b/src/com/android/dialer/list/PhoneFavoritesTileAdapter.java index a4a2cb418..e28fd73f3 100644 --- a/src/com/android/dialer/list/PhoneFavoritesTileAdapter.java +++ b/src/com/android/dialer/list/PhoneFavoritesTileAdapter.java @@ -505,7 +505,11 @@ public class PhoneFavoritesTileAdapter extends BaseAdapter implements int itemViewType = getItemViewType(position); - ContactTileRow contactTileRowView = (ContactTileRow) convertView; + ContactTileRow contactTileRowView = null; + + if (convertView instanceof ContactTileRow) { + contactTileRowView = (ContactTileRow) convertView; + } ArrayList<ContactEntry> contactList = getItem(position); diff --git a/src/com/android/dialer/list/TileInteractionTeaserView.java b/src/com/android/dialer/list/TileInteractionTeaserView.java new file mode 100644 index 000000000..6e70fd186 --- /dev/null +++ b/src/com/android/dialer/list/TileInteractionTeaserView.java @@ -0,0 +1,153 @@ +package com.android.dialer.list; + +import android.animation.Animator; + +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.Resources; +import android.util.AttributeSet; +import android.util.Log; +import android.view.View; +import android.view.animation.DecelerateInterpolator; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.android.dialer.DialtactsActivity; +import com.android.dialer.R; + +/** + * A teaser to introduce people to the contact photo check boxes + */ +public class TileInteractionTeaserView extends FrameLayout { + private static int sShrinkAnimationDuration; + + private static final String KEY_TILE_INTERACTION_TEASER_SHOWN = + "key_tile_interaction_teaser_shown"; + + private boolean mNeedLayout; + private int mTextTop; + private int mAnimatedHeight = -1; + + private PhoneFavoriteMergedAdapter mAdapter; + + public TileInteractionTeaserView(final Context context) { + this(context, null); + } + + public TileInteractionTeaserView(final Context context, final AttributeSet attrs) { + super(context, attrs); + final Resources resources = context.getResources(); + + mNeedLayout = true; + sShrinkAnimationDuration = resources.getInteger(R.integer.escape_animation_duration); + } + + @Override + protected void onFinishInflate() { + findViewById(R.id.dismiss_button).setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + startDestroyAnimation(); + } + }); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + + final TextView text = (TextView) findViewById(R.id.text); + final ImageView arrow = (ImageView) findViewById(R.id.arrow); + + // We post to avoid calling layout within layout + arrow.post(new Runnable() { + @Override + public void run() { + + // The text top is changed when we move the arrow, so we need to + // do multiple passes + int textTop = text.getTop(); + if (mNeedLayout || textTop != mTextTop) { + mNeedLayout = false; + mTextTop = textTop; + + final int lineHeight = text.getLineHeight(); + final LinearLayout.LayoutParams arrowParams = (LinearLayout.LayoutParams) arrow + .getLayoutParams(); + arrowParams.topMargin = mTextTop + lineHeight / 2; + arrow.setLayoutParams(arrowParams); + } + arrow.setVisibility(View.VISIBLE); + } + }); + } + + public boolean getShouldDisplayInList() { + final SharedPreferences prefs = getContext().getSharedPreferences( + DialtactsActivity.SHARED_PREFS_NAME, Context.MODE_PRIVATE); + return prefs.getBoolean(KEY_TILE_INTERACTION_TEASER_SHOWN, true); + } + + public void setAdapter(PhoneFavoriteMergedAdapter adapter) { + mAdapter = adapter; + } + + private void startDestroyAnimation() { + final int start = getHeight(); + final int end = 0; + mAnimatedHeight = start; + Log.v("Interaction", "Start from" + start); + + ValueAnimator heightAnimator = ValueAnimator.ofInt(start, end); + heightAnimator.setDuration(sShrinkAnimationDuration); + heightAnimator.setInterpolator(new DecelerateInterpolator(2.0f)); + heightAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + public void onAnimationUpdate(ValueAnimator animation) { + mAnimatedHeight = (Integer) animation.getAnimatedValue(); + requestLayout(); + } + }); + heightAnimator.addListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animator) { + } + + @Override + public void onAnimationEnd(Animator animator) { + setVisibility(GONE); + setDismissed(); + if (mAdapter != null) { + mAdapter.notifyDataSetChanged(); + } + } + + @Override + public void onAnimationCancel(Animator animator) { + } + + @Override + public void onAnimationRepeat(Animator animator) { + } + }); + + heightAnimator.start(); + } + + private void setDismissed() { + final SharedPreferences prefs = getContext().getSharedPreferences( + DialtactsActivity.SHARED_PREFS_NAME, Context.MODE_PRIVATE); + prefs.edit().putBoolean(KEY_TILE_INTERACTION_TEASER_SHOWN, false).apply(); + } + + @Override + protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { + if (mAnimatedHeight == -1) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } else { + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), mAnimatedHeight); + } + } +} |