diff options
author | Yorke Lee <yorkelee@google.com> | 2014-01-16 11:26:46 -0800 |
---|---|---|
committer | Yorke Lee <yorkelee@google.com> | 2014-02-20 12:24:36 -0800 |
commit | 3cefcc69c10ab12bd782a0b53779dbd1cc0e2aa1 (patch) | |
tree | e627f324ef1be14d2ac00bafe043d8f28294d575 | |
parent | 28ded60d6aa23314d2cfca9ccca1e5bf731508e4 (diff) |
Add drag to remove for favorites in Dialer
* Add remove view in dialtacts_activity.xml, and rearrange layout slightly
so that it takes up the same position in the layout as the search view
container. Contacts that are dragged to this remove view will be unstarred
and unpinned.
* Add drag event logic to the Remove View, so that when the user hovers a
contact over it, the UI will continue to respond. Previously, only the
PhoneFavoritesListView would detect touch events.
* Refactor DragDropController and OnDragDropListener into separate classes.
DragDropController performs the work of receiving drag/drop events from
multiple views, combining them, and then firing off callbacks as appropriate
to OnDragDropListeners. Each OnDragDropListener can then update their UI
or internal data model as necessary in response to the callbacks.
OnDragDropListener <----------------------------------------
^ |
| |
DialtactsActivity ---------------> RemoveView |
| | |
v | | callbacks
PhoneFavoriteListFragment |drag events |
| | |
v v |
PhoneFavoriteListView ------------> DragController--------
drag events |
| callbacks
v
PhoneFavoritesTileAdapter --> OnDragDropListener
* While in here, add a content description for the clear search button
Change-Id: I044ad1c5aa42c7686bde6bf5074095a4fe879bde
19 files changed, 433 insertions, 120 deletions
diff --git a/res/drawable-hdpi/ic_remove.png b/res/drawable-hdpi/ic_remove.png Binary files differnew file mode 100644 index 000000000..1ee6adf8d --- /dev/null +++ b/res/drawable-hdpi/ic_remove.png diff --git a/res/drawable-hdpi/ic_remove_highlight.png b/res/drawable-hdpi/ic_remove_highlight.png Binary files differnew file mode 100644 index 000000000..435ee36b0 --- /dev/null +++ b/res/drawable-hdpi/ic_remove_highlight.png diff --git a/res/drawable-mdpi/ic_remove.png b/res/drawable-mdpi/ic_remove.png Binary files differnew file mode 100644 index 000000000..2c134ea10 --- /dev/null +++ b/res/drawable-mdpi/ic_remove.png diff --git a/res/drawable-mdpi/ic_remove_highlight.png b/res/drawable-mdpi/ic_remove_highlight.png Binary files differnew file mode 100644 index 000000000..6a961cbb2 --- /dev/null +++ b/res/drawable-mdpi/ic_remove_highlight.png diff --git a/res/drawable-xhdpi/ic_remove.png b/res/drawable-xhdpi/ic_remove.png Binary files differnew file mode 100644 index 000000000..be81592ef --- /dev/null +++ b/res/drawable-xhdpi/ic_remove.png diff --git a/res/drawable-xhdpi/ic_remove_highlight.png b/res/drawable-xhdpi/ic_remove_highlight.png Binary files differnew file mode 100644 index 000000000..57949e317 --- /dev/null +++ b/res/drawable-xhdpi/ic_remove_highlight.png diff --git a/res/drawable-xxhdpi/ic_remove.png b/res/drawable-xxhdpi/ic_remove.png Binary files differnew file mode 100644 index 000000000..2722f23aa --- /dev/null +++ b/res/drawable-xxhdpi/ic_remove.png diff --git a/res/drawable-xxhdpi/ic_remove_highlight.png b/res/drawable-xxhdpi/ic_remove_highlight.png Binary files differnew file mode 100644 index 000000000..23ee8f6da --- /dev/null +++ b/res/drawable-xxhdpi/ic_remove_highlight.png diff --git a/res/layout/dialtacts_activity.xml b/res/layout/dialtacts_activity.xml index e2c385364..5a886e226 100644 --- a/res/layout/dialtacts_activity.xml +++ b/res/layout/dialtacts_activity.xml @@ -28,20 +28,20 @@ android:layout_height="match_parent" android:clipChildren="false" android:orientation="vertical" > - <LinearLayout + <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:id="@+id/search_view_container" - android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" - android:layout_height="match_parent" + android:layout_height="wrap_content" + android:id="@+id/search_view_container" android:orientation="horizontal" android:paddingLeft="16dp" android:paddingRight="23dp" android:background="@color/searchbox_background_color" - android:gravity="center_vertical"> + android:gravity="center_vertical" + > <EditText android:id="@+id/search_view" android:layout_width="0dp" @@ -57,6 +57,7 @@ android:src="@drawable/ic_close_dk" android:clickable="true" android:background="?android:attr/selectableItemBackground" + android:contentDescription="@string/description_clear_search" android:visibility="gone" /> <ImageView android:id="@+id/voice_search_button" @@ -68,12 +69,35 @@ android:contentDescription="@string/description_start_voice_search" android:background="?android:attr/selectableItemBackground" /> </LinearLayout> - <View - android:id="@+id/searchbox_divider" - android:layout_height="1dp" + <com.android.dialer.list.RemoveView android:layout_width="match_parent" - android:background="@color/background_dialer_light" /> - </LinearLayout> + android:layout_height="56dp" + android:id="@+id/remove_view_container" + android:orientation="horizontal" + android:gravity="center" + android:visibility="gone"> + <ImageView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:id="@+id/remove_view_icon" + android:src="@drawable/ic_remove" + android:contentDescription="@string/remove_contact" + /> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:id="@+id/remove_view_text" + android:textSize="@dimen/remove_text_size" + android:textColor="@color/remove_text_color" + android:text="@string/remove_contact" + /> + </com.android.dialer.list.RemoveView> + </FrameLayout> + <View + android:id="@+id/searchbox_divider" + android:layout_height="1dp" + android:layout_width="match_parent" + android:background="@color/background_dialer_light" /> <FrameLayout android:layout_height="0dp" android:layout_weight="1" diff --git a/res/values/colors.xml b/res/values/colors.xml index 370bdfeb6..fc8e8473f 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -12,7 +12,7 @@ ~ 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 - --> +--> <resources> @@ -27,8 +27,10 @@ <!-- Color of the text describing an unconsumed voicemail. --> <color name="call_log_voicemail_highlight_color">#33b5e5</color> - <!-- Colour of voicemail progress bar to the right of position indicator. - Same as the background color of the dialer --> + <!-- + Colour of voicemail progress bar to the right of position indicator. + Same as the background color of the dialer + --> <color name="voicemail_playback_seek_bar_yet_to_play">#cecece</color> <!-- Colour of voicemail progress bar to the left of position indicator. --> @@ -38,7 +40,7 @@ <color name="item_selected">#660099cc</color> <!-- Background color of new dialer activity --> - <color name="background_dialer_light">#cecece</color> + <color name="background_dialer_light">#eeeeee</color> <!-- Background color of dialer list items (contacts, call log entries) --> <color name="background_dialer_list_items">#eeeeee</color> @@ -71,6 +73,12 @@ <!-- Text color for no favorites message --> <color name="nofavorite_text_color">#777777</color> + <!-- Text color for the "Remove" text in its regular state --> + <color name="remove_text_color">#555555</color> + + <!-- Text color for the "Remove" text when a contact is dragged on top of the remove view --> + <color name="remove_highlighted_text_color">#FF3F3B</color> + <!-- Text color for the "speed dial" label in the favorites menu. --> <color name="speed_dial_text_color">#555555</color> diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 3c856d2e6..fb74e9748 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -13,7 +13,7 @@ ~ 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 - --> +--> <resources> <!-- Height of edit text in dialpad fragment --> @@ -29,9 +29,15 @@ <!-- Match call_button_height to Phone's dimens/in_call_end_button_height --> <dimen name="call_button_height">74dp</dimen> - <!-- Search View --> + <!-- Search View --> <dimen name="search_text_size">14sp</dimen> + <!-- + Drag to remove view (in dp because it is used in conjunction with a statically + sized icon + --> + <dimen name="remove_text_size">16dp</dimen> + <!-- Call Log --> <dimen name="call_log_call_action_size">32dip</dimen> <dimen name="call_log_call_action_width">48dip</dimen> @@ -51,9 +57,11 @@ the main area of a call log entry and the secondary action button. --> <dimen name="call_log_list_item_vertical_divider_width">1dp</dimen> - <!-- Layout weight values for dialpad screen. These layouts will be used in one + <!-- + Layout weight values for dialpad screen. These layouts will be used in one LinearLayout (dialpad_fragment.xml), configuring dialpad screen's vertical - ratio. --> + ratio. + --> <integer name="dialpad_layout_weight_digits">15</integer> <integer name="dialpad_layout_weight_dialpad">65</integer> @@ -63,14 +71,14 @@ <dimen name="dialpad_key_plus_size">15dp</dimen> <dimen name="dialpad_key_special_characters_size">25dp</dimen> <dimen name="dialpad_key_letters_width">41dp</dimen> - - <dimen name="fake_action_bar_height">60dp</dimen> <!-- Min with of fake menu buttons, which should be same as ActionBar's one --> <dimen name="fake_menu_button_min_width">56dp</dimen> <!-- Favorites tile and recent call log padding --> <dimen name="contact_tile_divider_width">12dp</dimen> + <!-- Favorites tile and recent call log padding --> + <dimen name="contact_tile_divider_padding">3dp</dimen> <dimen name="contact_tile_info_button_height_and_width">36dp</dimen> <item name="contact_tile_height_to_width_ratio" type="dimen">67%</item> <dimen name="favorites_row_top_padding">6dp</dimen> diff --git a/res/values/strings.xml b/res/values/strings.xml index a61e0bc4a..3f2157712 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -539,6 +539,9 @@ --> <string name="description_call_log_unheard_voicemail">Unheard voicemail</string> + <!-- String describing the icon used to clear the search field --> + <string name="description_clear_search">Clear search</string> + <!-- String describing the icon used to start a voice search --> <string name="description_start_voice_search">Start voice search</string> @@ -726,6 +729,8 @@ <!-- Content description for dismiss button on badge. [CHAR LIMIT=NONE] --> <string name="description_dismiss">Dismiss</string> + <!-- Remove button that shows up when contact is long-pressed. [CHAR LIMIT=NONE] --> + <string name="remove_contact">Remove</string> <!-- Header text displayed on the main dialer screen above the list of favorite phone numbers. [CHAR LIMIT=21] --> <string name="favorites_menu_speed_dial">Speed Dial</string> diff --git a/src/com/android/dialer/DialtactsActivity.java b/src/com/android/dialer/DialtactsActivity.java index 0c0fcdafe..227cd8eca 100644 --- a/src/com/android/dialer/DialtactsActivity.java +++ b/src/com/android/dialer/DialtactsActivity.java @@ -22,7 +22,6 @@ import android.animation.AnimatorListenerAdapter; import android.app.Activity; import android.app.Fragment; import android.app.FragmentManager; -import android.app.FragmentManager.BackStackEntry; import android.app.FragmentTransaction; import android.content.ActivityNotFoundException; import android.content.Context; @@ -50,8 +49,6 @@ import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; -import android.view.View.OnClickListener; -import android.view.View.OnFocusChangeListener; import android.view.inputmethod.InputMethodManager; import android.widget.AbsListView.OnScrollListener; import android.widget.EditText; @@ -70,9 +67,13 @@ import com.android.dialer.dialpad.SmartDialNameMatcher; import com.android.dialer.dialpad.SmartDialPrefix; import com.android.dialer.interactions.PhoneNumberInteraction; import com.android.dialer.list.AllContactsActivity; +import com.android.dialer.list.DragDropController; +import com.android.dialer.list.OnDragDropListener; import com.android.dialer.list.OnListFragmentScrolledListener; import com.android.dialer.list.PhoneFavoriteFragment; +import com.android.dialer.list.PhoneFavoriteTileView; import com.android.dialer.list.RegularSearchFragment; +import com.android.dialer.list.RemoveView; import com.android.dialer.list.SearchFragment; import com.android.dialer.list.SmartDialSearchFragment; import com.android.dialerbind.DatabaseHelperManager; @@ -88,7 +89,9 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O DialpadFragment.OnDialpadQueryChangedListener, PopupMenu.OnMenuItemClickListener, OnListFragmentScrolledListener, DialpadFragment.OnDialpadFragmentStartedListener, - PhoneFavoriteFragment.OnShowAllContactsListener { + PhoneFavoriteFragment.OnShowAllContactsListener, + PhoneFavoriteFragment.HostInterface, + OnDragDropListener { private static final String TAG = "DialtactsActivity"; public static final boolean DEBUG = false; @@ -122,6 +125,8 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O private static final int ACTIVITY_REQUEST_CODE_VOICE_SEARCH = 1; + private static final int FADE_ANIMATION_DURATION = 200; + private String mFilterText; /** @@ -168,6 +173,7 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O */ private boolean mFirstLaunch; private View mSearchViewContainer; + private RemoveView mRemoveViewContainer; private View mSearchViewCloseButton; private View mVoiceSearchButton; private EditText mSearchView; @@ -312,6 +318,7 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O mBottomPaddingView = findViewById(R.id.dialtacts_bottom_padding); mFragmentsFrame = findViewById(R.id.dialtacts_frame); mActionBar = findViewById(R.id.fake_action_bar); + mRemoveViewContainer = (RemoveView) findViewById(R.id.remove_view_container); prepareSearchView(); if (UI.FILTER_CONTACTS_ACTION.equals(intent.getAction()) @@ -977,4 +984,48 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O PackageManager.MATCH_DEFAULT_ONLY); return resolveInfo != null && resolveInfo.size() > 0; } + + @Override + public void onDragStarted(int itemIndex, int x, int y, PhoneFavoriteTileView view) { + crossfadeViews(mRemoveViewContainer, mSearchViewContainer, FADE_ANIMATION_DURATION); + } + + @Override + public void onDragHovered(int itemIndex, int x, int y) {} + + @Override + public void onDragFinished(int x, int y) { + crossfadeViews(mSearchViewContainer, mRemoveViewContainer, FADE_ANIMATION_DURATION); + } + + @Override + public void onDroppedOnRemove() {} + + /** + * Allows the PhoneFavoriteFragment to attach the drag controller to mRemoveViewContainer + * once it has been attached to the activity. + */ + @Override + public void setDragDropController(DragDropController dragController) { + mRemoveViewContainer.setDragDropController(dragController); + } + + /** + * Crossfades two views so that the first one appears while the other one is fading + * out of view. + */ + private void crossfadeViews(final View fadeIn, final View fadeOut, int duration) { + fadeOut.animate().alpha(0).setDuration(duration) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + fadeOut.setVisibility(View.GONE); + } + }); + + fadeIn.setVisibility(View.VISIBLE); + fadeIn.setAlpha(0); + fadeIn.animate().alpha(1).setDuration(FADE_ANIMATION_DURATION) + .setListener(null); + } } diff --git a/src/com/android/dialer/list/DragDropController.java b/src/com/android/dialer/list/DragDropController.java new file mode 100644 index 000000000..399cd099b --- /dev/null +++ b/src/com/android/dialer/list/DragDropController.java @@ -0,0 +1,71 @@ +package com.android.dialer.list; + +import android.view.View; + +import com.android.dialer.list.PhoneFavoritesTileAdapter.ContactTileRow; + +import java.util.ArrayList; +import java.util.List; + +/** + * Class that handles and combines drag events generated from multiple views, and then fires + * off events to any OnDragDropListeners that have registered for callbacks. + */ +public class DragDropController { + private List<OnDragDropListener> mOnDragDropListeners = new ArrayList<OnDragDropListener>(); + + /** + * @return True if the drag is started, false if the drag is cancelled for some reason. + */ + boolean handleDragStarted(int x, int y, ContactTileRow tileRow) { + final PhoneFavoriteTileView tileView = + (PhoneFavoriteTileView) tileRow.getViewAtPosition(x, y); + + final int itemIndex = tileRow.getItemIndex(x, y); + if (itemIndex != -1 && !mOnDragDropListeners.isEmpty()) { + for (int i = 0; i < mOnDragDropListeners.size(); i++) { + mOnDragDropListeners.get(i).onDragStarted(itemIndex, x, y, tileView); + } + } + + return true; + } + + public void handleDragHovered(int x, int y, View view) { + int itemIndex; + if (!(view instanceof ContactTileRow)) { + itemIndex = -1; + } else { + final ContactTileRow tile = (ContactTileRow) view; + itemIndex = tile.getItemIndex(x, y); + } + for (int i = 0; i < mOnDragDropListeners.size(); i++) { + mOnDragDropListeners.get(i).onDragHovered(itemIndex, x, y); + } + } + + public void handleDragFinished(int x, int y, boolean isRemoveView) { + if (isRemoveView) { + for (int i = 0; i < mOnDragDropListeners.size(); i++) { + mOnDragDropListeners.get(i).onDroppedOnRemove(); + } + } + + for (int i = 0; i < mOnDragDropListeners.size(); i++) { + mOnDragDropListeners.get(i).onDragFinished(x, y); + } + } + + public void addOnDragDropListener(OnDragDropListener listener) { + if (!mOnDragDropListeners.contains(listener)) { + mOnDragDropListeners.add(listener); + } + } + + public void removeOnDragDropListener(OnDragDropListener listener) { + if (mOnDragDropListeners.contains(listener)) { + mOnDragDropListeners.remove(listener); + } + } + +}
\ No newline at end of file diff --git a/src/com/android/dialer/list/OnDragDropListener.java b/src/com/android/dialer/list/OnDragDropListener.java new file mode 100644 index 000000000..7f6d1791c --- /dev/null +++ b/src/com/android/dialer/list/OnDragDropListener.java @@ -0,0 +1,41 @@ +package com.android.dialer.list; + + +/** + * Classes that want to receive callbacks in response to drag events should implement this + * interface. + */ +public interface OnDragDropListener { + /** + * Called when a drag is started. + * @param itemIndex Index of the contact on which the drag was triggered + * @param x X-coordinate of the drag event + * @param y Y-coordinate of the drag event + * @param view The contact tile which the drag was started on + */ + public void onDragStarted(int itemIndex, int x, int y, PhoneFavoriteTileView view); + + /** + * Called when a drag is in progress and the user moves the dragged contact to a + * location. + * @param itemIndex Index of the contact in the ListView which is currently being displaced + * by the dragged contact + * @param x X-coordinate of the drag event + * @param y Y-coordinate of the drag event + */ + public void onDragHovered(int itemIndex, int x, int y); + + /** + * Called when a drag is completed (whether by dropping it somewhere or simply by dragging + * the contact off the screen) + * @param x X-coordinate of the drag event + * @param y Y-coordinate of the drag event + */ + public void onDragFinished(int x, int y); + + /** + * Called when a contact has been dropped on the remove view, indicating that the user + * wants to remove this contact. + */ + public void onDroppedOnRemove(); +}
\ No newline at end of file diff --git a/src/com/android/dialer/list/PhoneFavoriteFragment.java b/src/com/android/dialer/list/PhoneFavoriteFragment.java index 860f9dc2a..79dbe8c49 100644 --- a/src/com/android/dialer/list/PhoneFavoriteFragment.java +++ b/src/com/android/dialer/list/PhoneFavoriteFragment.java @@ -107,6 +107,10 @@ public class PhoneFavoriteFragment extends Fragment implements OnItemClickListen public void onCallNumberDirectly(String phoneNumber); } + public interface HostInterface { + public void setDragDropController(DragDropController controller); + } + private class MissedCallLogLoaderListener implements LoaderManager.LoaderCallbacks<Cursor> { @Override @@ -279,7 +283,7 @@ public class PhoneFavoriteFragment extends Fragment implements OnItemClickListen mListView.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_RIGHT); mListView.setScrollBarStyle(ListView.SCROLLBARS_OUTSIDE_OVERLAY); mListView.setOnItemSwipeListener(mContactTileAdapter); - mListView.setOnDragDropListener(mContactTileAdapter); + mListView.getDragDropController().addOnDragDropListener(mContactTileAdapter); final ImageView dragShadowOverlay = (ImageView) mParentView.findViewById(R.id.contact_tile_drag_shadow_overlay); @@ -347,6 +351,15 @@ public class PhoneFavoriteFragment extends Fragment implements OnItemClickListen + " must implement OnShowAllContactsListener"); } + try { + OnDragDropListener listener = (OnDragDropListener) activity; + mListView.getDragDropController().addOnDragDropListener(listener); + ((HostInterface) activity).setDragDropController(mListView.getDragDropController()); + } catch (ClassCastException e) { + throw new ClassCastException(activity.toString() + + " must implement OnDragDropListener and HostInterface"); + } + // Use initLoader() instead of restartLoader() to refraining unnecessary reload. // This method call implicitly assures ContactTileLoaderListener's onLoadFinished() will // be called, on which we'll check if "all" contacts should be reloaded again or not. diff --git a/src/com/android/dialer/list/PhoneFavoriteListView.java b/src/com/android/dialer/list/PhoneFavoriteListView.java index 99979dd53..adda3cfd0 100644 --- a/src/com/android/dialer/list/PhoneFavoriteListView.java +++ b/src/com/android/dialer/list/PhoneFavoriteListView.java @@ -29,7 +29,6 @@ import android.view.DragEvent; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; -import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ListView; @@ -44,7 +43,8 @@ import com.android.dialer.list.SwipeHelper.SwipeHelperCallback; * - Swiping, which is borrowed from packages/apps/UnifiedEmail (com.android.mail.ui.Swipeable) * - Drag and drop */ -public class PhoneFavoriteListView extends ListView implements SwipeHelperCallback { +public class PhoneFavoriteListView extends ListView implements SwipeHelperCallback, + OnDragDropListener { public static final String LOG_TAG = PhoneFavoriteListView.class.getSimpleName(); @@ -52,7 +52,6 @@ public class PhoneFavoriteListView extends ListView implements SwipeHelperCallba private boolean mEnableSwipe = true; private OnItemGestureListener mOnItemGestureListener; - private OnDragDropListener mOnDragDropListener; private float mDensityScale; private float mTouchSlop; @@ -81,6 +80,8 @@ public class PhoneFavoriteListView extends ListView implements SwipeHelperCallba private int mDragShadowLeft; private int mDragShadowTop; + private DragDropController mDragDropController = new DragDropController(); + private final float DRAG_SHADOW_ALPHA = 0.7f; /** @@ -130,6 +131,7 @@ public class PhoneFavoriteListView extends ListView implements SwipeHelperCallba mSwipeHelper = new SwipeHelper(context, SwipeHelper.X, this, mDensityScale, mTouchSlop); setItemsCanFocus(true); + mDragDropController.addOnDragDropListener(this); } @Override @@ -156,10 +158,10 @@ public class PhoneFavoriteListView extends ListView implements SwipeHelperCallba mOnItemGestureListener = listener; } - public void setOnDragDropListener(OnDragDropListener listener) { - mOnDragDropListener = listener; - } - + /** + * TODO: This is all swipe to remove code (nothing to do with drag to remove). This should + * be cleaned up and removed once drag to remove becomes the only way to remove contacts. + */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { @@ -232,6 +234,10 @@ public class PhoneFavoriteListView extends ListView implements SwipeHelperCallba requestDisallowInterceptTouchEvent(true); } + /** + * End of swipe-to-remove code + */ + @Override public boolean dispatchDragEvent(DragEvent event) { final int action = event.getAction(); @@ -239,13 +245,34 @@ public class PhoneFavoriteListView extends ListView implements SwipeHelperCallba final int eY = (int) event.getY(); switch (action) { case DragEvent.ACTION_DRAG_STARTED: - if (!handleDragStarted(mTouchDownForDragStartX, mTouchDownForDragStartY)) { + final int[] coordinates = new int[2]; + getLocationOnScreen(coordinates); + // Calculate the X and Y coordinates of the drag event relative to the view + final int viewX = eX - coordinates[0]; + final int viewY = eY - coordinates[1]; + final View child = getViewAtPosition(viewX, viewY); + + if (!(child instanceof ContactTileRow)) { + // Bail early. + return false; + } + + final ContactTileRow tile = (ContactTileRow) child; + + // Disable drag and drop if there is a contact that has been swiped and is currently + // in the pending remove state + if (tile.getTileAdapter().hasPotentialRemoveEntryIndex()) { + return false; + } + + if (!mDragDropController.handleDragStarted(viewX, viewY, tile)) { return false; - }; + } break; case DragEvent.ACTION_DRAG_LOCATION: mLastDragY = eY; - handleDragHovered(eX, eY); + final View view = getViewAtPosition(eX, eY); + mDragDropController.handleDragHovered(eX, eY, view); // Kick off {@link #mScrollHandler} if it's not started yet. if (!mIsDragScrollerRunning && // And if the distance traveled while dragging exceeds the touch slop @@ -268,13 +295,13 @@ public class PhoneFavoriteListView extends ListView implements SwipeHelperCallba mIsDragScrollerRunning = false; // Either a successful drop or it's ended with out drop. if (action == DragEvent.ACTION_DROP || action == DragEvent.ACTION_DRAG_ENDED) { - handleDragFinished(eX, eY); + mDragDropController.handleDragFinished(eX, eY, false); } break; default: break; } - // This ListView will consumer the drag events on behalf of its children. + // This ListView will consume the drag events on behalf of its children. return true; } @@ -303,69 +330,48 @@ public class PhoneFavoriteListView extends ListView implements SwipeHelperCallba } } - /** - * @return True if the drag is started. - */ - private boolean handleDragStarted(int x, int y) { - final View child = getViewAtPosition(x, y); - if (!(child instanceof ContactTileRow)) { - // Bail early. - return false; - } - - final ContactTileRow tile = (ContactTileRow) child; + public DragDropController getDragDropController() { + return mDragDropController; + } - if (tile.getTileAdapter().hasPotentialRemoveEntryIndex()) { - return false; + @Override + public void onDragStarted(int itemIndex, int x, int y, PhoneFavoriteTileView tileView) { + if (mDragShadowOverlay == null) { + return; } - final int itemIndex = tile.getItemIndex(x, y); - if (itemIndex != -1 && mOnDragDropListener != null) { - final PhoneFavoriteTileView tileView = - (PhoneFavoriteTileView) tile.getViewAtPosition(x, y); - if (mDragShadowOverlay == null) { - return false; - } - - mDragShadowOverlay.clearAnimation(); - mDragShadowBitmap = createDraggedChildBitmap(tileView); - if (mDragShadowBitmap == null) { - return false; - } - - if (tileView instanceof PhoneFavoriteRegularRowView) { - mDragShadowLeft = tile.getLeft(); - mDragShadowTop = tile.getTop(); - } else { - // Square tile is relative to the contact tile, - // and contact tile is relative to this list view. - mDragShadowLeft = tileView.getLeft() + tileView.getParentRow().getLeft(); - mDragShadowTop = tileView.getTop() + tileView.getParentRow().getTop(); - } - - mDragShadowOverlay.setImageBitmap(mDragShadowBitmap); - mDragShadowOverlay.setVisibility(VISIBLE); - mDragShadowOverlay.setAlpha(DRAG_SHADOW_ALPHA); - - mDragShadowOverlay.setX(mDragShadowLeft); - mDragShadowOverlay.setY(mDragShadowTop); + mDragShadowOverlay.clearAnimation(); + mDragShadowBitmap = createDraggedChildBitmap(tileView); + if (mDragShadowBitmap == null) { + return; + } - // x and y passed in are the coordinates of where the user has touched down, calculate - // the offset to the top left coordinate of the dragged child. This will be used for - // drawing the drag shadow. - mTouchOffsetToChildLeft = x - mDragShadowLeft; - mTouchOffsetToChildTop = y - mDragShadowTop; + if (tileView instanceof PhoneFavoriteRegularRowView) { + mDragShadowLeft = tileView.getParentRow().getLeft(); + mDragShadowTop = tileView.getParentRow().getTop(); + } else { + // Square tile is relative to the contact tile, + // and contact tile is relative to this list view. + mDragShadowLeft = tileView.getLeft() + tileView.getParentRow().getLeft(); + mDragShadowTop = tileView.getTop() + tileView.getParentRow().getTop(); + } - // invalidate to trigger a redraw of the drag shadow. - invalidate(); + mDragShadowOverlay.setImageBitmap(mDragShadowBitmap); + mDragShadowOverlay.setVisibility(VISIBLE); + mDragShadowOverlay.setAlpha(DRAG_SHADOW_ALPHA); - mOnDragDropListener.onDragStarted(itemIndex); - } + mDragShadowOverlay.setX(mDragShadowLeft); + mDragShadowOverlay.setY(mDragShadowTop); - return true; + // x and y passed in are the coordinates of where the user has touched down, + // calculate the offset to the top left coordinate of the dragged child. This + // will be used for drawing the drag shadow. + mTouchOffsetToChildLeft = x - mDragShadowLeft; + mTouchOffsetToChildTop = y - mDragShadowTop; } - private void handleDragHovered(int x, int y) { + @Override + public void onDragHovered(int itemIndex, int x, int y) { // Update the drag shadow location. mDragShadowLeft = x - mTouchOffsetToChildLeft; mDragShadowTop = y - mTouchOffsetToChildTop; @@ -374,21 +380,10 @@ public class PhoneFavoriteListView extends ListView implements SwipeHelperCallba mDragShadowOverlay.setX(mDragShadowLeft); mDragShadowOverlay.setY(mDragShadowTop); } - - final View child = getViewAtPosition(x, y); - if (!(child instanceof ContactTileRow)) { - // Bail early. - return; - } - - final ContactTileRow tile = (ContactTileRow) child; - final int itemIndex = tile.getItemIndex(x, y); - if (itemIndex != -1 && mOnDragDropListener != null) { - mOnDragDropListener.onDragHovered(itemIndex); - } } - private void handleDragFinished(int x, int y) { + @Override + public void onDragFinished(int x, int y) { // Update the drag shadow location. mDragShadowLeft = x - mTouchOffsetToChildLeft; mDragShadowTop = y - mTouchOffsetToChildTop; @@ -400,12 +395,11 @@ public class PhoneFavoriteListView extends ListView implements SwipeHelperCallba .setListener(mDragShadowOverAnimatorListener) .start(); } - - if (mOnDragDropListener != null) { - mOnDragDropListener.onDragFinished(); - } } + @Override + public void onDroppedOnRemove() {} + private Bitmap createDraggedChildBitmap(View view) { view.setDrawingCacheEnabled(true); final Bitmap cache = view.getDrawingCache(); @@ -425,10 +419,4 @@ public class PhoneFavoriteListView extends ListView implements SwipeHelperCallba return bitmap; } - - public interface OnDragDropListener { - public void onDragStarted(int itemIndex); - public void onDragHovered(int itemIndex); - public void onDragFinished(); - } } diff --git a/src/com/android/dialer/list/PhoneFavoritesTileAdapter.java b/src/com/android/dialer/list/PhoneFavoritesTileAdapter.java index dff68b2be..45cc5a371 100644 --- a/src/com/android/dialer/list/PhoneFavoritesTileAdapter.java +++ b/src/com/android/dialer/list/PhoneFavoritesTileAdapter.java @@ -59,7 +59,7 @@ import java.util.PriorityQueue; * */ public class PhoneFavoritesTileAdapter extends BaseAdapter implements - SwipeHelper.OnItemGestureListener, PhoneFavoriteListView.OnDragDropListener { + SwipeHelper.OnItemGestureListener, OnDragDropListener { private static final String TAG = PhoneFavoritesTileAdapter.class.getSimpleName(); private static final boolean DEBUG = false; @@ -1204,24 +1204,38 @@ public class PhoneFavoritesTileAdapter extends BaseAdapter implements } @Override - public void onDragStarted(int itemIndex) { + public void onDragStarted(int itemIndex, int x, int y, PhoneFavoriteTileView view) { setInDragging(true); popContactEntry(itemIndex); } @Override - public void onDragHovered(int itemIndex) { + public void onDragHovered(int itemIndex, int x, int y) { if (mInDragging && mDragEnteredEntryIndex != itemIndex && isIndexInBound(itemIndex) && - itemIndex < PIN_LIMIT) { + itemIndex < PIN_LIMIT && + itemIndex >= 0) { markDropArea(itemIndex); } } @Override - public void onDragFinished() { + public void onDragFinished(int x, int y) { setInDragging(false); - handleDrop(); + // A contact has been dragged to the RemoveView in order to be unstarred, so simply wait + // for the new contact cursor which will cause the UI to be refreshed without the unstarred + // contact. + if (!mAwaitingRemove) { + handleDrop(); + } + } + + @Override + public void onDroppedOnRemove() { + if (mDraggedEntry != null) { + unstarAndUnpinContact(mDraggedEntry.lookupKey); + mAwaitingRemove = true; + } } } diff --git a/src/com/android/dialer/list/RemoveView.java b/src/com/android/dialer/list/RemoveView.java new file mode 100644 index 000000000..16942fe96 --- /dev/null +++ b/src/com/android/dialer/list/RemoveView.java @@ -0,0 +1,90 @@ +package com.android.dialer.list; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.DragEvent; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.android.dialer.R; + +public class RemoveView extends LinearLayout { + + DragDropController mDragDropController; + TextView mRemoveText; + ImageView mRemoveIcon; + int mUnhighlightedColor; + int mHighlightedColor; + Drawable mRemoveDrawable; + Drawable mRemoveHighlightedDrawable; + + public RemoveView(Context context) { + super(context); + } + + public RemoveView(Context context, AttributeSet attrs) { + this(context, attrs, -1); + } + + public RemoveView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + protected void onFinishInflate() { + mRemoveText = (TextView) findViewById(R.id.remove_view_text); + mRemoveIcon = (ImageView) findViewById(R.id.remove_view_icon); + final Resources r = getResources(); + mUnhighlightedColor = r.getColor(R.color.remove_text_color); + mHighlightedColor = r.getColor(R.color.remove_highlighted_text_color); + mRemoveDrawable = r.getDrawable(R.drawable.ic_remove); + mRemoveHighlightedDrawable = r.getDrawable(R.drawable.ic_remove_highlight); + } + + public void setDragDropController(DragDropController controller) { + mDragDropController = controller; + } + + @Override + public boolean dispatchDragEvent(DragEvent event) { + final int action = event.getAction(); + switch (action) { + case DragEvent.ACTION_DRAG_ENTERED: + setAppearanceHighlighted(); + break; + case DragEvent.ACTION_DRAG_EXITED: + setAppearanceNormal(); + break; + case DragEvent.ACTION_DRAG_LOCATION: + if (mDragDropController != null) { + mDragDropController.handleDragHovered((int) event.getX(), + // the true y-coordinate of the event with respect to the listview is + // offset by the height of the remove view + (int) event.getY() - getHeight(), null); + } + break; + case DragEvent.ACTION_DROP: + if (mDragDropController != null) { + mDragDropController.handleDragFinished((int) event.getX(), (int) event.getY(), true); + } + setAppearanceNormal(); + break; + } + return true; + } + + private void setAppearanceNormal() { + mRemoveText.setTextColor(mUnhighlightedColor); + mRemoveIcon.setImageDrawable(mRemoveDrawable); + invalidate(); + } + + private void setAppearanceHighlighted() { + mRemoveText.setTextColor(mHighlightedColor); + mRemoveIcon.setImageDrawable(mRemoveHighlightedDrawable); + invalidate(); + } +} |