MailboxListFragment.java revision 6bbc689efcb33c74129493e7097aa4a485a7d7c1
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.email.activity; 18 19import com.android.email.Controller; 20import com.android.email.Email; 21import com.android.email.R; 22import com.android.email.RefreshManager; 23import com.android.email.Utility; 24import com.android.email.provider.EmailProvider; 25import com.android.email.provider.EmailContent.Mailbox; 26import com.android.email.provider.EmailContent.Message; 27 28import android.app.Activity; 29import android.app.ListFragment; 30import android.app.LoaderManager.LoaderCallbacks; 31import android.content.ClipData; 32import android.content.ClipDescription; 33import android.content.Loader; 34import android.content.res.Resources; 35import android.database.Cursor; 36import android.graphics.drawable.Drawable; 37import android.net.Uri; 38import android.os.Bundle; 39import android.util.Log; 40import android.view.DragEvent; 41import android.view.LayoutInflater; 42import android.view.View; 43import android.view.View.OnDragListener; 44import android.view.ViewGroup; 45import android.widget.AdapterView; 46import android.widget.ListView; 47import android.widget.AdapterView.OnItemClickListener; 48 49import java.security.InvalidParameterException; 50 51/** 52 * This fragment presents a list of mailboxes for a given account. The "API" includes the 53 * following elements which must be provided by the host Activity. 54 * 55 * - call bindActivityInfo() to provide the account ID and set callbacks 56 * - provide callbacks for onOpen and onRefresh 57 * - pass-through implementations of onCreateContextMenu() and onContextItemSelected() (temporary) 58 * 59 * TODO Restoring ListView state -- don't do this when changing accounts 60 */ 61public class MailboxListFragment extends ListFragment implements OnItemClickListener, 62 OnDragListener { 63 private static final String TAG = "MailboxListFragment"; 64 private static final String BUNDLE_KEY_SELECTED_MAILBOX_ID 65 = "MailboxListFragment.state.selected_mailbox_id"; 66 private static final String BUNDLE_LIST_STATE = "MailboxListFragment.state.listState"; 67 private static final int LOADER_ID_MAILBOX_LIST = 1; 68 private static final boolean DEBUG_DRAG_DROP = false; // MUST NOT SUBMIT SET TO TRUE 69 70 private static final int NO_DROP_TARGET = -1; 71 // Total height of the top and bottom scroll zones, in pixels 72 private static final int SCROLL_ZONE_SIZE = 64; 73 // The amount of time to scroll by one pixel, in ms 74 private static final int SCROLL_SPEED = 4; 75 76 // Colors used for drop targets 77 private static Integer sDropTrashColor; 78 private static Drawable sDropActiveDrawable; 79 80 private long mLastLoadedAccountId = -1; 81 private long mAccountId = -1; 82 private long mSelectedMailboxId = -1; 83 84 private RefreshManager mRefreshManager; 85 86 // UI Support 87 private Activity mActivity; 88 private MailboxesAdapter mListAdapter; 89 private Callback mCallback = EmptyCallback.INSTANCE; 90 91 private ListView mListView; 92 93 private boolean mOpenRequested; 94 private boolean mResumed; 95 96 // True if a drag is currently in progress 97 private boolean mDragInProgress = false; 98 // The mailbox id of the dragged item's mailbox. We use it to prevent that box from being a 99 // valid drop target 100 private long mDragItemMailboxId = -1; 101 // The adapter position that the user's finger is hovering over 102 private int mDropTargetAdapterPosition = NO_DROP_TARGET; 103 // The mailbox list item view that the user's finger is hovering over 104 private MailboxListItem mDropTargetView; 105 // Lazily instantiated height of a mailbox list item (-1 is a sentinel for 'not initialized') 106 private int mDragItemHeight = -1; 107 // True if we are currently scrolling under the drag item 108 private boolean mTargetScrolling; 109 110 private Utility.ListStateSaver mSavedListState; 111 112 private MailboxesAdapter.Callback mMailboxesAdapterCallback = new MailboxesAdapter.Callback() { 113 @Override 114 public void onSetDropTargetBackground(MailboxListItem listItem) { 115 listItem.setDropTargetBackground(mDragInProgress, mDragItemMailboxId); 116 } 117 }; 118 119 /** 120 * Callback interface that owning activities must implement 121 */ 122 public interface Callback { 123 /** Called when a mailbox (including combined mailbox) is selected. */ 124 public void onMailboxSelected(long accountId, long mailboxId); 125 126 /** Called when an account is selected on the combined view. */ 127 public void onAccountSelected(long accountId); 128 129 /** 130 * Called when the list updates to propagate the current mailbox name and the unread count 131 * for it. 132 * 133 * Note the reason why it's separated from onMailboxSelected is because this needs to be 134 * reported when the unread count changes without changing the current mailbox. 135 */ 136 public void onCurrentMailboxUpdated(long mailboxId, String mailboxName, int unreadCount); 137 } 138 139 private static class EmptyCallback implements Callback { 140 public static final Callback INSTANCE = new EmptyCallback(); 141 @Override public void onMailboxSelected(long accountId, long mailboxId) { } 142 @Override public void onAccountSelected(long accountId) { } 143 @Override public void onCurrentMailboxUpdated(long mailboxId, String mailboxName, 144 int unreadCount) { } 145 } 146 147 /** 148 * Called to do initial creation of a fragment. This is called after 149 * {@link #onAttach(Activity)} and before {@link #onActivityCreated(Bundle)}. 150 */ 151 @Override 152 public void onCreate(Bundle savedInstanceState) { 153 if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { 154 Log.d(Email.LOG_TAG, "MailboxListFragment onCreate"); 155 } 156 super.onCreate(savedInstanceState); 157 158 mActivity = getActivity(); 159 mRefreshManager = RefreshManager.getInstance(mActivity); 160 mListAdapter = new MailboxesAdapter(mActivity, MailboxesAdapter.MODE_NORMAL, 161 mMailboxesAdapterCallback); 162 if (savedInstanceState != null) { 163 restoreInstanceState(savedInstanceState); 164 } 165 if (sDropTrashColor == null) { 166 Resources res = getResources(); 167 sDropTrashColor = res.getColor(R.color.mailbox_drop_destructive_bg_color); 168 sDropActiveDrawable = res.getDrawable(R.drawable.list_activated_holo); 169 } 170 } 171 172 @Override 173 public View onCreateView( 174 LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 175 return inflater.inflate(R.layout.mailbox_list_fragment, container, false); 176 } 177 178 @Override 179 public void onActivityCreated(Bundle savedInstanceState) { 180 if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { 181 Log.d(Email.LOG_TAG, "MailboxListFragment onActivityCreated"); 182 } 183 super.onActivityCreated(savedInstanceState); 184 185 mListView = getListView(); 186 mListView.setOnItemClickListener(this); 187 mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); 188 mListView.setOnDragListener(this); 189 registerForContextMenu(mListView); 190 } 191 192 public void setCallback(Callback callback) { 193 mCallback = (callback == null) ? EmptyCallback.INSTANCE : callback; 194 } 195 196 /** 197 * @param accountId the account we're looking at 198 */ 199 public void openMailboxes(long accountId) { 200 if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { 201 Log.d(Email.LOG_TAG, "MailboxListFragment openMailboxes"); 202 } 203 if (accountId == -1) { 204 throw new InvalidParameterException(); 205 } 206 if (mAccountId == accountId) { 207 return; 208 } 209 mOpenRequested = true; 210 mAccountId = accountId; 211 if (mResumed) { 212 startLoading(); 213 } 214 } 215 216 public void setSelectedMailbox(long mailboxId) { 217 mSelectedMailboxId = mailboxId; 218 if (mResumed) { 219 highlightSelectedMailbox(true); 220 } 221 } 222 223 /** 224 * Called when the Fragment is visible to the user. 225 */ 226 @Override 227 public void onStart() { 228 if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { 229 Log.d(Email.LOG_TAG, "MailboxListFragment onStart"); 230 } 231 super.onStart(); 232 } 233 234 /** 235 * Called when the fragment is visible to the user and actively running. 236 */ 237 @Override 238 public void onResume() { 239 if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { 240 Log.d(Email.LOG_TAG, "MailboxListFragment onResume"); 241 } 242 super.onResume(); 243 mResumed = true; 244 245 // If we're recovering from the stopped state, we don't have to reload. 246 // (when mOpenRequested = false) 247 if (mAccountId != -1 && mOpenRequested) { 248 startLoading(); 249 } 250 } 251 252 @Override 253 public void onPause() { 254 if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { 255 Log.d(Email.LOG_TAG, "MailboxListFragment onPause"); 256 } 257 mResumed = false; 258 super.onPause(); 259 mSavedListState = new Utility.ListStateSaver(getListView()); 260 } 261 262 /** 263 * Called when the Fragment is no longer started. 264 */ 265 @Override 266 public void onStop() { 267 if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { 268 Log.d(Email.LOG_TAG, "MailboxListFragment onStop"); 269 } 270 super.onStop(); 271 } 272 273 /** 274 * Called when the fragment is no longer in use. 275 */ 276 @Override 277 public void onDestroy() { 278 if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { 279 Log.d(Email.LOG_TAG, "MailboxListFragment onDestroy"); 280 } 281 super.onDestroy(); 282 } 283 284 @Override 285 public void onSaveInstanceState(Bundle outState) { 286 if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { 287 Log.d(Email.LOG_TAG, "MailboxListFragment onSaveInstanceState"); 288 } 289 super.onSaveInstanceState(outState); 290 outState.putLong(BUNDLE_KEY_SELECTED_MAILBOX_ID, mSelectedMailboxId); 291 outState.putParcelable(BUNDLE_LIST_STATE, new Utility.ListStateSaver(getListView())); 292 } 293 294 private void restoreInstanceState(Bundle savedInstanceState) { 295 mSelectedMailboxId = savedInstanceState.getLong(BUNDLE_KEY_SELECTED_MAILBOX_ID); 296 mSavedListState = savedInstanceState.getParcelable(BUNDLE_LIST_STATE); 297 } 298 299 private void startLoading() { 300 if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { 301 Log.d(Email.LOG_TAG, "MailboxListFragment startLoading"); 302 } 303 mOpenRequested = false; 304 // Clear the list. (ListFragment will show the "Loading" animation) 305 setListShown(false); 306 307 // If we've already loaded for a different account, discard the previous result and 308 // start loading again. 309 // We don't want to use restartLoader(), because if the Loader is retained, we *do* want to 310 // reuse the previous result. 311 // Also, when changing accounts, we don't preserve scroll position. 312 boolean accountChanging = false; 313 if ((mLastLoadedAccountId != -1) && (mLastLoadedAccountId != mAccountId)) { 314 accountChanging = true; 315 getLoaderManager().destroyLoader(LOADER_ID_MAILBOX_LIST); 316 317 // Also, when we're changing account, update the mailbox list if stale. 318 refreshMailboxListIfStale(); 319 } 320 getLoaderManager().initLoader(LOADER_ID_MAILBOX_LIST, null, 321 new MailboxListLoaderCallbacks(accountChanging)); 322 } 323 324 private class MailboxListLoaderCallbacks implements LoaderCallbacks<Cursor> { 325 private boolean mAccountChanging; 326 327 public MailboxListLoaderCallbacks(boolean accountChanging) { 328 mAccountChanging = accountChanging; 329 } 330 331 @Override 332 public Loader<Cursor> onCreateLoader(int id, Bundle args) { 333 if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { 334 Log.d(Email.LOG_TAG, "MailboxListFragment onCreateLoader"); 335 } 336 return MailboxesAdapter.createLoader(getActivity(), mAccountId, 337 MailboxesAdapter.MODE_NORMAL); 338 } 339 340 @Override 341 public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { 342 if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { 343 Log.d(Email.LOG_TAG, "MailboxListFragment onLoadFinished"); 344 } 345 mLastLoadedAccountId = mAccountId; 346 347 // Save list view state (primarily scroll position) 348 final ListView lv = getListView(); 349 final Utility.ListStateSaver lss; 350 if (mAccountChanging) { 351 lss = null; // Don't preserve list state 352 } else if (mSavedListState != null) { 353 lss = mSavedListState; 354 mSavedListState = null; 355 } else { 356 lss = new Utility.ListStateSaver(lv); 357 } 358 359 if (cursor.getCount() == 0) { 360 // If there's no row, don't set it to the ListView. 361 // Instead use setListShown(false) to make ListFragment show progress icon. 362 mListAdapter.swapCursor(null); 363 setListShown(false); 364 } else { 365 // Set the adapter. 366 mListAdapter.swapCursor(cursor); 367 setListAdapter(mListAdapter); 368 setListShown(true); 369 370 // We want to make selection visible only when account is changing.. 371 // i.e. Refresh caused by content changed events shouldn't scroll the list. 372 highlightSelectedMailbox(mAccountChanging); 373 } 374 375 // Restore the state 376 if (lss != null) { 377 lss.restore(lv); 378 } 379 380 // Clear this for next reload triggered by content changed events. 381 mAccountChanging = false; 382 } 383 384 @Override 385 public void onLoaderReset(Loader<Cursor> loader) { 386 mListAdapter.swapCursor(null); 387 } 388 } 389 390 public void onItemClick(AdapterView<?> parent, View view, int position, 391 long idDontUseIt /* see MailboxesAdapter */ ) { 392 final long id = mListAdapter.getId(position); 393 if (mListAdapter.isAccountRow(position)) { 394 mCallback.onAccountSelected(id); 395 } else { 396 mCallback.onMailboxSelected(mAccountId, id); 397 } 398 } 399 400 public void onRefresh() { 401 if (mAccountId != -1) { 402 mRefreshManager.refreshMailboxList(mAccountId); 403 } 404 } 405 406 private void refreshMailboxListIfStale() { 407 if (mRefreshManager.isMailboxListStale(mAccountId)) { 408 mRefreshManager.refreshMailboxList(mAccountId); 409 } 410 } 411 412 /** 413 * Highlight the selected mailbox. 414 */ 415 private void highlightSelectedMailbox(boolean ensureSelectionVisible) { 416 String mailboxName = ""; 417 int unreadCount = 0; 418 if (mSelectedMailboxId == -1) { 419 // No mailbox selected 420 mListView.clearChoices(); 421 } else { 422 final int count = mListView.getCount(); 423 for (int i = 0; i < count; i++) { 424 if (mListAdapter.getId(i) != mSelectedMailboxId) { 425 continue; 426 } 427 mListView.setItemChecked(i, true); 428 if (ensureSelectionVisible) { 429 Utility.listViewSmoothScrollToPosition(getActivity(), mListView, i); 430 } 431 mailboxName = mListAdapter.getDisplayName(i); 432 unreadCount = mListAdapter.getUnreadCount(i); 433 break; 434 } 435 } 436 mCallback.onCurrentMailboxUpdated(mSelectedMailboxId, mailboxName, unreadCount); 437 } 438 439 // Drag & Drop handling 440 441 /** 442 * Update all of the list's child views with the proper target background (for now, orange if 443 * a valid target, except red if the trash; standard background otherwise) 444 */ 445 private void updateChildViews() { 446 int itemCount = mListView.getChildCount(); 447 // Lazily initialize the height of our list items 448 if (itemCount > 0 && mDragItemHeight < 0) { 449 mDragItemHeight = mListView.getChildAt(0).getHeight(); 450 } 451 for (int i = 0; i < itemCount; i++) { 452 MailboxListItem item = (MailboxListItem)mListView.getChildAt(i); 453 item.setDropTargetBackground(mDragInProgress, mDragItemMailboxId); 454 } 455 } 456 457 /** 458 * Called when our ListView gets a DRAG_EXITED event 459 */ 460 private void onDragExited() { 461 // Reset the background of the current target 462 if (mDropTargetAdapterPosition != NO_DROP_TARGET) { 463 mDropTargetView.setDropTargetBackground(mDragInProgress, mDragItemMailboxId); 464 mDropTargetAdapterPosition = NO_DROP_TARGET; 465 } 466 stopScrolling(); 467 } 468 469 /** 470 * STOPSHIP: Very preliminary scrolling code 471 */ 472 private void onDragLocation(DragEvent event) { 473 // The drag is somewhere in the ListView 474 if (mDragItemHeight <= 0) { 475 // This shouldn't be possible, but avoid NPE 476 return; 477 } 478 // Find out which item we're in and highlight as appropriate 479 int rawTouchY = (int)event.getY(); 480 int offset = 0; 481 if (mListView.getCount() > 0) { 482 offset = mListView.getChildAt(0).getTop(); 483 } 484 int targetScreenPosition = (rawTouchY - offset) / mDragItemHeight; 485 int firstVisibleItem = mListView.getFirstVisiblePosition(); 486 int targetAdapterPosition = firstVisibleItem + targetScreenPosition; 487 if (targetAdapterPosition != mDropTargetAdapterPosition) { 488 if (DEBUG_DRAG_DROP) { 489 Log.d(TAG, "========== DROP TARGET " + mDropTargetAdapterPosition + " -> " + 490 targetAdapterPosition); 491 } 492 // Unhighlight the current target, if we've got one 493 if (mDropTargetAdapterPosition != NO_DROP_TARGET) { 494 mDropTargetView.setDropTargetBackground(true, mDragItemMailboxId); 495 } 496 // Get the new target mailbox view 497 MailboxListItem newTarget = 498 (MailboxListItem)mListView.getChildAt(targetScreenPosition); 499 // This can be null due to a bug in the framework (checking on that) 500 // In any event, we're no longer dragging in the list view if newTarget is null 501 if (newTarget == null) { 502 if (DEBUG_DRAG_DROP) { 503 Log.d(TAG, "========== WTF??? DRAG EXITED"); 504 } 505 onDragExited(); 506 return; 507 } else if (newTarget.mMailboxType == Mailbox.TYPE_TRASH) { 508 Log.d("onDragLocation", "=== Mailbox " + newTarget.mMailboxId + " TRASH"); 509 newTarget.setBackgroundColor(sDropTrashColor); 510 } else if (newTarget.isDropTarget(mDragItemMailboxId)) { 511 Log.d("onDragLocation", "=== Mailbox " + newTarget.mMailboxId + " TARGET"); 512 newTarget.setBackgroundDrawable(sDropActiveDrawable); 513 } else { 514 Log.d("onDragLocation", "=== Mailbox " + newTarget.mMailboxId + " (CALL)"); 515 targetAdapterPosition = NO_DROP_TARGET; 516 newTarget.setDropTargetBackground(true, mDragItemMailboxId); 517 } 518 // Save away our current position and view 519 mDropTargetAdapterPosition = targetAdapterPosition; 520 mDropTargetView = newTarget; 521 } 522 523 // This is a quick-and-dirty implementation of drag-under-scroll; something like this 524 // should eventually find its way into the framework 525 int scrollDiff = rawTouchY - (mListView.getHeight() - SCROLL_ZONE_SIZE); 526 boolean scrollDown = (scrollDiff > 0); 527 boolean scrollUp = (SCROLL_ZONE_SIZE > rawTouchY); 528 if (!mTargetScrolling && scrollDown) { 529 int itemsToScroll = mListView.getCount() - targetAdapterPosition; 530 int pixelsToScroll = (itemsToScroll + 1) * mDragItemHeight; 531 mListView.smoothScrollBy(pixelsToScroll, pixelsToScroll * SCROLL_SPEED); 532 if (DEBUG_DRAG_DROP) { 533 Log.d(TAG, "========== START TARGET SCROLLING DOWN"); 534 } 535 mTargetScrolling = true; 536 } else if (!mTargetScrolling && scrollUp) { 537 int pixelsToScroll = (firstVisibleItem + 1) * mDragItemHeight; 538 mListView.smoothScrollBy(-pixelsToScroll, pixelsToScroll * SCROLL_SPEED); 539 if (DEBUG_DRAG_DROP) { 540 Log.d(TAG, "========== START TARGET SCROLLING UP"); 541 } 542 mTargetScrolling = true; 543 } else if (!scrollUp && !scrollDown) { 544 stopScrolling(); 545 } 546 } 547 548 /** 549 * Indicate that scrolling has stopped 550 */ 551 private void stopScrolling() { 552 if (mTargetScrolling) { 553 mTargetScrolling = false; 554 if (DEBUG_DRAG_DROP) { 555 Log.d(TAG, "========== STOP TARGET SCROLLING"); 556 } 557 // Stop the scrolling 558 mListView.smoothScrollBy(0, 0); 559 } 560 } 561 562 private void onDragEnded() { 563 if (mDragInProgress) { 564 mDragInProgress = false; 565 // Reenable updates to the view and redraw (in case it changed) 566 mListAdapter.enableUpdates(true); 567 mListAdapter.notifyDataSetChanged(); 568 // Stop highlighting targets 569 updateChildViews(); 570 // Stop any scrolling that was going on 571 stopScrolling(); 572 } 573 } 574 575 private boolean onDragStarted(DragEvent event) { 576 // We handle dropping of items with our email mime type 577 // If the mime type has a mailbox id appended, that is the mailbox of the item 578 // being draged 579 ClipDescription description = event.getClipDescription(); 580 int mimeTypeCount = description.getMimeTypeCount(); 581 for (int i = 0; i < mimeTypeCount; i++) { 582 String mimeType = description.getMimeType(i); 583 if (mimeType.startsWith(EmailProvider.EMAIL_MESSAGE_MIME_TYPE)) { 584 if (DEBUG_DRAG_DROP) { 585 Log.d(TAG, "========== DRAG STARTED"); 586 } 587 mDragItemMailboxId = -1; 588 // See if we find a mailbox id here 589 int dash = mimeType.lastIndexOf('-'); 590 if (dash > 0) { 591 try { 592 mDragItemMailboxId = Long.parseLong(mimeType.substring(dash + 1)); 593 } catch (NumberFormatException e) { 594 // Ignore; we just won't know the mailbox 595 } 596 } 597 mDragInProgress = true; 598 // Stop the list from updating 599 mListAdapter.enableUpdates(false); 600 // Update the backgrounds of our child views to highlight drop targets 601 updateChildViews(); 602 return true; 603 } 604 } 605 return false; 606 } 607 608 private boolean onDrop(DragEvent event) { 609 stopScrolling(); 610 // If we're not on a target, we're done 611 if (mDropTargetAdapterPosition == NO_DROP_TARGET) return false; 612 final Controller controller = Controller.getInstance(mActivity); 613 ClipData clipData = event.getClipData(); 614 int count = clipData.getItemCount(); 615 if (DEBUG_DRAG_DROP) { 616 Log.d(TAG, "Received a drop of " + count + " items."); 617 } 618 // Extract the messageId's to move from the ClipData (set up in MessageListItem) 619 final long[] messageIds = new long[count]; 620 for (int i = 0; i < count; i++) { 621 Uri uri = clipData.getItemAt(i).getUri(); 622 String msgNum = uri.getPathSegments().get(1); 623 long id = Long.parseLong(msgNum); 624 messageIds[i] = id; 625 } 626 // Call either deleteMessage or moveMessage, depending on the target 627 Utility.runAsync(new Runnable() { 628 @Override 629 public void run() { 630 if (mDropTargetView.mMailboxType == Mailbox.TYPE_TRASH) { 631 for (long messageId: messageIds) { 632 // TODO Get this off UI thread (put in clip) 633 Message msg = Message.restoreMessageWithId(mActivity, messageId); 634 if (msg != null) { 635 controller.deleteMessage(messageId, msg.mAccountKey); 636 } 637 } 638 } else { 639 controller.moveMessage(messageIds, mDropTargetView.mMailboxId); 640 } 641 }}); 642 return true; 643 } 644 645 @Override 646 public boolean onDrag(View view, DragEvent event) { 647 boolean result = false; 648 switch (event.getAction()) { 649 case DragEvent.ACTION_DRAG_STARTED: 650 result = onDragStarted(event); 651 break; 652 case DragEvent.ACTION_DRAG_ENTERED: 653 // The drag has entered the ListView window 654 if (DEBUG_DRAG_DROP) { 655 Log.d(TAG, "========== DRAG ENTERED (target = " + mDropTargetAdapterPosition + 656 ")"); 657 } 658 break; 659 case DragEvent.ACTION_DRAG_EXITED: 660 // The drag has left the building 661 if (DEBUG_DRAG_DROP) { 662 Log.d(TAG, "========== DRAG EXITED (target = " + mDropTargetAdapterPosition + 663 ")"); 664 } 665 onDragExited(); 666 break; 667 case DragEvent.ACTION_DRAG_ENDED: 668 // The drag is over 669 if (DEBUG_DRAG_DROP) { 670 Log.d(TAG, "========== DRAG ENDED"); 671 } 672 onDragEnded(); 673 break; 674 case DragEvent.ACTION_DRAG_LOCATION: 675 // We're moving around within our window; handle scroll, if necessary 676 onDragLocation(event); 677 break; 678 case DragEvent.ACTION_DROP: 679 // The drag item was dropped 680 if (DEBUG_DRAG_DROP) { 681 Log.d(TAG, "========== DROP"); 682 } 683 result = onDrop(event); 684 break; 685 default: 686 break; 687 } 688 return result; 689 } 690} 691