Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 99 additions & 21 deletions app/src/main/java/com/cliqz/browser/main/TabFragment2.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import android.util.Patterns;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
Expand All @@ -25,10 +26,13 @@
import android.view.animation.Animation;
import android.view.inputmethod.InputMethodManager;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.Toast;

import androidx.annotation.ColorInt;
Expand All @@ -51,6 +55,7 @@
import com.cliqz.browser.tabs.TabsManager;
import com.cliqz.browser.telemetry.TelemetryKeys;
import com.cliqz.browser.utils.AppBackgroundManager;
import com.cliqz.browser.utils.ClipboardHandler;
import com.cliqz.browser.utils.ConfirmSubscriptionDialog;
import com.cliqz.browser.utils.EnableNotificationDialog;
import com.cliqz.browser.utils.SubscriptionsManager;
Expand Down Expand Up @@ -286,6 +291,19 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
mUnbinder = ButterKnife.bind(this, view);
searchBar.setSearchEditText(searchEditText);
searchBar.setProgressBar(progressBar);
searchBar.setOnClickListener(v -> {
if (searchBar.titleBar.getVisibility() == View.VISIBLE) {
if (antiTrackingDetails != null) {
searchBar.setAntiTrackingDetailsVisibility(View.GONE);
}
searchBar.showSearchEditText();
if (searchBar.mListener != null) {
searchBar.mListener.onTitleClicked(searchBar);
}
}
});
searchBar.setOnLongClickListener(v -> showClipboardPopUp());

final MainActivity activity = (MainActivity) getActivity();
final FlavoredActivityComponent component = activity != null ?
BrowserApp.getActivityComponent(activity) : null;
Expand Down Expand Up @@ -350,6 +368,60 @@ String getTelemetryView() {
}
}

private boolean showClipboardPopUp() {
final Context context = getContext();
final ClipboardHandler clipboard = new ClipboardHandler(context);
final View customView = LayoutInflater.from(context)
.inflate(R.layout.searchbar_long_press_popup_window, null);
final PopupWindow popupWindow = new PopupWindow(
customView,
LinearLayout.LayoutParams.WRAP_CONTENT,
context.getResources().getDimensionPixelSize(R.dimen.context_menu_height),
true
);

popupWindow.setElevation(context.getResources().getDimension(R.dimen.context_menu_elevation));

final Button copyButton = customView.findViewById(R.id.copy);
final Button pasteButton = customView.findViewById(R.id.paste);
final Button pasteAndGoButton = customView.findViewById(R.id.paste_and_go);

copyButton.setVisibility(searchBar.titleBar.getText().toString().isEmpty() ? View.GONE : View.VISIBLE);
pasteButton.setVisibility((clipboard.getText() != null && !clipboard.getText().isEmpty()) ? View.VISIBLE : View.GONE);
pasteAndGoButton.setVisibility((clipboard.getText() != null && !clipboard.getText().isEmpty()) ? View.VISIBLE : View.GONE);

copyButton.setOnClickListener(v -> {
popupWindow.dismiss();
clipboard.setText(searchBar.titleBar.getText().toString());
Toast.makeText(
context,
R.string.search_bar_long_press_popup_copied_to_clipboard_toast,
Toast.LENGTH_SHORT
).show();
});

pasteButton.setOnClickListener(v -> {
popupWindow.dismiss();
searchBar.setSearchText(clipboard.getText());
searchBar.showSearchEditText();
});

pasteAndGoButton.setOnClickListener(v -> {
popupWindow.dismiss();
searchBar.setSearchText(clipboard.getText());
final String content = searchBar.getSearchText();
searchOrVisitUrl(content);
});

popupWindow.showAsDropDown(
toolBarContainer,
getContext().getResources().getDimensionPixelSize(R.dimen.context_menu_x_offset),
getContext().getResources().getDimensionPixelSize(R.dimen.context_menu_y_offset),
Gravity.START
);
return true;
}

private void updateVpnIcon() {
if (mVpnPanelButton != null) {
if (vpnHandler.isVpnConnected()) {
Expand Down Expand Up @@ -605,30 +677,36 @@ boolean onEditorAction(EditText editText, int actionId, KeyEvent keyEvent) {
if (keyEvent != null && keyEvent.getKeyCode() == KeyEvent.KEYCODE_ENTER
&& keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
final String content = searchBar.getSearchText();
if (content != null && !content.isEmpty()) {
final Object event;
if (Patterns.WEB_URL.matcher(content).matches()) {
final String guessedUrl = StringUtils.guessUrl(content);
if (searchBar.isAutoCompleted()) {
telemetry.sendResultEnterSignal(false, true,
searchBar.getQuery().length(), guessedUrl.length());
} else {
telemetry.sendResultEnterSignal(false, false, content.length(), -1);
}
event = CliqzMessages.OpenLink.open(guessedUrl);
} else {
telemetry.sendResultEnterSignal(true, false, content.length(), -1);
setSearchEngine();
String searchUrl = mSearchEngine + UrlUtils.QUERY_PLACE_HOLDER;
event = CliqzMessages.OpenLink.open(UrlUtils.smartUrlFilter(content, true, searchUrl));
}
if (!onBoardingHelper.conditionallyShowSearchDescription()) {
bus.post(event);
return searchOrVisitUrl(content);
}
return false;
}


private boolean searchOrVisitUrl(String content) {
if (content != null && !content.isEmpty()) {
final Object event;
if (Patterns.WEB_URL.matcher(content).matches()) {
final String guessedUrl = StringUtils.guessUrl(content);
if (searchBar.isAutoCompleted()) {
telemetry.sendResultEnterSignal(false, true,
searchBar.getQuery().length(), guessedUrl.length());
} else {
hideKeyboard(null);
telemetry.sendResultEnterSignal(false, false, content.length(), -1);
}
return true;
event = CliqzMessages.OpenLink.open(guessedUrl);
} else {
telemetry.sendResultEnterSignal(true, false, content.length(), -1);
setSearchEngine();
final String searchUrl = mSearchEngine + UrlUtils.QUERY_PLACE_HOLDER;
event = CliqzMessages.OpenLink.open(UrlUtils.smartUrlFilter(content, true, searchUrl));
}
if (!onBoardingHelper.conditionallyShowSearchDescription()) {
bus.post(event);
} else {
hideKeyboard(null);
}
return true;
}
return false;
}
Expand Down
46 changes: 46 additions & 0 deletions app/src/main/java/com/cliqz/browser/utils/ClipboardHandler.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package com.cliqz.browser.utils

import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context

private const val MIME_TYPE_TEXT_PLAIN = "text/plain"
private const val MIME_TYPE_TEXT_HTML = "text/html"

/**
* A clipboard utility class that allows copying and pasting links/text to & from the clipboard
*/
class ClipboardHandler(context: Context) {
private val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager

var text: String?
get() {
if (!clipboard.isPrimaryClipEmpty() &&
(clipboard.isPrimaryClipPlainText() ||
clipboard.isPrimaryClipHtmlText())
) {
return clipboard.firstPrimaryClipItem?.text.toString()
}
return null
}
set(value) {
clipboard.primaryClip = ClipData.newPlainText("Text", value)
}

val url: String? = text

private fun ClipboardManager.isPrimaryClipPlainText() =
primaryClipDescription?.hasMimeType(MIME_TYPE_TEXT_PLAIN) ?: false

private fun ClipboardManager.isPrimaryClipHtmlText() =
primaryClipDescription?.hasMimeType(MIME_TYPE_TEXT_HTML) ?: false

private fun ClipboardManager.isPrimaryClipEmpty() = primaryClip?.itemCount == 0

private val ClipboardManager.firstPrimaryClipItem: ClipData.Item?
get() = primaryClip?.getItemAt(0)
}
34 changes: 2 additions & 32 deletions app/src/main/java/com/cliqz/browser/widget/SearchBar.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
Expand Down Expand Up @@ -73,7 +72,7 @@ public interface Listener extends TextWatcher, OnFocusChangeListener {
AppCompatImageView lock;

@BindView(R.id.title_bar)
TextView titleBar;
public TextView titleBar;

@Nullable
@BindView(R.id.tracker_counter)
Expand All @@ -84,7 +83,7 @@ public interface Listener extends TextWatcher, OnFocusChangeListener {
ViewGroup antiTrackingDetails;

@Nullable
Listener mListener;
public Listener mListener;

@Nullable
@BindView(R.id.reader_mode_button)
Expand Down Expand Up @@ -327,35 +326,6 @@ public void showKeyBoard() {
}
}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (event.getAction() != MotionEvent.ACTION_DOWN) {
return super.onInterceptTouchEvent(event);
}

if (antiTrackingDetails != null && antiTrackingDetails.getVisibility() == VISIBLE
&& event.getX() >= antiTrackingDetails.getX()) {
return super.onInterceptTouchEvent(event);
}

if (readerModeButton != null && readerModeButton.getVisibility() == VISIBLE
&& event.getX() >= readerModeButton.getX()) {
return super.onInterceptTouchEvent(event);
}

if (titleBar.getVisibility() == VISIBLE) {
if (antiTrackingDetails != null) {
setAntiTrackingDetailsVisibility(GONE);
}
showSearchEditText();
if (mListener != null) {
mListener.onTitleClicked(SearchBar.this);
}
return true;
}
return super.onInterceptTouchEvent(event);
}

/**
* Updates the color of the search bar depending on the mode of the tab
*
Expand Down
5 changes: 5 additions & 0 deletions app/src/main/res/drawable/rounded_all_corners.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/white" />
<corners android:radius="@dimen/context_menu_corner_radius"/>
</shape>
51 changes: 51 additions & 0 deletions app/src/main/res/layout/searchbar_long_press_popup_window.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/searchbar_long_press_popup_window"
android:layout_width="wrap_content"
android:layout_height="@dimen/context_menu_height"
android:layout_gravity="center"
android:layout_marginStart="12dp"
android:background="@drawable/rounded_all_corners"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingEnd="16dp">

<Button
android:id="@+id/copy"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="?selectableItemBackground"
android:minWidth="48dp"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:text="@string/search_bar_long_press_popup_copy"
android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:textSize="13sp" />

<Button
android:id="@+id/paste"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="?selectableItemBackground"
android:minWidth="48dp"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:text="@string/search_bar_long_press_popup_paste"
android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:textSize="13sp" />

<Button
android:id="@+id/paste_and_go"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="?selectableItemBackground"
android:minWidth="48dp"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:text="@string/search_bar_long_press_popup_paste_and_go"
android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:textSize="13sp" />
</LinearLayout>
8 changes: 8 additions & 0 deletions app/src/main/res/values/dimens.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,12 @@
<dimen name="text_padding">10dp</dimen>
<dimen name="topsites_logo_cornes_radius">5dp</dimen>
<dimen name="topsites_logo_textsize">24sp</dimen>

<dimen name="context_menu_corner_radius">6dp</dimen>

<dimen name="context_menu_height">36dp</dimen>
<dimen name="context_menu_x_offset">13dp</dimen>
<dimen name="context_menu_y_offset">8dp</dimen>

<dimen name="context_menu_elevation">3dp</dimen>
</resources>
6 changes: 6 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -329,4 +329,10 @@ Now you are ready to send tabs between your desktop and your mobile device. You
<string name="build_time">Build Date &amp; Time</string>
<string name="enable_android_backup_title">Enable Android Auto Backup</string>
<string name="enable_android_backup_summary">Auto Backup for Apps automatically backs up a user\'s data by uploading it to the user\'s Google Drive</string>

<!--Search bar long press popup menu -->
<string name="search_bar_long_press_popup_copy">Copy</string>
<string name="search_bar_long_press_popup_paste_and_go">Paste &amp; Go</string>
<string name="search_bar_long_press_popup_paste">Paste</string>
<string name="search_bar_long_press_popup_copied_to_clipboard_toast">URL copied to clipboard</string>
</resources>