diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/SuggestionsWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/SuggestionsWidget.java
index fe11962e9..7e9bce4d4 100644
--- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/SuggestionsWidget.java
+++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/SuggestionsWidget.java
@@ -1,7 +1,12 @@
package org.mozilla.vrbrowser.ui.widgets;
+import android.content.ClipData;
+import android.content.ClipboardManager;
import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.Typeface;
+import android.net.Uri;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.StyleSpan;
@@ -12,21 +17,22 @@
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
+import android.widget.AdapterView;
import android.widget.ArrayAdapter;
-import android.widget.ImageButton;
import android.widget.ImageView;
-import android.widget.ListView;
import android.widget.TextView;
import androidx.annotation.NonNull;
-import org.mozilla.gecko.util.ThreadUtils;
+import org.mozilla.geckoview.GeckoSession;
import org.mozilla.vrbrowser.R;
import org.mozilla.vrbrowser.audio.AudioEngine;
import org.mozilla.vrbrowser.ui.views.CustomListView;
+import org.mozilla.vrbrowser.ui.widgets.dialogs.SelectionActionWidget;
import org.mozilla.vrbrowser.utils.ViewUtils;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
public class SuggestionsWidget extends UIWidget implements WidgetManagerDelegate.FocusChangeListener {
@@ -38,10 +44,12 @@ public class SuggestionsWidget extends UIWidget implements WidgetManagerDelegate
private URLBarPopupDelegate mURLBarDelegate;
private String mHighlightedText;
private AudioEngine mAudio;
+ private ClipboardManager mClipboard;
+ private SelectionActionWidget mSelectionMenu;
public interface URLBarPopupDelegate {
- default void OnItemClicked(SuggestionItem item) {};
- default void OnItemDeleted(SuggestionItem item) {};
+ default void OnItemClicked(SuggestionItem item) {}
+ default void OnItemLongClicked(SuggestionItem item) {}
}
public SuggestionsWidget(Context aContext) {
@@ -87,8 +95,12 @@ public void onAnimationRepeat(Animation animation) {
mAdapter = new SuggestionsAdapter(getContext(), R.layout.list_popup_window_item, new ArrayList<>());
mList.setAdapter(mAdapter);
+ mList.setOnItemClickListener(mClickListener);
+ mList.setOnItemLongClickListener(mLongClickListener);
+ mList.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> hideMenu());
mAudio = AudioEngine.fromContext(aContext);
+ mClipboard = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
mHighlightedText = "";
}
@@ -135,6 +147,7 @@ public void hideNoAnim(@HideFlags int aHideFlags) {
@Override
public void onGlobalFocusChanged(View oldFocus, View newFocus) {
if (!ViewUtils.isEqualOrChildrenOf(this, newFocus)) {
+ hideMenu();
onDismiss();
}
}
@@ -200,7 +213,6 @@ private class ItemViewHolder {
ImageView favicon;
TextView title;
TextView url;
- ImageButton delete;
View divider;
}
@@ -220,24 +232,18 @@ public View getView(int position, View convertView, ViewGroup parent) {
itemViewHolder.layout = listItem.findViewById(R.id.layout);
itemViewHolder.layout.setTag(R.string.position_tag, position);
- itemViewHolder.layout.setOnClickListener(mRowListener);
itemViewHolder.favicon = listItem.findViewById(R.id.favicon);
itemViewHolder.title = listItem.findViewById(R.id.title);
itemViewHolder.url = listItem.findViewById(R.id.url);
- itemViewHolder.delete = listItem.findViewById(R.id.delete);
- itemViewHolder.delete.setTag(R.string.position_tag, position);
- itemViewHolder.delete.setOnClickListener(mDeleteButtonListener);
itemViewHolder.divider = listItem.findViewById(R.id.divider);
listItem.setTag(R.string.list_item_view_tag, itemViewHolder);
listItem.setOnHoverListener(mHoverListener);
- listItem.setOnTouchListener(mTouchListener);
} else {
itemViewHolder = (ItemViewHolder) listItem.getTag(R.string.list_item_view_tag);
itemViewHolder.layout.setTag(R.string.position_tag, position);
- itemViewHolder.delete.setTag(R.string.position_tag, position);
}
SuggestionItem selectedItem = getItem(position);
@@ -274,7 +280,6 @@ public View getView(int position, View convertView, ViewGroup parent) {
itemViewHolder.favicon.setImageResource(R.drawable.ic_icon_bookmark);
}
- itemViewHolder.delete.setVisibility(GONE);
itemViewHolder.favicon.setVisibility(VISIBLE);
if (position == 0) {
@@ -286,59 +291,6 @@ public View getView(int position, View convertView, ViewGroup parent) {
return listItem;
}
- OnClickListener mDeleteButtonListener = v -> {
- if (mAudio != null) {
- mAudio.playSound(AudioEngine.Sound.CLICK);
- }
-
- int position = (Integer)v.getTag(R.string.position_tag);
- SuggestionItem item = getItem(position);
- mAdapter.remove(item);
- mAdapter.notifyDataSetChanged();
-
- if (mURLBarDelegate != null) {
- mURLBarDelegate.OnItemDeleted(item);
- }
- };
-
- OnClickListener mRowListener = v -> {
- if (mAudio != null) {
- mAudio.playSound(AudioEngine.Sound.CLICK);
- }
-
- hide(KEEP_WIDGET);
-
- requestFocus();
- requestFocusFromTouch();
-
- if (mURLBarDelegate != null) {
- int position = (Integer)v.getTag(R.string.position_tag);
- SuggestionItem item = getItem(position);
- mURLBarDelegate.OnItemClicked(item);
- }
- };
-
- private OnTouchListener mTouchListener = (view, event) -> {
- int position = (int)view.getTag(R.string.position_tag);
- if (!isEnabled(position)) {
- return false;
- }
-
- int ev = event.getActionMasked();
- switch (ev) {
- case MotionEvent.ACTION_UP:
- view.setPressed(false);
- view.performClick();
- return true;
-
- case MotionEvent.ACTION_DOWN:
- view.setPressed(true);
- return true;
- }
-
- return false;
- };
-
private OnHoverListener mHoverListener = (view, motionEvent) -> {
int position = (int)view.getTag(R.string.position_tag);
if (!isEnabled(position)) {
@@ -348,7 +300,6 @@ public View getView(int position, View convertView, ViewGroup parent) {
View favicon = view.findViewById(R.id.favicon);
TextView title = view.findViewById(R.id.title);
View url = view.findViewById(R.id.url);
- View delete = view.findViewById(R.id.delete);
int ev = motionEvent.getActionMasked();
switch (ev) {
case MotionEvent.ACTION_HOVER_ENTER:
@@ -357,7 +308,6 @@ public View getView(int position, View convertView, ViewGroup parent) {
title.setHovered(true);
title.setShadowLayer(title.getShadowRadius(), title.getShadowDx(), title.getShadowDy(), getContext().getColor(R.color.text_shadow_light));
url.setHovered(true);
- delete.setHovered(true);
return true;
case MotionEvent.ACTION_HOVER_EXIT:
@@ -366,7 +316,6 @@ public View getView(int position, View convertView, ViewGroup parent) {
title.setHovered(false);
title.setShadowLayer(title.getShadowRadius(), title.getShadowDx(), title.getShadowDy(), getContext().getColor(R.color.text_shadow));
url.setHovered(false);
- delete.setHovered(false);
return true;
}
@@ -374,6 +323,90 @@ public View getView(int position, View convertView, ViewGroup parent) {
};
}
+ private AdapterView.OnItemClickListener mClickListener = new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView> parent, View view, int position, long id) {
+ if (mAudio != null) {
+ mAudio.playSound(AudioEngine.Sound.CLICK);
+ }
+
+ hide(KEEP_WIDGET);
+
+ requestFocus();
+ requestFocusFromTouch();
+
+ if (mURLBarDelegate != null) {
+ SuggestionItem item = mAdapter.getItem(position);
+ mURLBarDelegate.OnItemClicked(item);
+ }
+ }
+ };
+
+ private AdapterView.OnItemLongClickListener mLongClickListener = new AdapterView.OnItemLongClickListener() {
+ @Override
+ public boolean onItemLongClick(AdapterView> parent, View view, int position, long id) {
+ SuggestionItem item = mAdapter.getItem(position);
+
+ view.setHovered(true);
+
+ hideMenu();
+ if (item != null) {
+ showMenu(view, item);
+
+ return true;
+ }
+
+ return false;
+ }
+ };
+
+ private void showMenu(@NonNull View view, @NonNull SuggestionItem item) {
+ if (mSelectionMenu == null) {
+ mSelectionMenu = new SelectionActionWidget(getContext());
+ mSelectionMenu.mWidgetPlacement.parentHandle = getHandle();
+ mSelectionMenu.setActions(Collections.singleton(GeckoSession.SelectionActionDelegate.ACTION_COPY));
+ }
+
+ Rect offsetViewBounds = new Rect();
+ view.getDrawingRect(offsetViewBounds);
+ float ratio = WidgetPlacement.viewToWidgetRatio(getContext(), this);
+ offsetDescendantRectToMyCoords(view, offsetViewBounds);
+ RectF rectF = new RectF(
+ offsetViewBounds.left * ratio,
+ offsetViewBounds.top * ratio,
+ offsetViewBounds.right * ratio,
+ offsetViewBounds.bottom * ratio
+ );
+ mSelectionMenu.setSelectionRect(rectF);
+ mSelectionMenu.setDelegate(new SelectionActionWidget.Delegate() {
+ @Override
+ public void onAction(String action) {
+ hideMenu();
+ ClipData clip = ClipData.newRawUri(item.title, Uri.parse(item.url));
+ mClipboard.setPrimaryClip(clip);
+ }
+
+ @Override
+ public void onDismiss() {
+ hideMenu();
+ }
+ });
+ mSelectionMenu.show(KEEP_FOCUS);
+ }
+
+ private void hideMenu() {
+ if (mSelectionMenu != null) {
+ mSelectionMenu.setDelegate((SelectionActionWidget.Delegate)null);
+ if (!mSelectionMenu.isReleased()) {
+ if (mSelectionMenu.isVisible()) {
+ mSelectionMenu.hide(REMOVE_WIDGET);
+ }
+ mSelectionMenu.releaseWidget();
+ }
+ mSelectionMenu = null;
+ }
+ }
+
private SpannableStringBuilder createHighlightedText(@NonNull String text) {
final SpannableStringBuilder sb = new SpannableStringBuilder(text);
final StyleSpan bold = new StyleSpan(Typeface.BOLD);
diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java
index fc76881d5..e97590115 100644
--- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java
+++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java
@@ -10,6 +10,7 @@
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.net.Uri;
import android.util.Log;
@@ -1726,7 +1727,17 @@ public void onShowActionRequest(@NonNull GeckoSession aSession, @NonNull Selecti
Matrix matrix = new Matrix();
aSession.getClientToSurfaceMatrix(matrix);
matrix.mapRect(aSelection.clientRect);
- mSelectionMenu.setSelectionRect(aSelection.clientRect);
+ RectF selectionRect = null;
+ if (aSelection.clientRect != null) {
+ float ratio = WidgetPlacement.worldToWindowRatio(getContext());
+ selectionRect = new RectF(
+ aSelection.clientRect.left * ratio,
+ aSelection.clientRect.top* ratio,
+ aSelection.clientRect.right * ratio,
+ aSelection.clientRect.bottom * ratio
+ );
+ }
+ mSelectionMenu.setSelectionRect(selectionRect);
mSelectionMenu.setDelegate(new SelectionActionWidget.Delegate() {
@Override
public void onAction(String action) {
diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/SelectionActionWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/SelectionActionWidget.java
index 6bcf2fae7..5986a852f 100644
--- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/SelectionActionWidget.java
+++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/SelectionActionWidget.java
@@ -16,11 +16,9 @@
import org.mozilla.vrbrowser.ui.widgets.UIWidget;
import org.mozilla.vrbrowser.ui.widgets.WidgetManagerDelegate;
import org.mozilla.vrbrowser.ui.widgets.WidgetPlacement;
-import org.mozilla.vrbrowser.utils.StringUtils;
import org.mozilla.vrbrowser.utils.ViewUtils;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
import static android.view.Gravity.CENTER_VERTICAL;
@@ -78,8 +76,8 @@ public void show(@ShowFlags int aShowFlags) {
if (mPosition != null) {
mWidgetPlacement.parentAnchorX = 0.0f;
mWidgetPlacement.parentAnchorY = 1.0f;
- mWidgetPlacement.translationX = mPosition.x * WidgetPlacement.worldToWindowRatio(getContext());
- mWidgetPlacement.translationY = -mPosition.y * WidgetPlacement.worldToWindowRatio(getContext());
+ mWidgetPlacement.translationX = mPosition.x;
+ mWidgetPlacement.translationY = -mPosition.y;
mWidgetPlacement.translationY += mWidgetPlacement.height * 0.5f;
}
super.show(aShowFlags);
diff --git a/app/src/main/res/drawable/selection_menu_background.xml b/app/src/main/res/drawable/selection_menu_background.xml
index fab616db3..831afeb11 100644
--- a/app/src/main/res/drawable/selection_menu_background.xml
+++ b/app/src/main/res/drawable/selection_menu_background.xml
@@ -3,5 +3,6 @@
android:shape="rectangle">
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/selection_menu_background_triangle.xml b/app/src/main/res/drawable/selection_menu_background_triangle.xml
index 916f45f60..3bba8c3d3 100644
--- a/app/src/main/res/drawable/selection_menu_background_triangle.xml
+++ b/app/src/main/res/drawable/selection_menu_background_triangle.xml
@@ -9,22 +9,22 @@
android:name="trianglegroup"
android:pivotX="50"
android:pivotY="50"
- android:scaleX="0.95"
- android:scaleY="0.95"
+ android:scaleX="0.92"
+ android:scaleY="0.92"
android:translateY="-50"
android:rotation="180">
+ android:strokeColor="@color/iron"
+ android:strokeWidth="6"/>
@@ -66,16 +66,6 @@
android:visibility="visible"
tools:text="item URL" />
-
-