Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.chrome.browser.ntp; | 5 package org.chromium.chrome.browser.ntp; |
| 6 | 6 |
| 7 import android.support.annotation.IntDef; | 7 import android.support.annotation.IntDef; |
| 8 import android.support.v4.view.ViewCompat; | 8 import android.support.v4.view.ViewCompat; |
| 9 import android.view.ContextMenu; | 9 import android.view.ContextMenu; |
| 10 import android.view.Menu; | 10 import android.view.Menu; |
| 11 import android.view.MenuItem; | 11 import android.view.MenuItem; |
| 12 import android.view.MenuItem.OnMenuItemClickListener; | 12 import android.view.MenuItem.OnMenuItemClickListener; |
| 13 import android.view.View; | 13 import android.view.View; |
| 14 | 14 |
| 15 import org.chromium.base.Callback; | 15 import org.chromium.base.Callback; |
| 16 import org.chromium.chrome.R; | 16 import org.chromium.chrome.R; |
| 17 import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager; | 17 import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager; |
| 18 import org.chromium.ui.mojom.WindowOpenDisposition; | 18 import org.chromium.ui.mojom.WindowOpenDisposition; |
| 19 | 19 |
| 20 import java.lang.annotation.Retention; | 20 import java.lang.annotation.Retention; |
| 21 import java.lang.annotation.RetentionPolicy; | 21 import java.lang.annotation.RetentionPolicy; |
| 22 | 22 |
| 23 /** | 23 /** |
| 24 * Takes care of creating a context menu and triaging the time clicks. | 24 * Takes care of creating a context menu and triaging the time clicks. |
| 25 */ | 25 */ |
| 26 public class ContextMenuHandler implements OnMenuItemClickListener { | 26 public class ContextMenuHandler implements OnMenuItemClickListener { |
| 27 @IntDef({ID_OPEN_IN_NEW_WINDOW, ID_OPEN_IN_NEW_TAB, ID_OPEN_IN_INCOGNITO_TAB , ID_REMOVE, | 27 @IntDef({ID_OPEN_IN_NEW_WINDOW, ID_OPEN_IN_NEW_TAB, ID_OPEN_IN_INCOGNITO_TAB , ID_REMOVE, |
| 28 ID_SAVE_FOR_OFFLINE}) | 28 ID_SAVE_FOR_OFFLINE}) |
| 29 @Retention(RetentionPolicy.SOURCE) | 29 @Retention(RetentionPolicy.SOURCE) |
| 30 @interface ContextMenuItemId {} | 30 public @interface ContextMenuItemId {} |
| 31 static final int ID_OPEN_IN_NEW_WINDOW = 0; | 31 public static final int ID_OPEN_IN_NEW_WINDOW = 0; |
| 32 static final int ID_OPEN_IN_NEW_TAB = 1; | 32 public static final int ID_OPEN_IN_NEW_TAB = 1; |
| 33 static final int ID_OPEN_IN_INCOGNITO_TAB = 2; | 33 public static final int ID_OPEN_IN_INCOGNITO_TAB = 2; |
| 34 static final int ID_REMOVE = 3; | 34 public static final int ID_REMOVE = 3; |
| 35 static final int ID_SAVE_FOR_OFFLINE = 4; | 35 public static final int ID_SAVE_FOR_OFFLINE = 4; |
| 36 | 36 |
| 37 private final NewTabPageManager mManager; | 37 private final NewTabPageManager mManager; |
| 38 private final Delegate mDelegate; | 38 private final Delegate mDelegate; |
| 39 private final TouchDisableableView mOuterView; | 39 private final TouchDisableableView mOuterView; |
| 40 | 40 |
| 41 /** Defines callback to configure the context menu and respond to user inter action. */ | 41 /** Defines callback to configure the context menu and respond to user inter action. */ |
| 42 public interface Delegate { | 42 public interface Delegate { |
| 43 /** Opens the current item the way specified by {@code windowDisposition }. */ | 43 /** Opens the current item the way specified by {@code windowDisposition }. */ |
| 44 void openItem(int windowDisposition); | 44 void openItem(int windowDisposition); |
| 45 | 45 |
| 46 /** Removed the current item. */ | 46 /** Removed the current item. */ |
| 47 void removeItem(); | 47 void removeItem(); |
| 48 | 48 |
| 49 /** @return whether the current item can be saved offline. */ | 49 /** @return whether the current item can be saved offline. */ |
| 50 boolean canBeSavedOffline(); | 50 boolean canBeSavedOffline(); |
| 51 } | 51 } |
| 52 | 52 |
| 53 /** Interface for a view that can be set to stop responding to touches. */ | 53 /** Interface for a view that can be set to stop responding to touches. */ |
| 54 public interface TouchDisableableView { | 54 public interface TouchDisableableView { |
| 55 void setTouchEnabled(boolean enabled); | 55 void setTouchEnabled(boolean enabled); |
| 56 View asView(); | 56 View asView(); |
| 57 } | 57 } |
| 58 | 58 |
| 59 public ContextMenuHandler(NewTabPageManager newTabPageManager, TouchDisablea bleView outerView, | 59 public ContextMenuHandler(NewTabPageManager newTabPageManager, TouchDisablea bleView outerView, |
| 60 Delegate delegate) { | 60 Delegate delegate) { |
| 61 assert outerView instanceof View; | |
| 62 mManager = newTabPageManager; | 61 mManager = newTabPageManager; |
| 63 mOuterView = outerView; | 62 mOuterView = outerView; |
| 64 mDelegate = delegate; | 63 mDelegate = delegate; |
| 65 } | 64 } |
| 66 | 65 |
| 67 public boolean showItem(@ContextMenuItemId int itemId) { | 66 public boolean showItem(@ContextMenuItemId int itemId) { |
| 68 switch (itemId) { | 67 switch (itemId) { |
| 69 case ID_OPEN_IN_NEW_WINDOW: | 68 case ID_OPEN_IN_NEW_WINDOW: |
| 70 return mManager.isOpenInNewWindowEnabled(); | 69 return mManager.isOpenInNewWindowEnabled(); |
| 71 case ID_OPEN_IN_NEW_TAB: | 70 case ID_OPEN_IN_NEW_TAB: |
| 72 return true; | 71 return true; |
| 73 case ID_OPEN_IN_INCOGNITO_TAB: | 72 case ID_OPEN_IN_INCOGNITO_TAB: |
| 74 return mManager.isOpenInIncognitoEnabled(); | 73 return mManager.isOpenInIncognitoEnabled(); |
| 75 case ID_SAVE_FOR_OFFLINE: | 74 case ID_SAVE_FOR_OFFLINE: |
| 76 return mDelegate.canBeSavedOffline(); | 75 return mDelegate.canBeSavedOffline(); |
| 77 case ID_REMOVE: | 76 case ID_REMOVE: |
| 78 return true; | 77 return true; |
| 79 | 78 |
| 80 default: | 79 default: |
| 81 return false; | 80 return false; |
| 82 } | 81 } |
| 83 } | 82 } |
| 84 | 83 |
| 85 public void onCreateContextMenu(ContextMenu menu) { | 84 public void onCreateContextMenu(ContextMenu menu, final View associatedView) { |
| 86 if (showItem(ID_OPEN_IN_NEW_WINDOW)) { | 85 if (showItem(ID_OPEN_IN_NEW_WINDOW)) { |
| 87 addContextMenuItem( | 86 addContextMenuItem( |
| 88 menu, ID_OPEN_IN_NEW_WINDOW, R.string.contextmenu_open_in_ot her_window); | 87 menu, ID_OPEN_IN_NEW_WINDOW, R.string.contextmenu_open_in_ot her_window); |
| 89 } | 88 } |
| 90 | 89 |
| 91 if (showItem(ID_OPEN_IN_NEW_TAB)) { | 90 if (showItem(ID_OPEN_IN_NEW_TAB)) { |
| 92 addContextMenuItem(menu, ID_OPEN_IN_NEW_TAB, R.string.contextmenu_op en_in_new_tab); | 91 addContextMenuItem(menu, ID_OPEN_IN_NEW_TAB, R.string.contextmenu_op en_in_new_tab); |
| 93 } | 92 } |
| 94 | 93 |
| 95 if (showItem(ID_OPEN_IN_INCOGNITO_TAB)) { | 94 if (showItem(ID_OPEN_IN_INCOGNITO_TAB)) { |
| 96 addContextMenuItem( | 95 addContextMenuItem( |
| 97 menu, ID_OPEN_IN_INCOGNITO_TAB, R.string.contextmenu_open_in _incognito_tab); | 96 menu, ID_OPEN_IN_INCOGNITO_TAB, R.string.contextmenu_open_in _incognito_tab); |
| 98 } | 97 } |
| 99 | 98 |
| 100 if (showItem(ID_SAVE_FOR_OFFLINE)) { | 99 if (showItem(ID_SAVE_FOR_OFFLINE)) { |
| 101 addContextMenuItem(menu, ID_SAVE_FOR_OFFLINE, R.string.contextmenu_s ave_link); | 100 addContextMenuItem(menu, ID_SAVE_FOR_OFFLINE, R.string.contextmenu_s ave_link); |
| 102 } | 101 } |
| 103 | 102 |
| 104 if (showItem(ID_REMOVE)) { | 103 if (showItem(ID_REMOVE)) { |
| 105 addContextMenuItem(menu, ID_REMOVE, R.string.remove); | 104 addContextMenuItem(menu, ID_REMOVE, R.string.remove); |
| 106 } | 105 } |
| 107 | 106 |
| 108 // Disable touch events on the RecyclerView while the context menu is op en. This is to | 107 // Disable touch events on the RecyclerView while the context menu is op en. This is to |
| 109 // prevent the user long pressing to get the context menu then on the sa me press scrolling | 108 // prevent the user long pressing to get the context menu then on the sa me press scrolling |
| 110 // or swiping to dismiss an item (eg. https://crbug.com/638854, https:// crbug.com/638555, | 109 // or swiping to dismiss an item (eg. https://crbug.com/638854, https:// crbug.com/638555, |
| 111 // https://crbug.com/636296) | 110 // https://crbug.com/636296) |
| 112 mOuterView.setTouchEnabled(false); | 111 mOuterView.setTouchEnabled(false); |
| 113 | 112 |
| 113 mManager.getContextMenuLifetimeManager().onContextMenuCreated(menu, asso ciatedView); | |
|
Bernhard Bauer
2016/11/11 13:30:08
Wait, so the manager owns the LifetimeManager, whi
dgn
2016/11/14 18:34:08
Done.
| |
| 114 | |
| 114 mManager.addContextMenuCloseCallback(new Callback<Menu>() { | 115 mManager.addContextMenuCloseCallback(new Callback<Menu>() { |
| 115 @Override | 116 @Override |
| 116 public void onResult(Menu result) { | 117 public void onResult(Menu result) { |
| 117 mOuterView.setTouchEnabled(true); | 118 mOuterView.setTouchEnabled(true); |
| 118 mManager.removeContextMenuCloseCallback(this); | 119 mManager.removeContextMenuCloseCallback(this); |
| 120 mManager.getContextMenuLifetimeManager().onMenuClosed(); | |
| 119 } | 121 } |
| 120 }); | 122 }); |
| 121 } | 123 } |
| 122 | 124 |
| 123 @Override | 125 @Override |
| 124 public boolean onMenuItemClick(MenuItem item) { | 126 public boolean onMenuItemClick(MenuItem item) { |
| 125 // If the user clicks a snippet then immediately long presses they will create a context | 127 // If the user clicks a snippet then immediately long presses they will create a context |
| 126 // menu while the snippet's URL loads in the background. This means that when they press | 128 // menu while the snippet's URL loads in the background. This means that when they press |
| 127 // an item on context menu the NTP will not actually be open. We add thi s check here to | 129 // an item on context menu the NTP will not actually be open. We add thi s check here to |
| 128 // prevent taking any action if the user has already left the NTP. | 130 // prevent taking any action if the user has already left the NTP. |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 150 return false; | 152 return false; |
| 151 } | 153 } |
| 152 } | 154 } |
| 153 | 155 |
| 154 /** | 156 /** |
| 155 * Convenience method to reduce multi-line function call to single line. | 157 * Convenience method to reduce multi-line function call to single line. |
| 156 */ | 158 */ |
| 157 private void addContextMenuItem(ContextMenu menu, @ContextMenuItemId int id, int resourceId) { | 159 private void addContextMenuItem(ContextMenu menu, @ContextMenuItemId int id, int resourceId) { |
| 158 menu.add(Menu.NONE, id, Menu.NONE, resourceId).setOnMenuItemClickListene r(this); | 160 menu.add(Menu.NONE, id, Menu.NONE, resourceId).setOnMenuItemClickListene r(this); |
| 159 } | 161 } |
| 162 | |
| 163 /** Helps closing open context menus when the view the associated view is mo dified. */ | |
| 164 public static class LifetimeManager { | |
| 165 private ContextMenu mContextMenu; | |
| 166 private View mAssociatedView; | |
| 167 | |
| 168 public void onContextMenuCreated(ContextMenu c, View v) { | |
| 169 mContextMenu = c; | |
| 170 mAssociatedView = v; | |
| 171 } | |
| 172 | |
| 173 public void onViewModified(View v) { | |
| 174 if (mAssociatedView == null || mAssociatedView != v) return; | |
|
Bernhard Bauer
2016/11/11 13:30:08
|mAssociatedView| would be null if either that is
dgn
2016/11/14 18:34:08
Simplified this and removed the redundant checks.
| |
| 175 if (mContextMenu == null) return; | |
| 176 mContextMenu.close(); | |
| 177 mContextMenu = null; | |
| 178 } | |
| 179 | |
| 180 private void onMenuClosed() { | |
| 181 mContextMenu = null; | |
| 182 mAssociatedView = null; | |
| 183 } | |
| 184 } | |
| 160 } | 185 } |
| OLD | NEW |