ActionMenuPresenter.java revision 058ac7cfe5bb7b9ecc411b94622ac3f31a7fa25e
1/* 2 * Copyright (C) 2011 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.internal.view.menu; 18 19import android.content.Context; 20import android.content.res.Configuration; 21import android.content.res.Resources; 22import android.os.Parcel; 23import android.os.Parcelable; 24import android.util.SparseBooleanArray; 25import android.view.ActionProvider; 26import android.view.MenuItem; 27import android.view.MotionEvent; 28import android.view.SoundEffectConstants; 29import android.view.View; 30import android.view.ViewConfiguration; 31import android.view.View.MeasureSpec; 32import android.view.accessibility.AccessibilityNodeInfo; 33import android.view.ViewGroup; 34import android.widget.ImageButton; 35 36import com.android.internal.view.ActionBarPolicy; 37import com.android.internal.view.menu.ActionMenuView.ActionMenuChildView; 38 39import java.util.ArrayList; 40 41/** 42 * MenuPresenter for building action menus as seen in the action bar and action modes. 43 */ 44public class ActionMenuPresenter extends BaseMenuPresenter 45 implements ActionProvider.SubUiVisibilityListener { 46 private static final String TAG = "ActionMenuPresenter"; 47 48 private View mOverflowButton; 49 private boolean mReserveOverflow; 50 private boolean mReserveOverflowSet; 51 private int mWidthLimit; 52 private int mActionItemWidthLimit; 53 private int mMaxItems; 54 private boolean mMaxItemsSet; 55 private boolean mStrictWidthLimit; 56 private boolean mWidthLimitSet; 57 private boolean mExpandedActionViewsExclusive; 58 59 private int mMinCellSize; 60 61 // Group IDs that have been added as actions - used temporarily, allocated here for reuse. 62 private final SparseBooleanArray mActionButtonGroups = new SparseBooleanArray(); 63 64 private View mScrapActionButtonView; 65 66 private OverflowPopup mOverflowPopup; 67 private ActionButtonSubmenu mActionButtonPopup; 68 69 private OpenOverflowRunnable mPostedOpenRunnable; 70 71 final PopupPresenterCallback mPopupPresenterCallback = new PopupPresenterCallback(); 72 int mOpenSubMenuId; 73 74 public ActionMenuPresenter(Context context) { 75 super(context, com.android.internal.R.layout.action_menu_layout, 76 com.android.internal.R.layout.action_menu_item_layout); 77 } 78 79 @Override 80 public void initForMenu(Context context, MenuBuilder menu) { 81 super.initForMenu(context, menu); 82 83 final Resources res = context.getResources(); 84 85 final ActionBarPolicy abp = ActionBarPolicy.get(context); 86 if (!mReserveOverflowSet) { 87 mReserveOverflow = abp.showsOverflowMenuButton(); 88 } 89 90 if (!mWidthLimitSet) { 91 mWidthLimit = abp.getEmbeddedMenuWidthLimit(); 92 } 93 94 // Measure for initial configuration 95 if (!mMaxItemsSet) { 96 mMaxItems = abp.getMaxActionButtons(); 97 } 98 99 int width = mWidthLimit; 100 if (mReserveOverflow) { 101 if (mOverflowButton == null) { 102 mOverflowButton = new OverflowMenuButton(mSystemContext); 103 final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 104 mOverflowButton.measure(spec, spec); 105 } 106 width -= mOverflowButton.getMeasuredWidth(); 107 } else { 108 mOverflowButton = null; 109 } 110 111 mActionItemWidthLimit = width; 112 113 mMinCellSize = (int) (ActionMenuView.MIN_CELL_SIZE * res.getDisplayMetrics().density); 114 115 // Drop a scrap view as it may no longer reflect the proper context/config. 116 mScrapActionButtonView = null; 117 } 118 119 public void onConfigurationChanged(Configuration newConfig) { 120 if (!mMaxItemsSet) { 121 mMaxItems = mContext.getResources().getInteger( 122 com.android.internal.R.integer.max_action_buttons); 123 } 124 if (mMenu != null) { 125 mMenu.onItemsChanged(true); 126 } 127 } 128 129 public void setWidthLimit(int width, boolean strict) { 130 mWidthLimit = width; 131 mStrictWidthLimit = strict; 132 mWidthLimitSet = true; 133 } 134 135 public void setReserveOverflow(boolean reserveOverflow) { 136 mReserveOverflow = reserveOverflow; 137 mReserveOverflowSet = true; 138 } 139 140 public void setItemLimit(int itemCount) { 141 mMaxItems = itemCount; 142 mMaxItemsSet = true; 143 } 144 145 public void setExpandedActionViewsExclusive(boolean isExclusive) { 146 mExpandedActionViewsExclusive = isExclusive; 147 } 148 149 @Override 150 public MenuView getMenuView(ViewGroup root) { 151 MenuView result = super.getMenuView(root); 152 ((ActionMenuView) result).setPresenter(this); 153 return result; 154 } 155 156 @Override 157 public View getItemView(MenuItemImpl item, View convertView, ViewGroup parent) { 158 View actionView = item.getActionView(); 159 if (actionView == null || item.hasCollapsibleActionView()) { 160 if (!(convertView instanceof ActionMenuItemView)) { 161 convertView = null; 162 } 163 actionView = super.getItemView(item, convertView, parent); 164 } 165 actionView.setVisibility(item.isActionViewExpanded() ? View.GONE : View.VISIBLE); 166 167 final ActionMenuView menuParent = (ActionMenuView) parent; 168 final ViewGroup.LayoutParams lp = actionView.getLayoutParams(); 169 if (!menuParent.checkLayoutParams(lp)) { 170 actionView.setLayoutParams(menuParent.generateLayoutParams(lp)); 171 } 172 return actionView; 173 } 174 175 @Override 176 public void bindItemView(MenuItemImpl item, MenuView.ItemView itemView) { 177 itemView.initialize(item, 0); 178 179 final ActionMenuView menuView = (ActionMenuView) mMenuView; 180 ActionMenuItemView actionItemView = (ActionMenuItemView) itemView; 181 actionItemView.setItemInvoker(menuView); 182 } 183 184 @Override 185 public boolean shouldIncludeItem(int childIndex, MenuItemImpl item) { 186 return item.isActionButton(); 187 } 188 189 @Override 190 public void updateMenuView(boolean cleared) { 191 super.updateMenuView(cleared); 192 193 if (mMenu != null) { 194 final ArrayList<MenuItemImpl> actionItems = mMenu.getActionItems(); 195 final int count = actionItems.size(); 196 for (int i = 0; i < count; i++) { 197 final ActionProvider provider = actionItems.get(i).getActionProvider(); 198 if (provider != null) { 199 provider.setSubUiVisibilityListener(this); 200 } 201 } 202 } 203 204 final ArrayList<MenuItemImpl> nonActionItems = mMenu != null ? 205 mMenu.getNonActionItems() : null; 206 207 boolean hasOverflow = false; 208 if (mReserveOverflow && nonActionItems != null) { 209 final int count = nonActionItems.size(); 210 if (count == 1) { 211 hasOverflow = !nonActionItems.get(0).isActionViewExpanded(); 212 } else { 213 hasOverflow = count > 0; 214 } 215 } 216 217 if (hasOverflow) { 218 if (mOverflowButton == null) { 219 mOverflowButton = new OverflowMenuButton(mSystemContext); 220 } 221 ViewGroup parent = (ViewGroup) mOverflowButton.getParent(); 222 if (parent != mMenuView) { 223 if (parent != null) { 224 parent.removeView(mOverflowButton); 225 } 226 ActionMenuView menuView = (ActionMenuView) mMenuView; 227 menuView.addView(mOverflowButton, menuView.generateOverflowButtonLayoutParams()); 228 } 229 } else if (mOverflowButton != null && mOverflowButton.getParent() == mMenuView) { 230 ((ViewGroup) mMenuView).removeView(mOverflowButton); 231 } 232 233 ((ActionMenuView) mMenuView).setOverflowReserved(mReserveOverflow); 234 } 235 236 @Override 237 public boolean filterLeftoverView(ViewGroup parent, int childIndex) { 238 if (parent.getChildAt(childIndex) == mOverflowButton) return false; 239 return super.filterLeftoverView(parent, childIndex); 240 } 241 242 public boolean onSubMenuSelected(SubMenuBuilder subMenu) { 243 if (!subMenu.hasVisibleItems()) return false; 244 245 SubMenuBuilder topSubMenu = subMenu; 246 while (topSubMenu.getParentMenu() != mMenu) { 247 topSubMenu = (SubMenuBuilder) topSubMenu.getParentMenu(); 248 } 249 View anchor = findViewForItem(topSubMenu.getItem()); 250 if (anchor == null) { 251 if (mOverflowButton == null) return false; 252 anchor = mOverflowButton; 253 } 254 255 mOpenSubMenuId = subMenu.getItem().getItemId(); 256 mActionButtonPopup = new ActionButtonSubmenu(mContext, subMenu); 257 mActionButtonPopup.setAnchorView(anchor); 258 mActionButtonPopup.show(); 259 super.onSubMenuSelected(subMenu); 260 return true; 261 } 262 263 private View findViewForItem(MenuItem item) { 264 final ViewGroup parent = (ViewGroup) mMenuView; 265 if (parent == null) return null; 266 267 final int count = parent.getChildCount(); 268 for (int i = 0; i < count; i++) { 269 final View child = parent.getChildAt(i); 270 if (child instanceof MenuView.ItemView && 271 ((MenuView.ItemView) child).getItemData() == item) { 272 return child; 273 } 274 } 275 return null; 276 } 277 278 /** 279 * Display the overflow menu if one is present. 280 * @return true if the overflow menu was shown, false otherwise. 281 */ 282 public boolean showOverflowMenu() { 283 if (mReserveOverflow && !isOverflowMenuShowing() && mMenu != null && mMenuView != null && 284 mPostedOpenRunnable == null && !mMenu.getNonActionItems().isEmpty()) { 285 OverflowPopup popup = new OverflowPopup(mContext, mMenu, mOverflowButton, true); 286 mPostedOpenRunnable = new OpenOverflowRunnable(popup); 287 // Post this for later; we might still need a layout for the anchor to be right. 288 ((View) mMenuView).post(mPostedOpenRunnable); 289 290 // ActionMenuPresenter uses null as a callback argument here 291 // to indicate overflow is opening. 292 super.onSubMenuSelected(null); 293 294 return true; 295 } 296 return false; 297 } 298 299 /** 300 * Hide the overflow menu if it is currently showing. 301 * 302 * @return true if the overflow menu was hidden, false otherwise. 303 */ 304 public boolean hideOverflowMenu() { 305 if (mPostedOpenRunnable != null && mMenuView != null) { 306 ((View) mMenuView).removeCallbacks(mPostedOpenRunnable); 307 mPostedOpenRunnable = null; 308 return true; 309 } 310 311 MenuPopupHelper popup = mOverflowPopup; 312 if (popup != null) { 313 popup.dismiss(); 314 return true; 315 } 316 return false; 317 } 318 319 /** 320 * Dismiss all popup menus - overflow and submenus. 321 * @return true if popups were dismissed, false otherwise. (This can be because none were open.) 322 */ 323 public boolean dismissPopupMenus() { 324 boolean result = hideOverflowMenu(); 325 result |= hideSubMenus(); 326 return result; 327 } 328 329 /** 330 * Dismiss all submenu popups. 331 * 332 * @return true if popups were dismissed, false otherwise. (This can be because none were open.) 333 */ 334 public boolean hideSubMenus() { 335 if (mActionButtonPopup != null) { 336 mActionButtonPopup.dismiss(); 337 return true; 338 } 339 return false; 340 } 341 342 /** 343 * @return true if the overflow menu is currently showing 344 */ 345 public boolean isOverflowMenuShowing() { 346 return mOverflowPopup != null && mOverflowPopup.isShowing(); 347 } 348 349 /** 350 * @return true if space has been reserved in the action menu for an overflow item. 351 */ 352 public boolean isOverflowReserved() { 353 return mReserveOverflow; 354 } 355 356 public boolean flagActionItems() { 357 final ArrayList<MenuItemImpl> visibleItems = mMenu.getVisibleItems(); 358 final int itemsSize = visibleItems.size(); 359 int maxActions = mMaxItems; 360 int widthLimit = mActionItemWidthLimit; 361 final int querySpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 362 final ViewGroup parent = (ViewGroup) mMenuView; 363 364 int requiredItems = 0; 365 int requestedItems = 0; 366 int firstActionWidth = 0; 367 boolean hasOverflow = false; 368 for (int i = 0; i < itemsSize; i++) { 369 MenuItemImpl item = visibleItems.get(i); 370 if (item.requiresActionButton()) { 371 requiredItems++; 372 } else if (item.requestsActionButton()) { 373 requestedItems++; 374 } else { 375 hasOverflow = true; 376 } 377 if (mExpandedActionViewsExclusive && item.isActionViewExpanded()) { 378 // Overflow everything if we have an expanded action view and we're 379 // space constrained. 380 maxActions = 0; 381 } 382 } 383 384 // Reserve a spot for the overflow item if needed. 385 if (mReserveOverflow && 386 (hasOverflow || requiredItems + requestedItems > maxActions)) { 387 maxActions--; 388 } 389 maxActions -= requiredItems; 390 391 final SparseBooleanArray seenGroups = mActionButtonGroups; 392 seenGroups.clear(); 393 394 int cellSize = 0; 395 int cellsRemaining = 0; 396 if (mStrictWidthLimit) { 397 cellsRemaining = widthLimit / mMinCellSize; 398 final int cellSizeRemaining = widthLimit % mMinCellSize; 399 cellSize = mMinCellSize + cellSizeRemaining / cellsRemaining; 400 } 401 402 // Flag as many more requested items as will fit. 403 for (int i = 0; i < itemsSize; i++) { 404 MenuItemImpl item = visibleItems.get(i); 405 406 if (item.requiresActionButton()) { 407 View v = getItemView(item, mScrapActionButtonView, parent); 408 if (mScrapActionButtonView == null) { 409 mScrapActionButtonView = v; 410 } 411 if (mStrictWidthLimit) { 412 cellsRemaining -= ActionMenuView.measureChildForCells(v, 413 cellSize, cellsRemaining, querySpec, 0); 414 } else { 415 v.measure(querySpec, querySpec); 416 } 417 final int measuredWidth = v.getMeasuredWidth(); 418 widthLimit -= measuredWidth; 419 if (firstActionWidth == 0) { 420 firstActionWidth = measuredWidth; 421 } 422 final int groupId = item.getGroupId(); 423 if (groupId != 0) { 424 seenGroups.put(groupId, true); 425 } 426 item.setIsActionButton(true); 427 } else if (item.requestsActionButton()) { 428 // Items in a group with other items that already have an action slot 429 // can break the max actions rule, but not the width limit. 430 final int groupId = item.getGroupId(); 431 final boolean inGroup = seenGroups.get(groupId); 432 boolean isAction = (maxActions > 0 || inGroup) && widthLimit > 0 && 433 (!mStrictWidthLimit || cellsRemaining > 0); 434 435 if (isAction) { 436 View v = getItemView(item, mScrapActionButtonView, parent); 437 if (mScrapActionButtonView == null) { 438 mScrapActionButtonView = v; 439 } 440 if (mStrictWidthLimit) { 441 final int cells = ActionMenuView.measureChildForCells(v, 442 cellSize, cellsRemaining, querySpec, 0); 443 cellsRemaining -= cells; 444 if (cells == 0) { 445 isAction = false; 446 } 447 } else { 448 v.measure(querySpec, querySpec); 449 } 450 final int measuredWidth = v.getMeasuredWidth(); 451 widthLimit -= measuredWidth; 452 if (firstActionWidth == 0) { 453 firstActionWidth = measuredWidth; 454 } 455 456 if (mStrictWidthLimit) { 457 isAction &= widthLimit >= 0; 458 } else { 459 // Did this push the entire first item past the limit? 460 isAction &= widthLimit + firstActionWidth > 0; 461 } 462 } 463 464 if (isAction && groupId != 0) { 465 seenGroups.put(groupId, true); 466 } else if (inGroup) { 467 // We broke the width limit. Demote the whole group, they all overflow now. 468 seenGroups.put(groupId, false); 469 for (int j = 0; j < i; j++) { 470 MenuItemImpl areYouMyGroupie = visibleItems.get(j); 471 if (areYouMyGroupie.getGroupId() == groupId) { 472 // Give back the action slot 473 if (areYouMyGroupie.isActionButton()) maxActions++; 474 areYouMyGroupie.setIsActionButton(false); 475 } 476 } 477 } 478 479 if (isAction) maxActions--; 480 481 item.setIsActionButton(isAction); 482 } else { 483 // Neither requires nor requests an action button. 484 item.setIsActionButton(false); 485 } 486 } 487 return true; 488 } 489 490 @Override 491 public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { 492 dismissPopupMenus(); 493 super.onCloseMenu(menu, allMenusAreClosing); 494 } 495 496 @Override 497 public Parcelable onSaveInstanceState() { 498 SavedState state = new SavedState(); 499 state.openSubMenuId = mOpenSubMenuId; 500 return state; 501 } 502 503 @Override 504 public void onRestoreInstanceState(Parcelable state) { 505 SavedState saved = (SavedState) state; 506 if (saved.openSubMenuId > 0) { 507 MenuItem item = mMenu.findItem(saved.openSubMenuId); 508 if (item != null) { 509 SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu(); 510 onSubMenuSelected(subMenu); 511 } 512 } 513 } 514 515 @Override 516 public void onSubUiVisibilityChanged(boolean isVisible) { 517 if (isVisible) { 518 // Not a submenu, but treat it like one. 519 super.onSubMenuSelected(null); 520 } else { 521 mMenu.close(false); 522 } 523 } 524 525 private static class SavedState implements Parcelable { 526 public int openSubMenuId; 527 528 SavedState() { 529 } 530 531 SavedState(Parcel in) { 532 openSubMenuId = in.readInt(); 533 } 534 535 @Override 536 public int describeContents() { 537 return 0; 538 } 539 540 @Override 541 public void writeToParcel(Parcel dest, int flags) { 542 dest.writeInt(openSubMenuId); 543 } 544 545 public static final Parcelable.Creator<SavedState> CREATOR 546 = new Parcelable.Creator<SavedState>() { 547 public SavedState createFromParcel(Parcel in) { 548 return new SavedState(in); 549 } 550 551 public SavedState[] newArray(int size) { 552 return new SavedState[size]; 553 } 554 }; 555 } 556 557 private class OverflowMenuButton extends ImageButton implements ActionMenuChildView { 558 public OverflowMenuButton(Context context) { 559 super(context, null, com.android.internal.R.attr.actionOverflowButtonStyle); 560 561 setClickable(true); 562 setFocusable(true); 563 setVisibility(VISIBLE); 564 setEnabled(true); 565 setOnTouchListener(new OverflowForwardListener(context)); 566 } 567 568 @Override 569 public boolean performClick() { 570 if (super.performClick()) { 571 return true; 572 } 573 574 playSoundEffect(SoundEffectConstants.CLICK); 575 showOverflowMenu(); 576 return true; 577 } 578 579 @Override 580 public boolean needsDividerBefore() { 581 return false; 582 } 583 584 @Override 585 public boolean needsDividerAfter() { 586 return false; 587 } 588 589 @Override 590 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 591 if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) { 592 // Fill available height 593 heightMeasureSpec = MeasureSpec.makeMeasureSpec( 594 MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.EXACTLY); 595 } 596 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 597 } 598 599 @Override 600 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 601 super.onInitializeAccessibilityNodeInfo(info); 602 info.setOpensPopup(true); 603 } 604 } 605 606 private class OverflowPopup extends MenuPopupHelper { 607 public OverflowPopup(Context context, MenuBuilder menu, View anchorView, 608 boolean overflowOnly) { 609 super(context, menu, anchorView, overflowOnly); 610 setCallback(mPopupPresenterCallback); 611 } 612 613 @Override 614 public void onDismiss() { 615 super.onDismiss(); 616 mMenu.close(); 617 mOverflowPopup = null; 618 } 619 } 620 621 private class ActionButtonSubmenu extends MenuPopupHelper { 622 private SubMenuBuilder mSubMenu; 623 624 public ActionButtonSubmenu(Context context, SubMenuBuilder subMenu) { 625 super(context, subMenu); 626 mSubMenu = subMenu; 627 628 MenuItemImpl item = (MenuItemImpl) subMenu.getItem(); 629 if (!item.isActionButton()) { 630 // Give a reasonable anchor to nested submenus. 631 setAnchorView(mOverflowButton == null ? (View) mMenuView : mOverflowButton); 632 } 633 634 setCallback(mPopupPresenterCallback); 635 636 boolean preserveIconSpacing = false; 637 final int count = subMenu.size(); 638 for (int i = 0; i < count; i++) { 639 MenuItem childItem = subMenu.getItem(i); 640 if (childItem.isVisible() && childItem.getIcon() != null) { 641 preserveIconSpacing = true; 642 break; 643 } 644 } 645 setForceShowIcon(preserveIconSpacing); 646 } 647 648 @Override 649 public void onDismiss() { 650 super.onDismiss(); 651 mActionButtonPopup = null; 652 mOpenSubMenuId = 0; 653 } 654 } 655 656 private class PopupPresenterCallback implements MenuPresenter.Callback { 657 658 @Override 659 public boolean onOpenSubMenu(MenuBuilder subMenu) { 660 if (subMenu == null) return false; 661 662 mOpenSubMenuId = ((SubMenuBuilder) subMenu).getItem().getItemId(); 663 return false; 664 } 665 666 @Override 667 public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { 668 if (menu instanceof SubMenuBuilder) { 669 ((SubMenuBuilder) menu).getRootMenu().close(false); 670 } 671 } 672 } 673 674 private class OpenOverflowRunnable implements Runnable { 675 private OverflowPopup mPopup; 676 677 public OpenOverflowRunnable(OverflowPopup popup) { 678 mPopup = popup; 679 } 680 681 public void run() { 682 mMenu.changeMenuMode(); 683 final View menuView = (View) mMenuView; 684 if (menuView != null && menuView.getWindowToken() != null && mPopup.tryShow()) { 685 mOverflowPopup = mPopup; 686 } 687 mPostedOpenRunnable = null; 688 } 689 } 690 691 private class OverflowForwardListener extends TouchForwardingListener { 692 /** Scaled touch slop, used for detecting movement outside bounds. */ 693 private final float mScaledTouchSlop; 694 695 private int mActivePointerId = MotionEvent.INVALID_POINTER_ID; 696 697 public OverflowForwardListener(Context context) { 698 mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 699 } 700 701 @Override 702 public boolean onTouchObserved(View src, MotionEvent srcEvent) { 703 if (!src.isEnabled()) { 704 return false; 705 } 706 707 // Always start forwarding events when the source view is touched. 708 mActivePointerId = srcEvent.getPointerId(0); 709 src.performClick(); 710 return true; 711 } 712 713 @Override 714 public boolean onTouchForwarded(View src, MotionEvent srcEvent) { 715 final OverflowPopup popup = mOverflowPopup; 716 if (popup != null && popup.isShowing()) { 717 final int activePointerId = mActivePointerId; 718 if (activePointerId != MotionEvent.INVALID_POINTER_ID && src.isEnabled() 719 && popup.forwardMotionEvent(src, srcEvent, activePointerId)) { 720 // Handled the motion event, continue forwarding. 721 return true; 722 } 723 724 final int activePointerIndex = srcEvent.findPointerIndex(activePointerId); 725 if (activePointerIndex >= 0) { 726 final float x = srcEvent.getX(activePointerIndex); 727 final float y = srcEvent.getY(activePointerIndex); 728 if (src.pointInView(x, y, mScaledTouchSlop)) { 729 // The user is touching the source view. Cancel 730 // forwarding, but don't dismiss the popup. 731 return false; 732 } 733 } 734 735 popup.dismiss(); 736 } 737 738 // Cancel forwarding. 739 return false; 740 } 741 } 742} 743