mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-05 15:28:39 +09:00
pt 1 in reviving the android build (copied from pm 28a1, wish me luck)
This commit is contained in:
parent
efa9662725
commit
d7788a6d6d
4249 changed files with 468189 additions and 0 deletions
|
|
@ -0,0 +1,69 @@
|
|||
/* 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 android.annotation.TargetApi;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.view.ActionMode;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
import org.mozilla.gecko.GeckoAppShell;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
public class FloatingActionModeCallback extends ActionMode.Callback2 {
|
||||
private FloatingToolbarTextSelection textSelection;
|
||||
private List<TextAction> actions;
|
||||
|
||||
public FloatingActionModeCallback(FloatingToolbarTextSelection textSelection, List<TextAction> actions) {
|
||||
this.textSelection = textSelection;
|
||||
this.actions = actions;
|
||||
}
|
||||
|
||||
public void updateActions(List<TextAction> actions) {
|
||||
this.actions = actions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
|
||||
menu.clear();
|
||||
|
||||
for (int i = 0; i < actions.size(); i++) {
|
||||
final TextAction action = actions.get(i);
|
||||
menu.add(Menu.NONE, i, action.getFloatingOrder(), action.getLabel());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
||||
final TextAction action = actions.get(item.getItemId());
|
||||
|
||||
GeckoAppShell.notifyObservers("TextSelection:Action", action.getId());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyActionMode(ActionMode mode) {}
|
||||
|
||||
@Override
|
||||
public void onGetContentRect(ActionMode mode, View view, Rect outRect) {
|
||||
final Rect contentRect = textSelection.contentRect;
|
||||
if (contentRect != null) {
|
||||
outRect.set(contentRect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,206 @@
|
|||
/* 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 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.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import org.mozilla.gecko.EventDispatcher;
|
||||
import org.mozilla.gecko.GeckoApp;
|
||||
import org.mozilla.gecko.GeckoAppShell;
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
import org.mozilla.gecko.TelemetryContract;
|
||||
import org.mozilla.gecko.gfx.LayerView;
|
||||
import org.mozilla.gecko.util.GeckoEventListener;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ch.boye.httpclientandroidlib.util.TextUtils;
|
||||
|
||||
/**
|
||||
* Floating toolbar for text selection actions. Only on Android 6+.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
public class FloatingToolbarTextSelection implements TextSelection, GeckoEventListener {
|
||||
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;
|
||||
|
||||
private final Activity activity;
|
||||
private final LayerView layerView;
|
||||
private final int[] locationInWindow;
|
||||
private final float handlesOffset;
|
||||
|
||||
private ActionMode actionMode;
|
||||
private FloatingActionModeCallback actionModeCallback;
|
||||
private String selectionID;
|
||||
/* package-private */ Rect contentRect;
|
||||
|
||||
public FloatingToolbarTextSelection(Activity activity, LayerView layerView) {
|
||||
this.activity = activity;
|
||||
this.layerView = layerView;
|
||||
this.locationInWindow = new int[2];
|
||||
|
||||
this.handlesOffset = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
|
||||
HANDLES_OFFSET_DP, activity.getResources().getDisplayMetrics());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dismiss() {
|
||||
if (finishActionMode()) {
|
||||
endTextSelection();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void endTextSelection() {
|
||||
if (TextUtils.isEmpty(selectionID)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final JSONObject args = new JSONObject();
|
||||
try {
|
||||
args.put("selectionID", selectionID);
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOGTAG, "Error building JSON arguments for TextSelection:End", e);
|
||||
return;
|
||||
}
|
||||
|
||||
GeckoAppShell.notifyObservers("TextSelection:End", args.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void create() {
|
||||
registerForEvents();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
unregisterFromEvents();
|
||||
}
|
||||
|
||||
private void registerForEvents() {
|
||||
GeckoApp.getEventDispatcher().registerGeckoThreadListener(this,
|
||||
"TextSelection:ActionbarInit",
|
||||
"TextSelection:ActionbarStatus",
|
||||
"TextSelection:ActionbarUninit",
|
||||
"TextSelection:Update",
|
||||
"TextSelection:Visibility");
|
||||
}
|
||||
|
||||
private void unregisterFromEvents() {
|
||||
GeckoApp.getEventDispatcher().unregisterGeckoThreadListener(this,
|
||||
"TextSelection:ActionbarInit",
|
||||
"TextSelection:ActionbarStatus",
|
||||
"TextSelection:ActionbarUninit",
|
||||
"TextSelection:Update",
|
||||
"TextSelection:Visibility");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(final String event, final JSONObject message) {
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
handleOnMainThread(event, message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void handleOnMainThread(final String event, final JSONObject message) {
|
||||
if ("TextSelection:ActionbarInit".equals(event)) {
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.SHOW,
|
||||
TelemetryContract.Method.CONTENT, "text_selection");
|
||||
|
||||
selectionID = message.optString("selectionID");
|
||||
} else if ("TextSelection:ActionbarStatus".equals(event)) {
|
||||
// Ensure async updates from SearchService for example are valid.
|
||||
if (selectionID != message.optString("selectionID")) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateRect(message);
|
||||
|
||||
if (!isRectVisible()) {
|
||||
finishActionMode();
|
||||
} else {
|
||||
startActionMode(TextAction.fromEventMessage(message));
|
||||
}
|
||||
} else if ("TextSelection:ActionbarUninit".equals(event)) {
|
||||
finishActionMode();
|
||||
} else if ("TextSelection:Update".equals(event)) {
|
||||
startActionMode(TextAction.fromEventMessage(message));
|
||||
} else if ("TextSelection:Visibility".equals(event)) {
|
||||
finishActionMode();
|
||||
}
|
||||
}
|
||||
|
||||
private void startActionMode(List<TextAction> actions) {
|
||||
if (actionMode != null) {
|
||||
actionModeCallback.updateActions(actions);
|
||||
actionMode.invalidate();
|
||||
return;
|
||||
}
|
||||
|
||||
actionModeCallback = new FloatingActionModeCallback(this, actions);
|
||||
actionMode = activity.startActionMode(actionModeCallback, ActionMode.TYPE_FLOATING);
|
||||
}
|
||||
|
||||
private boolean finishActionMode() {
|
||||
if (actionMode != null) {
|
||||
actionMode.finish();
|
||||
actionMode = null;
|
||||
actionModeCallback = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the content rect is a point (left == right and top == bottom) then this means that the
|
||||
* content rect is not in the currently visible part.
|
||||
*/
|
||||
private boolean isRectVisible() {
|
||||
// There's another case of an empty rect where just left == right but not top == bottom.
|
||||
// That's the rect for a collapsed selection. While technically this rect isn't visible too
|
||||
// we are not interested in this case because we do not want to hide the toolbar.
|
||||
return contentRect.left != contentRect.right || contentRect.top != contentRect.bottom;
|
||||
}
|
||||
|
||||
private void updateRect(JSONObject message) {
|
||||
try {
|
||||
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 zoomFactor = layerView.getZoomFactor();
|
||||
layerView.getLocationInWindow(locationInWindow);
|
||||
|
||||
contentRect = new Rect(
|
||||
(int) (x * zoomFactor + locationInWindow[0]),
|
||||
(int) (y * zoomFactor + locationInWindow[1]),
|
||||
(int) ((x + width) * zoomFactor + locationInWindow[0]),
|
||||
(int) ((y + height) * zoomFactor + locationInWindow[1] +
|
||||
(height > 0 ? handlesOffset : 0)));
|
||||
} catch (JSONException e) {
|
||||
Log.w(LOGTAG, "Could not calculate content rect", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
/* 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 android.util.Log;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Text selection action like "copy", "paste", ..
|
||||
*/
|
||||
public class TextAction {
|
||||
private static final String LOGTAG = "GeckoTextAction";
|
||||
|
||||
private String id;
|
||||
private String label;
|
||||
private int order;
|
||||
private int floatingOrder;
|
||||
|
||||
private TextAction() {}
|
||||
|
||||
public static List<TextAction> fromEventMessage(JSONObject message) {
|
||||
final List<TextAction> actions = new ArrayList<>();
|
||||
|
||||
try {
|
||||
final JSONArray array = message.getJSONArray("actions");
|
||||
|
||||
for (int i = 0; i < array.length(); i++) {
|
||||
final JSONObject object = array.getJSONObject(i);
|
||||
|
||||
final TextAction action = new TextAction();
|
||||
action.id = object.getString("id");
|
||||
action.label = object.getString("label");
|
||||
action.order = object.getInt("order");
|
||||
action.floatingOrder = object.optInt("floatingOrder", i);
|
||||
|
||||
actions.add(action);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
Log.w(LOGTAG, "Could not parse text actions", e);
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return order;
|
||||
}
|
||||
|
||||
public int getFloatingOrder() {
|
||||
return floatingOrder;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
/* 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;
|
||||
|
||||
public interface TextSelection {
|
||||
void create();
|
||||
|
||||
boolean dismiss();
|
||||
|
||||
void destroy();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue