/**
   * Notifies the menu that the contents of the menu item specified by {@code menuRowId} have
   * changed. This should be called if icons, titles, etc. are changing for a particular menu item
   * while the menu is open.
   *
   * @param menuRowId The id of the menu item to change. This must be a row id and not a child id.
   */
  public void menuItemContentChanged(int menuRowId) {
    // Make sure we have all the valid state objects we need.
    if (mAdapter == null || mMenu == null || mPopup == null || mPopup.getListView() == null) {
      return;
    }

    // Calculate the item index.
    int index = -1;
    int menuSize = mMenu.size();
    for (int i = 0; i < menuSize; i++) {
      if (mMenu.getItem(i).getItemId() == menuRowId) {
        index = i;
        break;
      }
    }
    if (index == -1) return;

    // Check if the item is visible.
    ListView list = mPopup.getListView();
    int startIndex = list.getFirstVisiblePosition();
    int endIndex = list.getLastVisiblePosition();
    if (index < startIndex || index > endIndex) return;

    // Grab the correct View.
    View view = list.getChildAt(index - startIndex);
    if (view == null) return;

    // Cause the Adapter to re-populate the View.
    list.getAdapter().getView(index, view, list);
  }
  @Override
  public void onClick(View v) {
    if (UiClosables.closeQuietly(mPopup)) {
      return;
    }

    mAdapter =
        new GroupMembershipAdapter<GroupSelectionItem>(
            getContext(), R.layout.group_membership_list_item);

    mGroupMetaData.moveToPosition(-1);
    while (mGroupMetaData.moveToNext()) {
      String accountName = mGroupMetaData.getString(GroupMetaDataLoader.ACCOUNT_NAME);
      String accountType = mGroupMetaData.getString(GroupMetaDataLoader.ACCOUNT_TYPE);
      String dataSet = mGroupMetaData.getString(GroupMetaDataLoader.DATA_SET);
      if (accountName.equals(mAccountName)
          && accountType.equals(mAccountType)
          && Objects.equal(dataSet, mDataSet)) {
        long groupId = mGroupMetaData.getLong(GroupMetaDataLoader.GROUP_ID);
        if (groupId != mFavoritesGroupId && (groupId != mDefaultGroupId || mDefaultGroupVisible)) {
          String title = mGroupMetaData.getString(GroupMetaDataLoader.TITLE);
          boolean checked = hasMembership(groupId);
          mAdapter.add(new GroupSelectionItem(groupId, title, checked));
        }
      }
    }

    mAdapter.add(
        new GroupSelectionItem(
            CREATE_NEW_GROUP_GROUP_ID,
            getContext().getString(R.string.create_group_item_label),
            false));

    mPopup = new ListPopupWindow(getContext(), null);
    mPopup.setAnchorView(mGroupList);
    mPopup.setAdapter(mAdapter);
    mPopup.setModal(true);
    mPopup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
    mPopup.show();

    ListView listView = mPopup.getListView();
    listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
    listView.setOverScrollMode(OVER_SCROLL_ALWAYS);
    int count = mAdapter.getCount();
    for (int i = 0; i < count; i++) {
      listView.setItemChecked(i, mAdapter.getItem(i).isChecked());
    }

    listView.setOnItemClickListener(this);
  }
  @Override
  public boolean onKey(View v, int keyCode, KeyEvent event) {
    if (mPopup == null || mPopup.getListView() == null) return false;

    if (event.getKeyCode() == KeyEvent.KEYCODE_MENU) {
      if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
        event.startTracking();
        v.getKeyDispatcherState().startTracking(event, this);
        return true;
      } else if (event.getAction() == KeyEvent.ACTION_UP) {
        v.getKeyDispatcherState().handleUpEvent(event);
        if (event.isTracking() && !event.isCanceled()) {
          dismiss();
          return true;
        }
      }
    }
    return false;
  }
 public void setGroupMetaData(Cursor groupMetaData) {
   this.mGroupMetaData = groupMetaData;
   updateView();
   // Open up the list of groups if a new group was just created.
   if (mCreatedNewGroup) {
     mCreatedNewGroup = false;
     onClick(this); // This causes the popup to open.
     if (mPopup != null) {
       // Ensure that the newly created group is checked.
       int position = mAdapter.getCount() - 2;
       ListView listView = mPopup.getListView();
       if (!listView.isItemChecked(position)) {
         // Newly created group is not checked, so check it.
         listView.setItemChecked(position, true);
         onItemClick(listView, null, position, listView.getItemIdAtPosition(position));
       }
     }
   }
 }
  private void runMenuItemEnterAnimations() {
    mMenuItemEnterAnimator = new AnimatorSet();
    AnimatorSet.Builder builder = null;

    ViewGroup list = mPopup.getListView();
    for (int i = 0; i < list.getChildCount(); i++) {
      View view = list.getChildAt(i);
      Object animatorObject = view.getTag(R.id.menu_item_enter_anim_id);
      if (animatorObject != null) {
        if (builder == null) {
          builder = mMenuItemEnterAnimator.play((Animator) animatorObject);
        } else {
          builder.with((Animator) animatorObject);
        }
      }
    }

    mMenuItemEnterAnimator.addListener(mAnimationHistogramRecorder);
    mMenuItemEnterAnimator.start();
  }
  /**
   * Creates and shows the app menu anchored to the specified view.
   *
   * @param context The context of the AppMenu (ensure the proper theme is set on this context).
   * @param anchorView The anchor {@link View} of the {@link ListPopupWindow}.
   * @param isByPermanentButton Whether or not permanent hardware button triggered it. (oppose to
   *     software button or keyboard).
   * @param screenRotation Current device screen rotation.
   * @param visibleDisplayFrame The display area rect in which AppMenu is supposed to fit in.
   * @param screenHeight Current device screen height.
   * @param footerResourceId The resource id for a view to add to the end of the menu list. Can be 0
   *     if no such view is required.
   */
  void show(
      Context context,
      View anchorView,
      boolean isByPermanentButton,
      int screenRotation,
      Rect visibleDisplayFrame,
      int screenHeight,
      int footerResourceId) {
    mPopup = new ListPopupWindow(context, null, android.R.attr.popupMenuStyle);
    mPopup.setModal(true);
    mPopup.setAnchorView(anchorView);
    mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);

    int footerHeight = 0;
    if (footerResourceId != 0) {
      mPopup.setPromptPosition(ListPopupWindow.POSITION_PROMPT_BELOW);
      View promptView = LayoutInflater.from(context).inflate(footerResourceId, null);
      mPopup.setPromptView(promptView);
      int measureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
      promptView.measure(measureSpec, measureSpec);
      footerHeight = promptView.getMeasuredHeight();
    }
    mPopup.setOnDismissListener(
        new OnDismissListener() {
          @Override
          public void onDismiss() {
            if (mPopup.getAnchorView() instanceof ImageButton) {
              ((ImageButton) mPopup.getAnchorView()).setSelected(false);
            }

            if (mMenuItemEnterAnimator != null) mMenuItemEnterAnimator.cancel();

            mHandler.appMenuDismissed();
            mHandler.onMenuVisibilityChanged(false);
          }
        });

    // Some OEMs don't actually let us change the background... but they still return the
    // padding of the new background, which breaks the menu height.  If we still have a
    // drawable here even though our style says @null we should use this padding instead...
    Drawable originalBgDrawable = mPopup.getBackground();

    // Need to explicitly set the background here.  Relying on it being set in the style caused
    // an incorrectly drawn background.
    if (isByPermanentButton) {
      mPopup.setBackgroundDrawable(
          ApiCompatibilityUtils.getDrawable(context.getResources(), R.drawable.menu_bg));
    } else {
      mPopup.setBackgroundDrawable(
          ApiCompatibilityUtils.getDrawable(context.getResources(), R.drawable.edge_menu_bg));
      mPopup.setAnimationStyle(R.style.OverflowMenuAnim);
    }

    // Turn off window animations for low end devices, and on Android M, which has built-in menu
    // animations.
    if (SysUtils.isLowEndDevice() || Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
      mPopup.setAnimationStyle(0);
    }

    Rect bgPadding = new Rect();
    mPopup.getBackground().getPadding(bgPadding);

    int popupWidth =
        context.getResources().getDimensionPixelSize(R.dimen.menu_width)
            + bgPadding.left
            + bgPadding.right;

    mPopup.setWidth(popupWidth);

    mCurrentScreenRotation = screenRotation;
    mIsByPermanentButton = isByPermanentButton;

    // Extract visible items from the Menu.
    int numItems = mMenu.size();
    List<MenuItem> menuItems = new ArrayList<MenuItem>();
    for (int i = 0; i < numItems; ++i) {
      MenuItem item = mMenu.getItem(i);
      if (item.isVisible()) {
        menuItems.add(item);
      }
    }

    Rect sizingPadding = new Rect(bgPadding);
    if (isByPermanentButton && originalBgDrawable != null) {
      Rect originalPadding = new Rect();
      originalBgDrawable.getPadding(originalPadding);
      sizingPadding.top = originalPadding.top;
      sizingPadding.bottom = originalPadding.bottom;
    }

    // A List adapter for visible items in the Menu. The first row is added as a header to the
    // list view.
    mAdapter = new AppMenuAdapter(this, menuItems, LayoutInflater.from(context));
    mPopup.setAdapter(mAdapter);

    setMenuHeight(menuItems.size(), visibleDisplayFrame, screenHeight, sizingPadding, footerHeight);
    setPopupOffset(mPopup, mCurrentScreenRotation, visibleDisplayFrame, sizingPadding);
    mPopup.setOnItemClickListener(this);
    mPopup.show();
    mPopup.getListView().setItemsCanFocus(true);
    mPopup.getListView().setOnKeyListener(this);

    mHandler.onMenuVisibilityChanged(true);

    if (mVerticalFadeDistance > 0) {
      mPopup.getListView().setVerticalFadingEdgeEnabled(true);
      mPopup.getListView().setFadingEdgeLength(mVerticalFadeDistance);
    }

    // Don't animate the menu items for low end devices.
    if (!SysUtils.isLowEndDevice() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
      mPopup
          .getListView()
          .addOnLayoutChangeListener(
              new View.OnLayoutChangeListener() {
                @Override
                public void onLayoutChange(
                    View v,
                    int left,
                    int top,
                    int right,
                    int bottom,
                    int oldLeft,
                    int oldTop,
                    int oldRight,
                    int oldBottom) {
                  mPopup.getListView().removeOnLayoutChangeListener(this);
                  runMenuItemEnterAnimations();
                }
              });
    }
  }