Bug 1367079 - 1. Update TextSelection implementations for GeckoView; r=snorp
Make TextSelection implementations not depend on GeckoApp. Instead, make
them use GeckoView's EventDispatcher directly for communicating with
Gecko.
MozReview-Commit-ID: EygAt3D9HMI
--- a/mobile/android/base/java/org/mozilla/gecko/ActionBarTextSelection.java
+++ b/mobile/android/base/java/org/mozilla/gecko/ActionBarTextSelection.java
@@ -22,21 +22,21 @@ import android.view.Menu;
import android.view.MenuItem;
import java.util.Arrays;
import java.util.Timer;
import java.util.TimerTask;
import android.util.Log;
-class ActionBarTextSelection implements TextSelection, BundleEventListener {
+public class ActionBarTextSelection implements TextSelection, BundleEventListener {
private static final String LOGTAG = "GeckoTextSelection";
private static final int SHUTDOWN_DELAY_MS = 250;
- private final GeckoApp geckoApp;
+ private final GeckoView geckoView;
private final ActionModePresenter presenter;
private int selectionID; // Unique ID provided for each selection action.
private GeckoBundle[] mCurrentItems;
private TextSelectionActionModeCallback mCallback;
@@ -51,51 +51,42 @@ class ActionBarTextSelection implements
public void run() {
endActionMode();
}
});
}
};
private ActionModeTimerTask mActionModeTimerTask;
- ActionBarTextSelection(@NonNull final GeckoApp geckoApp,
- @Nullable final ActionModePresenter presenter) {
- this.geckoApp = geckoApp;
+ public ActionBarTextSelection(@NonNull final GeckoView geckoView,
+ @Nullable final ActionModePresenter presenter) {
+ this.geckoView = geckoView;
this.presenter = presenter;
}
@Override
public void create() {
- // Only register listeners if we have valid start/middle/end handles
- if (geckoApp == null) {
- Log.e(LOGTAG, "Failed to initialize text selection because at least one context is null");
- } else {
- geckoApp.getAppEventDispatcher().registerUiThreadListener(this,
- "TextSelection:ActionbarInit",
- "TextSelection:ActionbarStatus",
- "TextSelection:ActionbarUninit");
- }
+ geckoView.getEventDispatcher().registerUiThreadListener(this,
+ "TextSelection:ActionbarInit",
+ "TextSelection:ActionbarStatus",
+ "TextSelection:ActionbarUninit");
}
@Override
public boolean dismiss() {
// We do not call endActionMode() here because this is already handled by the activity.
return false;
}
@Override
public void destroy() {
- if (geckoApp == null) {
- Log.e(LOGTAG, "Do not unregister TextSelection:* listeners since context is null");
- } else {
- geckoApp.getAppEventDispatcher().unregisterUiThreadListener(this,
- "TextSelection:ActionbarInit",
- "TextSelection:ActionbarStatus",
- "TextSelection:ActionbarUninit");
- }
+ geckoView.getEventDispatcher().unregisterUiThreadListener(this,
+ "TextSelection:ActionbarInit",
+ "TextSelection:ActionbarStatus",
+ "TextSelection:ActionbarUninit");
}
@Override
public void handleMessage(final String event, final GeckoBundle message,
final EventCallback callback) {
if ("TextSelection:ActionbarInit".equals(event)) {
// Init / Open the action bar. Note the current selectionID,
// cancel any pending actionBar close.
@@ -179,17 +170,17 @@ class ActionBarTextSelection implements
final GeckoBundle obj = mItems[i];
final MenuItem menuitem = menu.add(0, i, 0, obj.getString("label", ""));
final int actionEnum = obj.getBoolean("showAsAction")
? MenuItem.SHOW_AS_ACTION_ALWAYS
: MenuItem.SHOW_AS_ACTION_NEVER;
menuitem.setShowAsAction(actionEnum);
final String iconString = obj.getString("icon", "");
- ResourceDrawableUtils.getDrawable(geckoApp, iconString,
+ ResourceDrawableUtils.getDrawable(geckoView.getContext(), iconString,
new ResourceDrawableUtils.BitmapLoader() {
@Override
public void onBitmapFound(Drawable d) {
if (d != null) {
menuitem.setIcon(d);
}
}
});
@@ -203,24 +194,24 @@ class ActionBarTextSelection implements
return true;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
final GeckoBundle obj = mItems[item.getItemId()];
final GeckoBundle data = new GeckoBundle(1);
data.putString("id", obj.getString("id", ""));
- geckoApp.getAppEventDispatcher().dispatch("TextSelection:Action", data);
+ geckoView.getEventDispatcher().dispatch("TextSelection:Action", data);
return true;
}
// Called when the user exits the action mode
@Override
public void onDestroyActionMode(ActionMode mode) {
mActionMode = null;
mCallback = null;
final GeckoBundle data = new GeckoBundle(1);
data.putInt("selectionID", selectionID);
- geckoApp.getAppEventDispatcher().dispatch("TextSelection:End", data);
+ geckoView.getEventDispatcher().dispatch("TextSelection:End", data);
}
}
}
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
@@ -1236,21 +1236,17 @@ public abstract class GeckoApp extends G
null);
Tabs.getInstance().attachToContext(this, mLayerView, getAppEventDispatcher());
Tabs.registerOnTabsChangedListener(this);
// Use global layout state change to kick off additional initialization
mMainLayout.getViewTreeObserver().addOnGlobalLayoutListener(this);
- if (Versions.preMarshmallow) {
- mTextSelection = new ActionBarTextSelection(this, getTextSelectPresenter());
- } else {
- mTextSelection = new FloatingToolbarTextSelection(this, mLayerView);
- }
+ mTextSelection = TextSelection.Factory.create(mLayerView, getTextSelectPresenter());
mTextSelection.create();
final Bundle finalSavedInstanceState = savedInstanceState;
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
// Determine whether we should restore tabs.
mLastSessionCrashed = updateCrashedState();
--- a/mobile/android/base/java/org/mozilla/gecko/text/FloatingActionModeCallback.java
+++ b/mobile/android/base/java/org/mozilla/gecko/text/FloatingActionModeCallback.java
@@ -49,17 +49,17 @@ public class FloatingActionModeCallback
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
final TextAction action = actions.get(item.getItemId());
final GeckoBundle data = new GeckoBundle(1);
data.putString("id", action.getId());
- textSelection.geckoApp.getAppEventDispatcher().dispatch("TextSelection:Action", data);
+ textSelection.geckoView.getEventDispatcher().dispatch("TextSelection:Action", data);
return true;
}
@Override
public void onDestroyActionMode(ActionMode mode) {}
@Override
--- a/mobile/android/base/java/org/mozilla/gecko/text/FloatingToolbarTextSelection.java
+++ b/mobile/android/base/java/org/mozilla/gecko/text/FloatingToolbarTextSelection.java
@@ -8,21 +8,20 @@ import android.annotation.TargetApi;
import android.app.Activity;
import android.graphics.Rect;
import android.os.Build;
import android.util.Log;
import android.util.TypedValue;
import android.view.ActionMode;
import org.mozilla.gecko.EventDispatcher;
-import org.mozilla.gecko.GeckoApp;
-import org.mozilla.gecko.GeckoAppShell;
+import org.mozilla.gecko.GeckoView;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
-import org.mozilla.gecko.gfx.LayerView;
+import org.mozilla.gecko.util.ActivityUtils;
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 java.util.List;
/**
@@ -31,33 +30,31 @@ import java.util.List;
@TargetApi(Build.VERSION_CODES.M)
public class FloatingToolbarTextSelection implements TextSelection, BundleEventListener {
private static final String LOGTAG = "GeckoFloatTextSelection";
// This is an additional offset we add to the height of the selection. This will avoid that the
// floating toolbar overlays the bottom handle(s).
private static final int HANDLES_OFFSET_DP = 20;
- /* package */ final GeckoApp geckoApp;
- private final LayerView layerView;
+ /* package */ final GeckoView geckoView;
private final int[] locationInWindow;
private final float handlesOffset;
private ActionMode actionMode;
private FloatingActionModeCallback actionModeCallback;
private int selectionID;
/* package-private */ Rect contentRect;
- public FloatingToolbarTextSelection(GeckoApp geckoApp, LayerView layerView) {
- this.geckoApp = geckoApp;
- this.layerView = layerView;
+ public FloatingToolbarTextSelection(final GeckoView geckoView) {
+ this.geckoView = geckoView;
this.locationInWindow = new int[2];
this.handlesOffset = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- HANDLES_OFFSET_DP, geckoApp.getResources().getDisplayMetrics());
+ HANDLES_OFFSET_DP, geckoView.getContext().getResources().getDisplayMetrics());
}
@Override
public boolean dismiss() {
if (finishActionMode()) {
endTextSelection();
return true;
}
@@ -67,39 +64,39 @@ public class FloatingToolbarTextSelectio
private void endTextSelection() {
if (selectionID == 0) {
return;
}
final GeckoBundle data = new GeckoBundle(1);
data.putInt("selectionID", selectionID);
- geckoApp.getAppEventDispatcher().dispatch("TextSelection:End", data);
+ geckoView.getEventDispatcher().dispatch("TextSelection:End", data);
}
@Override
public void create() {
registerForEvents();
}
@Override
public void destroy() {
unregisterFromEvents();
}
private void registerForEvents() {
- geckoApp.getAppEventDispatcher().registerUiThreadListener(this,
+ geckoView.getEventDispatcher().registerUiThreadListener(this,
"TextSelection:ActionbarInit",
"TextSelection:ActionbarStatus",
"TextSelection:ActionbarUninit",
"TextSelection:Visibility");
}
private void unregisterFromEvents() {
- geckoApp.getAppEventDispatcher().unregisterUiThreadListener(this,
+ geckoView.getEventDispatcher().unregisterUiThreadListener(this,
"TextSelection:ActionbarInit",
"TextSelection:ActionbarStatus",
"TextSelection:ActionbarUninit",
"TextSelection:Visibility");
}
@Override // BundleEventListener
public void handleMessage(final String event, final GeckoBundle message,
@@ -134,18 +131,23 @@ public class FloatingToolbarTextSelectio
private void startActionMode(List<TextAction> actions) {
if (actionMode != null) {
actionModeCallback.updateActions(actions);
actionMode.invalidate();
return;
}
+ final Activity activity =
+ ActivityUtils.getActivityFromContext(geckoView.getContext());
+ if (activity == null) {
+ return;
+ }
actionModeCallback = new FloatingActionModeCallback(this, actions);
- actionMode = geckoApp.startActionMode(actionModeCallback, ActionMode.TYPE_FLOATING);
+ actionMode = activity.startActionMode(actionModeCallback, ActionMode.TYPE_FLOATING);
}
private boolean finishActionMode() {
if (actionMode != null) {
actionMode.finish();
actionMode = null;
actionModeCallback = null;
return true;
@@ -166,19 +168,19 @@ public class FloatingToolbarTextSelectio
}
private void updateRect(final GeckoBundle message) {
final double x = message.getDouble("x");
final double y = (int) message.getDouble("y");
final double width = (int) message.getDouble("width");
final double height = (int) message.getDouble("height");
- final float toolbarOffset = layerView.getCurrentToolbarHeight();
- final float zoomFactor = layerView.getZoomFactor();
- layerView.getLocationInWindow(locationInWindow);
+ final float toolbarOffset = geckoView.getCurrentToolbarHeight();
+ final float zoomFactor = geckoView.getZoomFactor();
+ geckoView.getLocationInWindow(locationInWindow);
contentRect = new Rect(
(int) (x * zoomFactor + locationInWindow[0]),
(int) (y * zoomFactor + locationInWindow[1] + toolbarOffset),
(int) ((x + width) * zoomFactor + locationInWindow[0]),
(int) ((y + height) * zoomFactor + locationInWindow[1] +
(height > 0 ? handlesOffset : 0)));
}
--- a/mobile/android/base/java/org/mozilla/gecko/text/TextSelection.java
+++ b/mobile/android/base/java/org/mozilla/gecko/text/TextSelection.java
@@ -1,13 +1,32 @@
/* 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 org.mozilla.gecko.text;
+import org.mozilla.gecko.ActionBarTextSelection;
+import org.mozilla.gecko.AppConstants.Versions;
+import org.mozilla.gecko.GeckoView;
+import org.mozilla.gecko.widget.ActionModePresenter;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
public interface TextSelection {
void create();
boolean dismiss();
void destroy();
+
+ static class Factory {
+ public static TextSelection create(@NonNull final GeckoView geckoView,
+ @Nullable final ActionModePresenter presenter) {
+ if (Versions.preMarshmallow) {
+ return new ActionBarTextSelection(geckoView, presenter);
+ } else {
+ return new FloatingToolbarTextSelection(geckoView);
+ }
+ }
+ }
}