diff options
author | Yorke Lee <yorkelee@google.com> | 2014-03-04 20:39:16 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2014-03-04 20:39:16 +0000 |
commit | 2816207eef9095b5c080b75554fedbdc79442ba3 (patch) | |
tree | 7827e9b7b4ea782570e6ac586eb5a91d2ce8fd7e | |
parent | e2129528a1bd5bf99163026cbd4e01f97b0877ac (diff) | |
parent | d5b5d0a35d0f0e7dfd75828976dc3c0f95cdd672 (diff) |
am d5b5d0a3: Add drag to remove for favorites in Dialer
* commit 'd5b5d0a35d0f0e7dfd75828976dc3c0f95cdd672':
Add drag to remove for favorites in Dialer
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 2564cd7bd..20a73c15b 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -533,6 +533,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> @@ -720,6 +723,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(); + } +} |