Skip to content

Commit

Permalink
feat: add HyperOS AI in editor and text selection
Browse files Browse the repository at this point in the history
Signed-off-by: Next Alone <[email protected]>
  • Loading branch information
NextAlone committed Nov 4, 2024
1 parent 79c2ce9 commit bef68a9
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,11 @@
import org.telegram.ui.Components.RecyclerListView;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import xyz.nextalone.gen.Config;
import xyz.nextalone.nnngram.helpers.HyperOsHelper;
import xyz.nextalone.nnngram.helpers.TranslateHelper;

public abstract class TextSelectionHelper<Cell extends TextSelectionHelper.SelectableView> {
Expand Down Expand Up @@ -1420,34 +1423,55 @@ public void invalidate() {

private static final int TRANSLATE = 3;
private static final int BLOCK = 4;
private static final Map<Integer, Integer> menus = new HashMap<>();
private int getMenuIndex(int id, int defaultIndex) {
if (menus.containsKey(id)) {
Integer index = menus.get(id);
if (index != null) {
return index;
}
}
return defaultIndex;
}

private ActionMode.Callback createActionCallback() {
final ActionMode.Callback callback = new ActionMode.Callback() {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
menu.removeItem(R.id.hyperos_ai);
menu.add(Menu.NONE, android.R.id.copy, 0, android.R.string.copy);
menu.add(Menu.NONE, R.id.menu_quote, 1, LocaleController.getString(R.string.Quote));
menu.add(Menu.NONE, android.R.id.selectAll, 2, android.R.string.selectAll);
menu.add(Menu.NONE, TRANSLATE, 3, LocaleController.getString(R.string.TranslateMessage));
menu.add(Menu.NONE, BLOCK, 4, LocaleController.getString(R.string.block));
menus.clear();
int index = 0;
if (HyperOsHelper.INSTANCE.isHyperAiAvailable(textSelectionOverlay.getContext())) {
menus.put(R.id.hyperos_ai, index);
menu.add(Menu.NONE, R.id.hyperos_ai, index++, "AI");
}
menus.put(android.R.id.copy, index);
menu.add(Menu.NONE, android.R.id.copy, index++, android.R.string.copy);
menus.put(R.id.menu_quote, index);
menu.add(Menu.NONE, R.id.menu_quote, index++, LocaleController.getString(R.string.Quote));
menus.put(android.R.id.selectAll, index);
menu.add(Menu.NONE, android.R.id.selectAll, index++, android.R.string.selectAll);
menus.put(TRANSLATE, index);
menu.add(Menu.NONE, TRANSLATE, index++, LocaleController.getString(R.string.TranslateMessage));
menus.put(BLOCK, index);
menu.add(Menu.NONE, BLOCK, index, LocaleController.getString(R.string.block));
return true;
}

@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
menu.getItem(1).setVisible(canShowQuote());
menu.getItem(getMenuIndex(R.id.menu_quote, 0)).setVisible(canShowQuote());
MenuItem copyItem = menu.findItem(android.R.id.copy);
if (copyItem != null) {
copyItem.setVisible(canCopy());
}
if (selectedView != null) {
CharSequence charSequence = getText(selectedView, false);
if (!canCopy()) {
menu.getItem(2).setVisible(false);
menu.getItem(getMenuIndex(android.R.id.selectAll, 2)).setVisible(false);
} else if (multiselect || selectionStart <= 0 && selectionEnd >= charSequence.length() - 1) {
menu.getItem(2).setVisible(false);
menu.getItem(getMenuIndex(android.R.id.selectAll, 2)).setVisible(false);
} else {
menu.getItem(2).setVisible(true);
menu.getItem(getMenuIndex(android.R.id.selectAll, 2)).setVisible(true);
}
}
if (onTranslateListener != null && LanguageDetector.hasSupport() && getSelectedText() != null) {
Expand All @@ -1469,7 +1493,7 @@ public boolean onPrepareActionMode(ActionMode mode, Menu menu) {

private String translateFromLanguage = null;
private void updateTranslateButton(Menu menu) {
menu.getItem(3).setVisible(!LanguageDetector.hasSupport() || translateFromLanguage == null || !TranslateHelper.isLanguageRestricted(translateFromLanguage));
menu.getItem(getMenuIndex(TRANSLATE, 3)).setVisible(!LanguageDetector.hasSupport() || translateFromLanguage == null || !TranslateHelper.isLanguageRestricted(translateFromLanguage));
}

@Override
Expand Down Expand Up @@ -1517,6 +1541,15 @@ public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
hideActions();
clear(true);
return true;
} else if (itemId == R.id.hyperos_ai) {
CharSequence str = getSelectedText();
if (str == null) {
return true;
}
HyperOsHelper.INSTANCE.startHyperOsAiService(textSelectionOverlay, str.toString());
hideActions();
clear(true);
return true;
} else {
clear();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,12 @@
package org.telegram.ui.Components;

import static org.telegram.messenger.AndroidUtilities.dp;
import static org.telegram.messenger.AndroidUtilities.getSystemProperty;

import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
Expand Down Expand Up @@ -87,7 +81,7 @@
import java.util.List;

import xyz.nextalone.gen.Config;
import xyz.nextalone.nnngram.utils.Log;
import xyz.nextalone.nnngram.helpers.HyperOsHelper;

public class EditTextBoldCursor extends EditTextEffects {

Expand Down Expand Up @@ -190,9 +184,6 @@ public void run() {
public static boolean disableMarkdown = Config.markdownDisabled;
private boolean showDisableMarkdown = false;

public static boolean IS_HYPEROS = getSystemProperty("ro.mi.os.version.name") != null;
private static final String HYPEROS_NOTES_PKG = "com.miui.notes";
private static final String HYPEROS_AI_SERVICE = "com.miui.notes.ai.AiTextWidgetService";
static {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
Expand Down Expand Up @@ -1256,24 +1247,7 @@ private void addUndoRedo(Menu menu) {

private void addHyperOsAi(Menu menu) {
// Check if is HyperOS
if (!IS_HYPEROS || !Config.enableXiaomiHyperAi) {
return;
}

PackageManager packageManager = getContext().getPackageManager();
if (packageManager == null) {
return;
}

try {
// Retrieve package information for HyperOS Notes
PackageInfo packageInfo = packageManager.getPackageInfo(HYPEROS_NOTES_PKG, 0);

if (packageInfo.versionCode < 1100) {
return;
}
} catch (PackageManager.NameNotFoundException e) {
// Package not found, exit gracefully
if (!HyperOsHelper.INSTANCE.isHyperAiAvailable(getContext())) {
return;
}

Expand All @@ -1292,67 +1266,12 @@ public boolean onTextContextMenuItem(int id) {
floatingActionMode.finish();
return true;
} else if (id == R.id.hyperos_ai) {
startHyperOsAiService();
HyperOsHelper.INSTANCE.startHyperOsAiService(this);
return true;
}
return super.onTextContextMenuItem(id);
}

private void startHyperOsAiService() {
try {
String currentPackage = getContext().getPackageName();
Intent serviceIntent = new Intent();

// Pass the package name
serviceIntent.putExtra("packageName", currentPackage);

// Handle selection logic
String selectedText = "";
if (hasSelection()) {
int selectionStart = getSelectionStart();
int selectionEnd = getSelectionEnd();
if (selectionStart != selectionEnd) {
selectedText = getText().subSequence(selectionStart, selectionEnd).toString();
}
}
serviceIntent.putExtra("selectedText", selectedText);

// Store original view bounds
serviceIntent.putExtra("originalViewLeft", getLeft());
serviceIntent.putExtra("originalViewTop", getTop());
serviceIntent.putExtra("originalViewRight", getRight());
serviceIntent.putExtra("originalViewBottom", getBottom());
serviceIntent.putExtra("originalViewName", getClass().getName());
serviceIntent.putExtra("isEditor", true);

// Get the active screen location
int[] screenCoordinates = new int[2];
Rect focusedRect = new Rect();
getLocationOnScreen(screenCoordinates);
getFocusedRect(focusedRect);
focusedRect.offset(screenCoordinates[0], screenCoordinates[1]);

Activity currentActivity = (Activity) getContext();
if (currentActivity != null) {
Rect windowFrame = new Rect();
currentActivity.getWindow().getDecorView().getWindowVisibleDisplayFrame(windowFrame);

// Putting the visible window bounds into the Intent
serviceIntent.putExtra("left", windowFrame.left);
serviceIntent.putExtra("top", windowFrame.top);
serviceIntent.putExtra("right", windowFrame.right);
serviceIntent.putExtra("bottom", windowFrame.bottom);
serviceIntent.putExtra("taskId", currentActivity.getTaskId());
}

// Prepare and start the service
serviceIntent.setComponent(new ComponentName(HYPEROS_NOTES_PKG, HYPEROS_AI_SERVICE));
getContext().startForegroundService(serviceIntent);
} catch (Exception e) {
Log.e("Failed to start HyperOS AI service", e);
}
}

private boolean shouldShowQuoteButton() {
if (!hasSelection() || getSelectionStart() < 0 || getSelectionEnd() < 0 || getSelectionStart() == getSelectionEnd()) {
return false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package xyz.nextalone.nnngram.helpers

import android.app.Activity
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Rect
import android.view.View
import android.widget.EditText
import org.telegram.messenger.AndroidUtilities
import xyz.nextalone.gen.Config
import xyz.nextalone.nnngram.utils.Log.e

object HyperOsHelper {
private var IS_HYPEROS: Boolean =
AndroidUtilities.getSystemProperty("ro.mi.os.version.name") != null
private const val HYPEROS_NOTES_PKG: String = "com.miui.notes"
private const val HYPEROS_AI_SERVICE: String = "com.miui.notes.ai.AiTextWidgetService"


fun isHyperAiAvailable(context: Context): Boolean {
// Check if is HyperOS
if (!IS_HYPEROS || !Config.enableXiaomiHyperAi) {
return false
}

val packageManager: PackageManager = context.packageManager ?: return false

try {
// Retrieve package information for HyperOS Notes
val packageInfo = packageManager.getPackageInfo(HYPEROS_NOTES_PKG, 0)

if (packageInfo.versionCode < 1100) {
return false
}
} catch (e: PackageManager.NameNotFoundException) {
// Package not found, exit gracefully
return false
}
return true
}

@JvmOverloads
fun startHyperOsAiService(view: View, text: String = "") {
try {
val currentPackage: String = view.context.packageName
val serviceIntent = Intent()

// Pass the package name
serviceIntent.putExtra("packageName", currentPackage)

// Handle selection logic
var selectedText = ""
if (view is EditText) {
if (view.hasSelection()) {
val selectionStart: Int = view.selectionStart
val selectionEnd: Int = view.selectionEnd
if (selectionStart != selectionEnd) {
selectedText =
view.getText().subSequence(selectionStart, selectionEnd).toString()
}
}
} else {
selectedText = text
}
serviceIntent.putExtra("selectedText", selectedText)

// Store original view bounds
serviceIntent.putExtra("originalViewLeft", view.left)
serviceIntent.putExtra("originalViewTop", view.top)
serviceIntent.putExtra("originalViewRight", view.right)
serviceIntent.putExtra("originalViewBottom", view.bottom)
serviceIntent.putExtra("originalViewName", javaClass.name)
serviceIntent.putExtra("isEditor", true)

// Get the active screen location
val screenCoordinates = IntArray(2)
val focusedRect = Rect()
view.getLocationOnScreen(screenCoordinates)
view.getFocusedRect(focusedRect)
focusedRect.offset(screenCoordinates[0], screenCoordinates[1])

val currentActivity = view.context as Activity?
if (currentActivity != null) {
val windowFrame = Rect()
currentActivity.window.decorView.getWindowVisibleDisplayFrame(windowFrame)

// Putting the visible window bounds into the Intent
serviceIntent.putExtra("left", windowFrame.left)
serviceIntent.putExtra("top", windowFrame.top)
serviceIntent.putExtra("right", windowFrame.right)
serviceIntent.putExtra("bottom", windowFrame.bottom)
serviceIntent.putExtra("taskId", currentActivity.taskId)
}

// Prepare and start the service
serviceIntent.setComponent(
ComponentName(
HYPEROS_NOTES_PKG,
HYPEROS_AI_SERVICE
)
)
view.context.startForegroundService(serviceIntent)
} catch (e: Exception) {
e("Failed to start HyperOS AI service", e)
}
}
}

0 comments on commit bef68a9

Please sign in to comment.