Bug 1050480 - Add a match case option to find-in-page, r=wesj
--- a/mobile/android/base/FindInPageBar.java
+++ b/mobile/android/base/FindInPageBar.java
@@ -4,37 +4,40 @@
package org.mozilla.gecko;
import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.GeckoRequest;
import org.mozilla.gecko.util.NativeJSObject;
import org.mozilla.gecko.util.ThreadUtils;
+import org.json.JSONException;
import org.json.JSONObject;
import android.content.Context;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
+import android.widget.CheckedTextView;
import android.widget.LinearLayout;
import android.widget.TextView;
public class FindInPageBar extends LinearLayout implements TextWatcher, View.OnClickListener, GeckoEventListener {
- private static final String LOGTAG = "FindInPageBar";
+ private static final String LOGTAG = "GeckoFindInPageBar";
private static final String REQUEST_ID = "FindInPageBar";
private final Context mContext;
private CustomEditText mFindText;
+ private CheckedTextView mMatchCase;
private TextView mStatusText;
private boolean mInflated;
public FindInPageBar(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
setFocusable(true);
}
@@ -59,16 +62,19 @@ public class FindInPageBar extends Linea
if (keyCode == KeyEvent.KEYCODE_BACK) {
hide();
return true;
}
return false;
}
});
+ mMatchCase = (CheckedTextView) content.findViewById(R.id.find_matchcase);
+ mMatchCase.setOnClickListener(this);
+
mStatusText = (TextView) content.findViewById(R.id.find_status);
mInflated = true;
EventDispatcher.getInstance().registerGeckoThreadListener(this, "TextSelection:Data");
}
public void show() {
if (!mInflated)
@@ -118,16 +124,26 @@ public class FindInPageBar extends Linea
}
// View.OnClickListener implementation
@Override
public void onClick(View v) {
final int viewId = v.getId();
+ if (viewId == R.id.find_matchcase) {
+ // Toggle matchcase state (color).
+ mMatchCase.toggle();
+
+ // Repeat the find after a matchcase change.
+ sendRequestToFinderHelper("FindInPage:Find", mFindText.getText().toString());
+ getInputMethodManager(mFindText).hideSoftInputFromWindow(mFindText.getWindowToken(), 0);
+ return;
+ }
+
if (viewId == R.id.find_prev) {
sendRequestToFinderHelper("FindInPage:Prev", mFindText.getText().toString());
getInputMethodManager(mFindText).hideSoftInputFromWindow(mFindText.getWindowToken(), 0);
return;
}
if (viewId == R.id.find_next) {
sendRequestToFinderHelper("FindInPage:Next", mFindText.getText().toString());
@@ -179,17 +195,26 @@ public class FindInPageBar extends Linea
});
}
}
/**
* Request find operation, and update matchCount results (current count and total).
*/
private void sendRequestToFinderHelper(final String request, final String searchString) {
- GeckoAppShell.sendRequestToGecko(new GeckoRequest(request, searchString) {
+ final JSONObject json = new JSONObject();
+ try {
+ json.put("searchString", searchString);
+ json.put("matchCase", mMatchCase.isChecked());
+ } catch (JSONException e) {
+ Log.e(LOGTAG, "JSON error - Error creating JSONObject", e);
+ return;
+ }
+
+ GeckoAppShell.sendRequestToGecko(new GeckoRequest(request, json) {
@Override
public void onResponse(NativeJSObject nativeJSObject) {
final int total = nativeJSObject.optInt("total", 0);
final int current = nativeJSObject.optInt("current", 0);
updateResult(total, current);
}
public void onError() {
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -552,8 +552,13 @@ just addresses the organization to follo
<!-- Localization note (remote_tabs_last_synced): the variable is replaced by a
"relative time span string" produced by Android. This string describes the
time the tabs were last synced relative to the current time; examples
include "42 minutes ago", "4 days ago", "last week", etc. The subject of
"Last synced" is one of the user's other Sync clients, typically Firefox on
their desktop or laptop.-->
<!ENTITY remote_tabs_last_synced "Last synced: &formatS;">
+
+<!-- Find-In-Page strings -->
+<!-- LOCALIZATION NOTE (find_matchcase): This is meant to appear as an icon that changes color
+ if match-case is activated. i.e. No more than two letters, one uppercase, one lowercase. -->
+<!ENTITY find_matchcase "Aa">
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/resources/drawable/find_matchcase_selector.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:state_checked="true"
+ android:color="@color/find_matchcase_on"/>
+
+ <item android:state_checked="false"
+ android:color="@color/find_matchcase_off"/>
+
+</selector>
--- a/mobile/android/base/resources/layout/find_in_page_content.xml
+++ b/mobile/android/base/resources/layout/find_in_page_content.xml
@@ -23,16 +23,25 @@
<TextView android:id="@+id/find_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/find_in_page_status_margin_right"
android:textColor="@color/find_status_default"
android:visibility="gone"/>
+ <CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/find_matchcase"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="@dimen/find_in_page_matchcase_margin_right"
+ android:checked="false"
+ android:text="@string/find_matchcase"
+ android:textColor="@drawable/find_matchcase_selector"/>
+
<ImageButton android:id="@+id/find_prev"
style="@style/FindBar.ImageButton"
android:contentDescription="@string/find_prev"
android:layout_marginTop="@dimen/find_in_page_control_margin_top"
android:src="@drawable/find_prev"/>
<ImageButton android:id="@+id/find_next"
style="@style/FindBar.ImageButton"
--- a/mobile/android/base/resources/values/colors.xml
+++ b/mobile/android/base/resources/values/colors.xml
@@ -147,16 +147,18 @@
<color name="tab_history_timeline_separator">#D7D9DB</color>
<color name="tab_history_favicon_border">#D7D9DB</color>
<color name="tab_history_favicon_background">#FFFFFF</color>
<color name="tab_history_title_color">#363B40</color>
<color name="tab_history_border_color">#DADADF</color>
<!-- Colour used for Find-In-Page dialog -->
<color name="find_status_default">#AFB1B3</color>
+ <color name="find_matchcase_on">#AFB1B3</color>
+ <color name="find_matchcase_off">#D02626</color>
<!-- Canvas delegate paint color -->
<color name="canvas_delegate_paint">#FFFF0000</color>
<!-- Top sites thumbnail colors -->
<color name="top_site_default">#FFECF0F3</color>
<color name="top_site_border">#FFCFD9E1</color>
--- a/mobile/android/base/resources/values/dimens.xml
+++ b/mobile/android/base/resources/values/dimens.xml
@@ -178,12 +178,13 @@
<dimen name="tab_history_bg_width">2dp</dimen>
<dimen name="tab_history_border_padding">2dp</dimen>
<!-- Find-In-Page dialog dimensions. -->
<dimen name="find_in_page_text_margin_left">5dip</dimen>
<dimen name="find_in_page_text_margin_right">12dip</dimen>
<dimen name="find_in_page_text_padding_left">10dip</dimen>
<dimen name="find_in_page_text_padding_right">10dip</dimen>
- <dimen name="find_in_page_status_margin_right">5dip</dimen>
+ <dimen name="find_in_page_status_margin_right">15dip</dimen>
+ <dimen name="find_in_page_matchcase_margin_right">10dip</dimen>
<dimen name="find_in_page_control_margin_top">2dip</dimen>
</resources>
--- a/mobile/android/chrome/content/FindHelper.js
+++ b/mobile/android/chrome/content/FindHelper.js
@@ -28,28 +28,28 @@ var FindHelper = {
this._uninit();
this._findClosed();
break;
}
},
_findOpened: function() {
Messaging.addListener((data) => {
- this.doFind(data);
- return this._getMatchesCountResult(data);
+ this.doFind(data.searchString, data.matchCase);
+ return this._getMatchesCountResult(data.searchString);
}, "FindInPage:Find");
Messaging.addListener((data) => {
- this.findAgain(data, false);
- return this._getMatchesCountResult(data);
+ this.findAgain(data.searchString, false, data.matchCase);
+ return this._getMatchesCountResult(data.searchString);
}, "FindInPage:Next");
Messaging.addListener((data) => {
- this.findAgain(data, true);
- return this._getMatchesCountResult(data);
+ this.findAgain(data.searchString, true, data.matchCase);
+ return this._getMatchesCountResult(data.searchString);
}, "FindInPage:Prev");
},
_init: function() {
// If there's no find in progress, start one.
if (this._finder) {
return;
}
@@ -94,32 +94,34 @@ var FindHelper = {
/**
* Pass along the count results to FindInPageBar for display.
*/
onMatchesCountResult: function(result) {
this._matchesCountResult = result;
},
- doFind: function(aSearchString) {
+ doFind: function(searchString, matchCase) {
if (!this._finder) {
this._init();
}
- this._finder.fastFind(aSearchString, false);
+ this._finder.caseSensitive = matchCase;
+ this._finder.fastFind(searchString, false);
},
- findAgain: function(aString, aFindBackwards) {
+ findAgain: function(searchString, findBackwards, matchCase) {
// This can happen if the user taps next/previous after re-opening the search bar
if (!this._finder) {
- this.doFind(aString);
+ this.doFind(searchString, matchCase);
return;
}
- this._finder.findAgain(aFindBackwards, false, false);
+ this._finder.caseSensitive = matchCase;
+ this._finder.findAgain(findBackwards, false, false);
},
onFindResult: function(aData) {
if (aData.result == Ci.nsITypeAheadFind.FIND_NOTFOUND) {
if (this._viewportChanged) {
if (this._targetTab != BrowserApp.selectedTab) {
// this should never happen
Cu.reportError("Warning: selected tab changed during find!");
--- a/mobile/android/services/strings.xml.in
+++ b/mobile/android/services/strings.xml.in
@@ -211,8 +211,11 @@
<string name="fxaccount_sync_sign_in_error_notification_title">&fxaccount_sync_sign_in_error_notification_title2;</string>
<string name="fxaccount_sync_sign_in_error_notification_text">&fxaccount_sync_sign_in_error_notification_text2;</string>
<!-- Remove Account -->
<string name="fxaccount_remove_account_dialog_title">&fxaccount_remove_account_dialog_title;</string>
<string name="fxaccount_remove_account_dialog_message">&fxaccount_remove_account_dialog_message;</string>
<string name="fxaccount_remove_account_toast">&fxaccount_remove_account_toast;</string>
<string name="fxaccount_remove_account_menu_item">&fxaccount_remove_account_menu_item;</string>
+
+<!-- Find-In-Page strings -->
+<string name="find_matchcase">&find_matchcase;</string>