Bug 1328990 - Convert FormAssistPopup events to bundle events; r=sebastian

Convert "FormAssist:*" events in FormAssistPopup to
GeckoBundle/BundleEventListener events.  UI thread events are used
because the listener performs operations on the UI thread.

Also convert the "FormAssist:*" observers in browser.js to use
WindowEventDispatcher.

The "FormAssist:AutoComplete" event that goes from Gecko to Java is
renamed to "FormAssist:AutoCompleteResult" to prevent conflict with the
event with the same name that goes from Java to Gecko.
This commit is contained in:
Jim Chen 2017-01-17 20:06:07 -05:00
Родитель abfbb82e23
Коммит 58eee87559
2 изменённых файлов: 104 добавлений и 136 удалений

Просмотреть файл

@ -8,15 +8,13 @@ package org.mozilla.gecko;
import org.mozilla.gecko.animation.ViewHelper;
import org.mozilla.gecko.gfx.FloatSize;
import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.BundleEventListener;
import org.mozilla.gecko.util.EventCallback;
import org.mozilla.gecko.util.GeckoBundle;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.widget.SwipeDismissListViewTouchListener;
import org.mozilla.gecko.widget.SwipeDismissListViewTouchListener.OnDismissCallback;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.PointF;
@ -41,7 +39,7 @@ import android.widget.TextView;
import java.util.Arrays;
import java.util.Collection;
public class FormAssistPopup extends RelativeLayout implements GeckoEventListener {
public class FormAssistPopup extends RelativeLayout implements BundleEventListener {
private final Context mContext;
private final Animation mAnimation;
@ -96,8 +94,8 @@ public class FormAssistPopup extends RelativeLayout implements GeckoEventListene
public void onAttachedToWindow() {
super.onAttachedToWindow();
GeckoApp.getEventDispatcher().registerGeckoThreadListener(this,
"FormAssist:AutoComplete",
GeckoApp.getEventDispatcher().registerUiThreadListener(this,
"FormAssist:AutoCompleteResult",
"FormAssist:ValidationMessage",
"FormAssist:Hide");
}
@ -107,62 +105,34 @@ public class FormAssistPopup extends RelativeLayout implements GeckoEventListene
@Override
public void onDetachedFromWindow() {
GeckoApp.getEventDispatcher().unregisterGeckoThreadListener(this,
"FormAssist:AutoComplete",
GeckoApp.getEventDispatcher().unregisterUiThreadListener(this,
"FormAssist:AutoCompleteResult",
"FormAssist:ValidationMessage",
"FormAssist:Hide");
super.onDetachedFromWindow();
}
@Override
public void handleMessage(String event, JSONObject message) {
try {
if (event.equals("FormAssist:AutoComplete")) {
handleAutoCompleteMessage(message);
} else if (event.equals("FormAssist:ValidationMessage")) {
handleValidationMessage(message);
} else if (event.equals("FormAssist:Hide")) {
handleHideMessage(message);
}
} catch (Exception e) {
Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
@Override // BundleEventListener
public void handleMessage(final String event, final GeckoBundle message,
final EventCallback callback) {
if ("FormAssist:AutoCompleteResult".equals(event)) {
showAutoCompleteSuggestions(message.getBundleArray("suggestions"),
message.getBundle("rect"),
message.getBoolean("isEmpty"));
} else if ("FormAssist:ValidationMessage".equals(event)) {
showValidationMessage(message.getString("validationMessage"),
message.getBundle("rect"));
} else if ("FormAssist:Hide".equals(event)) {
hide();
}
}
private void handleAutoCompleteMessage(JSONObject message) throws JSONException {
final JSONArray suggestions = message.getJSONArray("suggestions");
final JSONObject rect = message.getJSONObject("rect");
final boolean isEmpty = message.getBoolean("isEmpty");
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
showAutoCompleteSuggestions(suggestions, rect, isEmpty);
}
});
}
private void handleValidationMessage(JSONObject message) throws JSONException {
final String validationMessage = message.getString("validationMessage");
final JSONObject rect = message.getJSONObject("rect");
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
showValidationMessage(validationMessage, rect);
}
});
}
private void handleHideMessage(JSONObject message) {
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
hide();
}
});
}
private void showAutoCompleteSuggestions(JSONArray suggestions, JSONObject rect, boolean isEmpty) {
private void showAutoCompleteSuggestions(final GeckoBundle[] suggestions,
final GeckoBundle rect,
final boolean isEmpty) {
final String inputMethod = InputMethods.getCurrentInputMethod(mContext);
if (!isEmpty && sInputMethodBlocklist.contains(inputMethod)) {
// Don't display the form auto-complete popup after the user starts typing
@ -180,9 +150,10 @@ public class FormAssistPopup extends RelativeLayout implements GeckoEventListene
public void onItemClick(AdapterView<?> parentView, View view, int position, long id) {
// Use the value stored with the autocomplete view, not the label text,
// since they can be different.
TextView textView = (TextView) view;
String value = (String) textView.getTag();
broadcastGeckoEvent("FormAssist:AutoComplete", value);
final TextView textView = (TextView) view;
final GeckoBundle message = new GeckoBundle(1);
message.putString("value", (String) textView.getTag());
GeckoApp.getEventDispatcher().dispatch("FormAssist:AutoComplete", message);
hide();
}
});
@ -199,7 +170,9 @@ public class FormAssistPopup extends RelativeLayout implements GeckoEventListene
Pair<String, String> item = adapter.getItem(position);
// Remove the item from form history.
broadcastGeckoEvent("FormAssist:Remove", item.second);
final GeckoBundle message = new GeckoBundle(1);
message.putString("value", item.second);
GeckoApp.getEventDispatcher().dispatch("FormAssist:Remove", message);
// Update the list
adapter.remove(item);
@ -228,7 +201,8 @@ public class FormAssistPopup extends RelativeLayout implements GeckoEventListene
}
}
private void showValidationMessage(String validationMessage, JSONObject rect) {
private void showValidationMessage(final String validationMessage,
final GeckoBundle rect) {
if (mValidationMessage == null) {
LayoutInflater inflater = LayoutInflater.from(mContext);
mValidationMessage = (RelativeLayout) inflater.inflate(R.layout.validation_message, null);
@ -258,18 +232,12 @@ public class FormAssistPopup extends RelativeLayout implements GeckoEventListene
}
}
private boolean setGeckoPositionData(JSONObject rect, boolean isAutoComplete) {
try {
mX = rect.getDouble("x");
mY = rect.getDouble("y");
mW = rect.getDouble("w");
mH = rect.getDouble("h");
} catch (JSONException e) {
// Bail if we can't get the correct dimensions for the popup.
Log.e(LOGTAG, "Error getting FormAssistPopup dimensions", e);
return false;
}
private boolean setGeckoPositionData(final GeckoBundle rect,
final boolean isAutoComplete) {
mX = rect.getDouble("x");
mY = rect.getDouble("y");
mW = rect.getDouble("w");
mH = rect.getDouble("h");
mPopupType = (isAutoComplete ?
PopupType.AUTOCOMPLETE : PopupType.VALIDATIONMESSAGE);
return true;
@ -394,7 +362,7 @@ public class FormAssistPopup extends RelativeLayout implements GeckoEventListene
public void hide() {
if (isShown()) {
setVisibility(GONE);
broadcastGeckoEvent("FormAssist:Hidden", null);
GeckoApp.getEventDispatcher().dispatch("FormAssist:Hidden", null);
}
}
@ -419,10 +387,6 @@ public class FormAssistPopup extends RelativeLayout implements GeckoEventListene
});
}
private static void broadcastGeckoEvent(String eventName, String eventData) {
GeckoAppShell.notifyObservers(eventName, eventData);
}
private class AutoCompleteListAdapter extends ArrayAdapter<Pair<String, String>> {
private final LayoutInflater mInflater;
private final int mTextViewResourceId;
@ -436,16 +400,12 @@ public class FormAssistPopup extends RelativeLayout implements GeckoEventListene
// This method takes an array of autocomplete suggestions with label/value properties
// and adds label/value Pair objects to the array that backs the adapter.
public void populateSuggestionsList(JSONArray suggestions) {
try {
for (int i = 0; i < suggestions.length(); i++) {
JSONObject suggestion = suggestions.getJSONObject(i);
String label = suggestion.getString("label");
String value = suggestion.getString("value");
add(new Pair<String, String>(label, value));
}
} catch (JSONException e) {
Log.e(LOGTAG, "JSONException", e);
public void populateSuggestionsList(final GeckoBundle[] suggestions) {
for (int i = 0; i < suggestions.length; i++) {
final GeckoBundle suggestion = suggestions[i];
final String label = suggestion.getString("label");
final String value = suggestion.getString("value");
add(new Pair<String, String>(label, value));
}
}

Просмотреть файл

@ -4664,7 +4664,7 @@ var BrowserEventHandler = {
} catch(e) {
Cu.reportError(e);
}
Messaging.sendRequest({ type: "FormAssist:Hide" });
WindowEventDispatcher.sendRequest({ type: "FormAssist:Hide" });
}
this._clusterClicked(x, y);
} else {
@ -4856,9 +4856,12 @@ var FormAssistant = {
_invalidSubmit: false,
init: function() {
Services.obs.addObserver(this, "FormAssist:AutoComplete", false);
Services.obs.addObserver(this, "FormAssist:Hidden", false);
Services.obs.addObserver(this, "FormAssist:Remove", false);
WindowEventDispatcher.registerListener(this, [
"FormAssist:AutoComplete",
"FormAssist:Hidden",
"FormAssist:Remove",
]);
Services.obs.addObserver(this, "invalidformsubmit", false);
Services.obs.addObserver(this, "PanZoom:StateChange", false);
@ -4870,6 +4873,52 @@ var FormAssistant = {
BrowserApp.deck.addEventListener("pageshow", this);
},
onEvent: function(event, message, callback) {
switch (event) {
case "FormAssist:AutoComplete":
if (!this._currentInputElement)
break;
let editableElement = this._currentInputElement.QueryInterface(Ci.nsIDOMNSEditableElement);
this._doingAutocomplete = true;
// If we have an active composition string, commit it before sending
// the autocomplete event with the text that will replace it.
try {
if (editableElement.editor.composing)
editableElement.editor.forceCompositionEnd();
} catch (e) {}
editableElement.setUserInput(message.value);
this._currentInputValue = message.value;
let event = this._currentInputElement.ownerDocument.createEvent("Events");
event.initEvent("DOMAutoComplete", true, true);
this._currentInputElement.dispatchEvent(event);
this._doingAutocomplete = false;
break;
case "FormAssist:Hidden":
this._currentInputElement = null;
break;
case "FormAssist:Remove":
if (!this._currentInputElement) {
break;
}
FormHistory.update({
op: "remove",
fieldname: this._currentInputElement.name,
value: message.value,
});
break;
}
},
observe: function(aSubject, aTopic, aData) {
switch (aTopic) {
case "PanZoom:StateChange":
@ -4895,47 +4944,6 @@ var FormAssistant = {
this._hideFormAssistPopup();
}
break;
case "FormAssist:AutoComplete":
if (!this._currentInputElement)
break;
let editableElement = this._currentInputElement.QueryInterface(Ci.nsIDOMNSEditableElement);
this._doingAutocomplete = true;
// If we have an active composition string, commit it before sending
// the autocomplete event with the text that will replace it.
try {
if (editableElement.editor.composing)
editableElement.editor.forceCompositionEnd();
} catch (e) {}
editableElement.setUserInput(aData);
this._currentInputValue = aData;
let event = this._currentInputElement.ownerDocument.createEvent("Events");
event.initEvent("DOMAutoComplete", true, true);
this._currentInputElement.dispatchEvent(event);
this._doingAutocomplete = false;
break;
case "FormAssist:Hidden":
this._currentInputElement = null;
break;
case "FormAssist:Remove":
if (!this._currentInputElement) {
break;
}
FormHistory.update({
op: "remove",
fieldname: this._currentInputElement.name,
value: aData
});
break;
}
},
@ -5138,8 +5146,8 @@ var FormAssistant = {
return;
}
Messaging.sendRequest({
type: "FormAssist:AutoComplete",
WindowEventDispatcher.sendRequest({
type: "FormAssist:AutoCompleteResult",
suggestions: suggestions,
rect: ElementTouchHelper.getBoundingContentRect(aElement),
isEmpty: isEmpty,
@ -5174,7 +5182,7 @@ var FormAssistant = {
if (!this._isValidateable(aElement))
return false;
Messaging.sendRequest({
WindowEventDispatcher.sendRequest({
type: "FormAssist:ValidationMessage",
validationMessage: aElement.validationMessage,
rect: ElementTouchHelper.getBoundingContentRect(aElement)
@ -5184,7 +5192,7 @@ var FormAssistant = {
},
_hideFormAssistPopup: function _hideFormAssistPopup() {
Messaging.sendRequest({ type: "FormAssist:Hide" });
WindowEventDispatcher.sendRequest({ type: "FormAssist:Hide" });
},
_isDisabledElement : function(aElement) {