Skip to content

Commit

Permalink
Add a way to dismiss PopupMenu elements
Browse files Browse the repository at this point in the history
Summary:
In native Android apps, like the YouTube app, context menus are closed when the device orientation changes.

In React Native apps instead, when having a [PopupMenu](https://developer.android.com/reference/android/widget/PopupMenu.html) open and rotating the device, the PopupMenu is not dismissed and appears in a wrong position on the screen.

This PR exposes a `dismissPopupMenu` method to allow the application to dismiss any open PopupMenu:

```(javascript)
UIManager.dismissPopupMenu()
```
Closes #15636

Differential Revision: D6837663

Pulled By: hramos

fbshipit-source-id: 7b0f4f04341129ad45c703a50897e17d93651974
  • Loading branch information
miguelsm authored and facebook-github-bot committed Mar 17, 2018
1 parent 6426735 commit 353c070
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public class NativeViewHierarchyManager {
private final LayoutAnimationController mLayoutAnimator = new LayoutAnimationController();

private boolean mLayoutAnimationEnabled;
private PopupMenu mPopupMenu;

public NativeViewHierarchyManager(ViewManagerRegistry viewManagers) {
this(viewManagers, new RootViewManager());
Expand Down Expand Up @@ -731,18 +732,27 @@ public synchronized void showPopupMenu(int reactTag, ReadableArray items, Callba
error.invoke("Can't display popup. Could not find view with tag " + reactTag);
return;
}
PopupMenu popupMenu = new PopupMenu(getReactContextForView(reactTag), anchor);
mPopupMenu = new PopupMenu(getReactContextForView(reactTag), anchor);

Menu menu = popupMenu.getMenu();
Menu menu = mPopupMenu.getMenu();
for (int i = 0; i < items.size(); i++) {
menu.add(Menu.NONE, Menu.NONE, i, items.getString(i));
}

PopupMenuCallbackHandler handler = new PopupMenuCallbackHandler(success);
popupMenu.setOnMenuItemClickListener(handler);
popupMenu.setOnDismissListener(handler);
mPopupMenu.setOnMenuItemClickListener(handler);
mPopupMenu.setOnDismissListener(handler);

popupMenu.show();
mPopupMenu.show();
}

/**
* Dismiss the last opened PopupMenu {@link PopupMenu}.
*/
public void dismissPopupMenu() {
if (mPopupMenu != null) {
mPopupMenu.dismiss();
}
}

private static class PopupMenuCallbackHandler implements PopupMenu.OnMenuItemClickListener,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,10 @@ public void showPopupMenu(int reactTag, ReadableArray items, Callback error, Cal
mOperationsQueue.enqueueShowPopupMenu(reactTag, items, error, success);
}

public void dismissPopupMenu() {
mOperationsQueue.enqueueDismissPopupMenu();
}

public void sendAccessibilityEvent(int tag, int eventType) {
mOperationsQueue.enqueueSendAccessibilityEvent(tag, eventType);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,11 @@ public void showPopupMenu(int reactTag, ReadableArray items, Callback error, Cal
mUIImplementation.showPopupMenu(reactTag, items, error, success);
}

@ReactMethod
public void dismissPopupMenu() {
mUIImplementation.dismissPopupMenu();
}

/**
* LayoutAnimation API on Android is currently experimental. Therefore, it needs to be enabled
* explicitly in order to avoid regression in existing application written for iOS using this API.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,13 @@ public void execute() {
}
}

private final class DismissPopupMenuOperation implements UIOperation {
@Override
public void execute() {
mNativeViewHierarchyManager.dismissPopupMenu();
}
}

/**
* A spec for animation operations (add/remove)
*/
Expand Down Expand Up @@ -656,6 +663,10 @@ public void enqueueShowPopupMenu(
mOperations.add(new ShowPopupMenuOperation(reactTag, items, error, success));
}

public void enqueueDismissPopupMenu() {
mOperations.add(new DismissPopupMenuOperation());
}

public void enqueueCreateView(
ThemedReactContext themedContext,
int viewReactTag,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
public class ReactToolbarManager extends ViewGroupManager<ReactToolbar> {

private static final String REACT_CLASS = "ToolbarAndroid";
private static final int COMMAND_DISMISS_POPUP_MENUS = 1;

@Override
public String getName() {
Expand Down Expand Up @@ -157,6 +158,27 @@ public boolean needsCustomLayoutForChildren() {
return true;
}

@Nullable
@Override
public Map<String, Integer> getCommandsMap() {
return MapBuilder.of("dismissPopupMenus", COMMAND_DISMISS_POPUP_MENUS);
}

@Override
public void receiveCommand(ReactToolbar view, int commandType, @Nullable ReadableArray args) {
switch (commandType) {
case COMMAND_DISMISS_POPUP_MENUS: {
view.dismissPopupMenus();
return;
}
default:
throw new IllegalArgumentException(String.format(
"Unsupported command %d received by %s.",
commandType,
getClass().getSimpleName()));
}
}

private int[] getDefaultContentInsets(Context context) {
Resources.Theme theme = context.getTheme();
TypedArray toolbarStyle = null;
Expand Down

0 comments on commit 353c070

Please sign in to comment.