blob: 85e26d0c68370c89c499d7a43e9157eec220f67e [file] [log] [blame]
Jun Mukai31f581c2015-04-02 13:44:29 -07001/*
2 * Copyright (C) 2015 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 android.widget;
18
Alan Viverette00aa5102015-11-03 13:03:15 -050019import android.annotation.NonNull;
Jun Mukai31f581c2015-04-02 13:44:29 -070020import android.content.Context;
Oren Blasberg8e12f8d2015-09-02 14:25:56 -070021import android.content.res.Configuration;
22import android.content.res.Resources;
23import android.transition.Transition;
Jun Mukai31f581c2015-04-02 13:44:29 -070024import android.util.AttributeSet;
Oren Blasberg8e12f8d2015-09-02 14:25:56 -070025import android.view.KeyEvent;
Alan Viverette00aa5102015-11-03 13:03:15 -050026import android.view.MenuItem;
Oren Blasberg23087be2015-09-08 14:59:12 -070027import android.view.MotionEvent;
Jun Mukai31f581c2015-04-02 13:44:29 -070028import android.view.View;
Oren Blasberg8e12f8d2015-09-02 14:25:56 -070029
30import com.android.internal.view.menu.ListMenuItemView;
31import com.android.internal.view.menu.MenuAdapter;
Oren Blasberg23087be2015-09-08 14:59:12 -070032import com.android.internal.view.menu.MenuBuilder;
Jun Mukai31f581c2015-04-02 13:44:29 -070033
34/**
35 * A MenuPopupWindow represents the popup window for menu.
36 *
37 * MenuPopupWindow is mostly same as ListPopupWindow, but it has customized
38 * behaviors specific to menus,
39 *
40 * @hide
41 */
Oren Blasberg23087be2015-09-08 14:59:12 -070042public class MenuPopupWindow extends ListPopupWindow implements MenuItemHoverListener {
43 private MenuItemHoverListener mHoverListener;
44
Jun Mukai31f581c2015-04-02 13:44:29 -070045 public MenuPopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
46 super(context, attrs, defStyleAttr, defStyleRes);
47 }
48
49 @Override
Oren Blasbergf44d90b2015-08-31 14:15:26 -070050 DropDownListView createDropDownListView(Context context, boolean hijackFocus) {
Oren Blasberg23087be2015-09-08 14:59:12 -070051 MenuDropDownListView view = new MenuDropDownListView(context, hijackFocus);
52 view.setHoverListener(this);
53 return view;
Jun Mukai31f581c2015-04-02 13:44:29 -070054 }
55
Oren Blasberg8e12f8d2015-09-02 14:25:56 -070056 public void setEnterTransition(Transition enterTransition) {
57 mPopup.setEnterTransition(enterTransition);
Jun Mukai31f581c2015-04-02 13:44:29 -070058 }
Oren Blasberg8e12f8d2015-09-02 14:25:56 -070059
Oren Blasberg23087be2015-09-08 14:59:12 -070060 public void setExitTransition(Transition exitTransition) {
61 mPopup.setExitTransition(exitTransition);
62 }
63
64 public void setHoverListener(MenuItemHoverListener hoverListener) {
65 mHoverListener = hoverListener;
66 }
67
Oren Blasberg8e12f8d2015-09-02 14:25:56 -070068 /**
69 * Set whether this window is touch modal or if outside touches will be sent to
70 * other windows behind it.
71 */
72 public void setTouchModal(boolean touchModal) {
73 mPopup.setTouchModal(touchModal);
74 }
75
Oren Blasberg23087be2015-09-08 14:59:12 -070076 @Override
Alan Viverette00aa5102015-11-03 13:03:15 -050077 public void onItemHoverEnter(@NonNull MenuBuilder menu, @NonNull MenuItem item) {
Oren Blasberg23087be2015-09-08 14:59:12 -070078 // Forward up the chain
79 if (mHoverListener != null) {
Alan Viverette00aa5102015-11-03 13:03:15 -050080 mHoverListener.onItemHoverEnter(menu, item);
81 }
82 }
83
84 @Override
85 public void onItemHoverExit(@NonNull MenuBuilder menu, @NonNull MenuItem item) {
86 // Forward up the chain
87 if (mHoverListener != null) {
88 mHoverListener.onItemHoverExit(menu, item);
Oren Blasberg23087be2015-09-08 14:59:12 -070089 }
90 }
91
92 /**
93 * @hide
94 */
95 public static class MenuDropDownListView extends DropDownListView {
Oren Blasberg8e12f8d2015-09-02 14:25:56 -070096 final int mAdvanceKey;
97 final int mRetreatKey;
98
Oren Blasberg23087be2015-09-08 14:59:12 -070099 private MenuItemHoverListener mHoverListener;
Alan Viverette00aa5102015-11-03 13:03:15 -0500100 private MenuItem mHoveredMenuItem;
Oren Blasberg23087be2015-09-08 14:59:12 -0700101
Oren Blasberg8e12f8d2015-09-02 14:25:56 -0700102 public MenuDropDownListView(Context context, boolean hijackFocus) {
103 super(context, hijackFocus);
104
105 final Resources res = context.getResources();
106 final Configuration config = res.getConfiguration();
107 if (config.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
108 mAdvanceKey = KeyEvent.KEYCODE_DPAD_LEFT;
109 mRetreatKey = KeyEvent.KEYCODE_DPAD_RIGHT;
110 } else {
111 mAdvanceKey = KeyEvent.KEYCODE_DPAD_RIGHT;
112 mRetreatKey = KeyEvent.KEYCODE_DPAD_LEFT;
113 }
114 }
115
Oren Blasberg23087be2015-09-08 14:59:12 -0700116 public void setHoverListener(MenuItemHoverListener hoverListener) {
117 mHoverListener = hoverListener;
118 }
119
120 public void clearSelection() {
121 setSelectedPositionInt(INVALID_POSITION);
122 setNextSelectedPositionInt(INVALID_POSITION);
123 }
124
Oren Blasberg8e12f8d2015-09-02 14:25:56 -0700125 @Override
126 public boolean onKeyDown(int keyCode, KeyEvent event) {
127 ListMenuItemView selectedItem = (ListMenuItemView) getSelectedView();
128 if (selectedItem != null && keyCode == mAdvanceKey) {
Alan Viverette00aa5102015-11-03 13:03:15 -0500129 if (selectedItem.isEnabled() && selectedItem.getItemData().hasSubMenu()) {
Oren Blasberg8e12f8d2015-09-02 14:25:56 -0700130 performItemClick(
131 selectedItem,
132 getSelectedItemPosition(),
133 getSelectedItemId());
134 }
135 return true;
136 } else if (selectedItem != null && keyCode == mRetreatKey) {
Oren Blasberg734320d2015-09-21 14:09:26 -0700137 setSelectedPositionInt(INVALID_POSITION);
138 setNextSelectedPositionInt(INVALID_POSITION);
Oren Blasberg8e12f8d2015-09-02 14:25:56 -0700139
Alan Viverette00aa5102015-11-03 13:03:15 -0500140 // Close only the top-level menu.
141 ((MenuAdapter) getAdapter()).getAdapterMenu().close(false /* closeAllMenus */);
Oren Blasberg8e12f8d2015-09-02 14:25:56 -0700142 return true;
143 }
144 return super.onKeyDown(keyCode, event);
145 }
146
Oren Blasberg23087be2015-09-08 14:59:12 -0700147 @Override
148 public boolean onHoverEvent(MotionEvent ev) {
Alan Viverette00aa5102015-11-03 13:03:15 -0500149 // Dispatch any changes in hovered item index to the listener.
150 if (mHoverListener != null) {
151 // The adapter may be wrapped. Adjust the index if necessary.
152 final int headersCount;
153 final MenuAdapter menuAdapter;
154 final ListAdapter adapter = getAdapter();
155 if (adapter instanceof HeaderViewListAdapter) {
156 final HeaderViewListAdapter headerAdapter = (HeaderViewListAdapter) adapter;
157 headersCount = headerAdapter.getHeadersCount();
158 menuAdapter = (MenuAdapter) headerAdapter.getWrappedAdapter();
159 } else {
160 headersCount = 0;
161 menuAdapter = (MenuAdapter) adapter;
162 }
Alan Viverette2ac975d2015-10-08 19:54:16 +0000163
Alan Viverette00aa5102015-11-03 13:03:15 -0500164 // Find the menu item for the view at the event coordinates.
165 MenuItem menuItem = null;
166 if (ev.getAction() != MotionEvent.ACTION_HOVER_EXIT) {
167 final int position = pointToPosition((int) ev.getX(), (int) ev.getY());
168 if (position != INVALID_POSITION) {
169 final int itemPosition = position - headersCount;
170 if (itemPosition >= 0 && itemPosition < menuAdapter.getCount()) {
171 menuItem = menuAdapter.getItem(itemPosition);
172 }
173 }
174 }
175
176 final MenuItem oldMenuItem = mHoveredMenuItem;
177 if (oldMenuItem != menuItem) {
178 final MenuBuilder menu = menuAdapter.getAdapterMenu();
179 if (oldMenuItem != null) {
180 mHoverListener.onItemHoverExit(menu, oldMenuItem);
181 }
182
183 mHoveredMenuItem = menuItem;
184
185 if (menuItem != null) {
186 mHoverListener.onItemHoverEnter(menu, menuItem);
Alan Viverette2ac975d2015-10-08 19:54:16 +0000187 }
188 }
Oren Blasberg23087be2015-09-08 14:59:12 -0700189 }
190
Alan Viverette00aa5102015-11-03 13:03:15 -0500191 return super.onHoverEvent(ev);
Oren Blasberg23087be2015-09-08 14:59:12 -0700192 }
Oren Blasberg8e12f8d2015-09-02 14:25:56 -0700193 }
Oren Blasberg8e12f8d2015-09-02 14:25:56 -0700194}