Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8df41524 authored by Abodunrinwa Toki's avatar Abodunrinwa Toki Committed by Android (Google) Code Review
Browse files

Merge "Introduce Translate intent."

parents 95e76cb4 4bad09cd
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -10133,6 +10133,7 @@ package android.content {
    field public static final java.lang.String ACTION_TIMEZONE_CHANGED = "android.intent.action.TIMEZONE_CHANGED";
    field public static final java.lang.String ACTION_TIME_CHANGED = "android.intent.action.TIME_SET";
    field public static final java.lang.String ACTION_TIME_TICK = "android.intent.action.TIME_TICK";
    field public static final java.lang.String ACTION_TRANSLATE = "android.intent.action.TRANSLATE";
    field public static final java.lang.String ACTION_UID_REMOVED = "android.intent.action.UID_REMOVED";
    field public static final deprecated java.lang.String ACTION_UMS_CONNECTED = "android.intent.action.UMS_CONNECTED";
    field public static final deprecated java.lang.String ACTION_UMS_DISCONNECTED = "android.intent.action.UMS_DISCONNECTED";
+11 −0
Original line number Diff line number Diff line
@@ -3589,6 +3589,17 @@ public class Intent implements Parcelable, Cloneable {
    public static final String
            ACTION_OPEN_DOCUMENT_TREE = "android.intent.action.OPEN_DOCUMENT_TREE";


    /**
     * Activity Action: Perform text translation.
     * <p>
     * Input: {@link #EXTRA_TEXT getCharSequence(EXTRA_TEXT)} is the text to translate.
     * <p>
     * Output: nothing.
     */
    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
    public static final String ACTION_TRANSLATE = "android.intent.action.TRANSLATE";

    /**
     * Broadcast Action: List of dynamic sensor is changed due to new sensor being connected or
     * exisiting sensor being disconnected.
+99 −31
Original line number Diff line number Diff line
@@ -58,7 +58,6 @@ import java.net.URLEncoder;
import java.time.Instant;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
@@ -523,10 +522,10 @@ public final class TextClassifierImpl implements TextClassifier {
        final TextClassification.Builder builder = new TextClassification.Builder()
                .setText(classifiedText);

        final int size = classifications.length;
        final int typeCount = classifications.length;
        AnnotatorModel.ClassificationResult highestScoringResult =
                size > 0 ? classifications[0] : null;
        for (int i = 0; i < size; i++) {
                typeCount > 0 ? classifications[0] : null;
        for (int i = 0; i < typeCount; i++) {
            builder.setEntityType(classifications[i].getCollection(),
                                  classifications[i].getScore());
            if (classifications[i].getScore() > highestScoringResult.getScore()) {
@@ -534,9 +533,12 @@ public final class TextClassifierImpl implements TextClassifier {
            }
        }

        // TODO: Make this configurable.
        final float foreignTextThreshold = typeCount == 0 ? 0.5f : 0.7f;
        boolean isPrimaryAction = true;
        for (LabeledIntent labeledIntent : IntentFactory.create(
                mContext, classifiedText, referenceTime, highestScoringResult)) {
                mContext, classifiedText, isForeignText(classifiedText, foreignTextThreshold),
                referenceTime, highestScoringResult)) {
            final RemoteAction action = labeledIntent.asRemoteAction(mContext);
            if (action == null) {
                continue;
@@ -558,6 +560,42 @@ public final class TextClassifierImpl implements TextClassifier {
        return builder.setId(createId(text, start, end)).build();
    }

    private boolean isForeignText(String text, float threshold) {
        // TODO: Revisit this algorithm.
        try {
            final LangIdModel.LanguageResult[] langResults = getLangIdImpl().detectLanguages(text);
            if (langResults.length <= 0) {
                return false;
            }

            LangIdModel.LanguageResult highestScoringResult = langResults[0];
            for (int i = 1; i < langResults.length; i++) {
                if (langResults[i].getScore() > highestScoringResult.getScore()) {
                    highestScoringResult = langResults[i];
                }
            }
            if (highestScoringResult.getScore() < threshold) {
                return false;
            }
            // TODO: Remove
            Log.d(LOG_TAG, String.format("Language detected: <%s:%s>",
                    highestScoringResult.getLanguage(), highestScoringResult.getScore()));

            final Locale detected = new Locale(highestScoringResult.getLanguage());
            final LocaleList deviceLocales = LocaleList.getDefault();
            final int size = deviceLocales.size();
            for (int i = 0; i < size; i++) {
                if (deviceLocales.get(i).getLanguage().equals(detected.getLanguage())) {
                    return false;
                }
            }
            return true;
        } catch (Throwable t) {
            Log.e(LOG_TAG, "Error detecting foreign text. Ignored.", t);
        }
        return false;
    }

    @Override
    public void dump(@NonNull IndentingPrintWriter printWriter) {
        synchronized (mLock) {
@@ -698,53 +736,67 @@ public final class TextClassifierImpl implements TextClassifier {
        public static List<LabeledIntent> create(
                Context context,
                String text,
                boolean foreignText,
                @Nullable Instant referenceTime,
                @Nullable AnnotatorModel.ClassificationResult classification) {
            final String type = classification != null
                    ? classification.getCollection().trim().toLowerCase(Locale.ENGLISH)
                    : null;
                    : "";
            text = text.trim();
            final List<LabeledIntent> actions;
            switch (type) {
                case TextClassifier.TYPE_EMAIL:
                    return createForEmail(context, text);
                    actions = createForEmail(context, text);
                    break;
                case TextClassifier.TYPE_PHONE:
                    return createForPhone(context, text);
                    actions = createForPhone(context, text);
                    break;
                case TextClassifier.TYPE_ADDRESS:
                    return createForAddress(context, text);
                    actions = createForAddress(context, text);
                    break;
                case TextClassifier.TYPE_URL:
                    return createForUrl(context, text);
                case TextClassifier.TYPE_DATE:
                    actions = createForUrl(context, text);
                    break;
                case TextClassifier.TYPE_DATE:  // fall through
                case TextClassifier.TYPE_DATE_TIME:
                    if (classification.getDatetimeResult() != null) {
                        final Instant parsedTime = Instant.ofEpochMilli(
                                classification.getDatetimeResult().getTimeMsUtc());
                        return createForDatetime(context, type, referenceTime, parsedTime);
                        actions = createForDatetime(context, type, referenceTime, parsedTime);
                    } else {
                        return new ArrayList<>();
                        actions = new ArrayList<>();
                    }
                    break;
                case TextClassifier.TYPE_FLIGHT_NUMBER:
                    return createForFlight(context, text);
                    actions = createForFlight(context, text);
                    break;
                default:
                    return new ArrayList<>();
                    actions = new ArrayList<>();
                    break;
            }
            if (foreignText) {
                insertTranslateAction(actions, context, text);
            }
            return actions;
        }

        @NonNull
        private static List<LabeledIntent> createForEmail(Context context, String text) {
            return Arrays.asList(
                    new LabeledIntent(
            final List<LabeledIntent> actions = new ArrayList<>();
            actions.add(new LabeledIntent(
                    context.getString(com.android.internal.R.string.email),
                    context.getString(com.android.internal.R.string.email_desc),
                    new Intent(Intent.ACTION_SENDTO)
                            .setData(Uri.parse(String.format("mailto:%s", text))),
                            LabeledIntent.DEFAULT_REQUEST_CODE),
                    new LabeledIntent(
                    LabeledIntent.DEFAULT_REQUEST_CODE));
            actions.add(new LabeledIntent(
                    context.getString(com.android.internal.R.string.add_contact),
                    context.getString(com.android.internal.R.string.add_contact_desc),
                    new Intent(Intent.ACTION_INSERT_OR_EDIT)
                            .setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE)
                            .putExtra(ContactsContract.Intents.Insert.EMAIL, text),
                    text.hashCode()));
            return actions;
        }

        @NonNull
@@ -801,12 +853,14 @@ public final class TextClassifierImpl implements TextClassifier {
            if (Uri.parse(text).getScheme() == null) {
                text = "http://" + text;
            }
            return Arrays.asList(new LabeledIntent(
            final List<LabeledIntent> actions = new ArrayList<>();
            actions.add(new LabeledIntent(
                    context.getString(com.android.internal.R.string.browse),
                    context.getString(com.android.internal.R.string.browse_desc),
                    new Intent(Intent.ACTION_VIEW, Uri.parse(text))
                            .putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()),
                    LabeledIntent.DEFAULT_REQUEST_CODE));
            return actions;
        }

        @NonNull
@@ -828,12 +882,14 @@ public final class TextClassifierImpl implements TextClassifier {

        @NonNull
        private static List<LabeledIntent> createForFlight(Context context, String text) {
            return Arrays.asList(new LabeledIntent(
            final List<LabeledIntent> actions = new ArrayList<>();
            actions.add(new LabeledIntent(
                    context.getString(com.android.internal.R.string.view_flight),
                    context.getString(com.android.internal.R.string.view_flight_desc),
                    new Intent(Intent.ACTION_WEB_SEARCH)
                            .putExtra(SearchManager.QUERY, text),
                    text.hashCode()));
            return actions;
        }

        @NonNull
@@ -864,5 +920,17 @@ public final class TextClassifierImpl implements TextClassifier {
                                    parsedTime.toEpochMilli() + DEFAULT_EVENT_DURATION),
                    parsedTime.hashCode());
        }

        private static void insertTranslateAction(
                List<LabeledIntent> actions, Context context, String text) {
            actions.add(new LabeledIntent(
                    context.getString(com.android.internal.R.string.translate),
                    context.getString(com.android.internal.R.string.translate_desc),
                    new Intent(Intent.ACTION_TRANSLATE)
                            // TODO: Probably better to introduce a "translate" scheme instead of
                            // using EXTRA_TEXT.
                            .putExtra(Intent.EXTRA_TEXT, text),
                    text.hashCode()));
        }
    }
}
+6 −0
Original line number Diff line number Diff line
@@ -2989,6 +2989,12 @@
    <!-- Accessibility description for an item in the text selection menu to track a flight [CHAR LIMIT=NONE] -->
    <string name="view_flight_desc">Track selected flight</string>

    <!-- Label for item in the text selection menu to translate selected text with a translation app. Should be a verb. [CHAR LIMIT=30] -->
    <string name="translate">Translate</string>

    <!-- Accessibility description for an item in the text selection menu to translate selected text with a translation app. [CHAR LIMIT=NONE] -->
    <string name="translate_desc">Translate selected text</string>

    <!-- If the device is getting low on internal storage, a notification is shown to the user.  This is the title of that notification. -->
    <string name="low_internal_storage_view_title">Storage space running out</string>
    <!-- If the device is getting low on internal storage, a notification is shown to the user.  This is the message of that notification. -->
+2 −0
Original line number Diff line number Diff line
@@ -574,6 +574,8 @@
  <java-symbol type="string" name="add_calendar_event_desc" />
  <java-symbol type="string" name="view_flight" />
  <java-symbol type="string" name="view_flight_desc" />
  <java-symbol type="string" name="translate" />
  <java-symbol type="string" name="translate_desc" />
  <java-symbol type="string" name="textSelectionCABTitle" />
  <java-symbol type="string" name="BaMmi" />
  <java-symbol type="string" name="CLIRDefaultOffNextCallOff" />