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

Commit 8f2bf3cb authored by Abodunrinwa Toki's avatar Abodunrinwa Toki
Browse files

Rewrite Icons from the TCS.

Because of the new app visibility constraints introduced in Android R,
apps may be unable to load icons from the TextClassifierService (TCS).
This is because the TCS returns "Icons" based on resources to the apps.
These resources were globally available until this new restriction.

In this CL, the TCMS rewrites responses with Icon(typ=RESOURCE) coming
from a TCS to responses with Icon(typ=URI). The new icons are backed
by a content provider that may be used to retrieve the necessary icons.

Bug: 151847511
Test: atest tests/tests/textclassifier/src/android/view/textclassifier/cts
Test: atest core/tests/coretests/src/android/view/textclassifier
Test: Select a phone number text, check that the "Call" icon shows
Change-Id: Ib63e54462508029cdf0e56c2c6a82ff4e81b02a8
parent 8862ee38
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -424,6 +424,11 @@ public abstract class TextClassifierService extends Service {
        return bundle.getParcelable(KEY_RESULT);
    }

    /** @hide **/
    public static <T extends Parcelable> void putResponse(Bundle bundle, T response) {
        bundle.putParcelable(KEY_RESULT, response);
    }

    /**
     * Callbacks for TextClassifierService results.
     *
+9 −0
Original line number Diff line number Diff line
@@ -206,6 +206,15 @@ public final class ConversationAction implements Parcelable {
        return mExtras;
    }

    /** @hide */
    public Builder toBuilder() {
        return new Builder(mType)
            .setTextReply(mTextReply)
            .setAction(mAction)
            .setConfidenceScore(mScore)
            .setExtras(mExtras);
    }

    /** Builder class to construct {@link ConversationAction}. */
    public static final class Builder {
        @Nullable
+4 −0
Original line number Diff line number Diff line
@@ -88,6 +88,10 @@ final class EntityConfidence implements Parcelable {
        return 0;
    }

    public Map<String, Float> toMap() {
        return new ArrayMap(mEntityConfidence);
    }

    @Override
    public String toString() {
        return mEntityConfidence.toString();
+41 −24
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
@@ -270,6 +271,20 @@ public final class TextClassification implements Parcelable {
        return mExtras;
    }

    /** @hide */
    public Builder toBuilder() {
        return new Builder()
                .setId(mId)
                .setText(mText)
                .addActions(mActions)
                .setEntityConfidence(mEntityConfidence)
                .setIcon(mLegacyIcon)
                .setLabel(mLegacyLabel)
                .setIntent(mLegacyIntent)
                .setOnClickListener(mLegacyOnClickListener)
                .setExtras(mExtras);
    }

    @Override
    public String toString() {
        return String.format(Locale.US,
@@ -323,7 +338,7 @@ public final class TextClassification implements Parcelable {
     */
    public static final class Builder {

        @NonNull private List<RemoteAction> mActions = new ArrayList<>();
        @NonNull private final List<RemoteAction> mActions = new ArrayList<>();
        @NonNull private final Map<String, Float> mTypeScoreMap = new ArrayMap<>();
        @Nullable private String mText;
        @Nullable private Drawable mLegacyIcon;
@@ -332,8 +347,6 @@ public final class TextClassification implements Parcelable {
        @Nullable private OnClickListener mLegacyOnClickListener;
        @Nullable private String mId;
        @Nullable private Bundle mExtras;
        @NonNull private final ArrayList<Intent> mActionIntents = new ArrayList<>();
        @Nullable private Bundle mForeignLanguageExtra;

        /**
         * Sets the classified text.
@@ -361,6 +374,18 @@ public final class TextClassification implements Parcelable {
            return this;
        }

        Builder setEntityConfidence(EntityConfidence scores) {
            mTypeScoreMap.clear();
            mTypeScoreMap.putAll(scores.toMap());
            return this;
        }

        /** @hide */
        public Builder clearEntityTypes() {
            mTypeScoreMap.clear();
            return this;
        }

        /**
         * Adds an action that may be performed on the classified text. Actions should be added in
         * order of likelihood that the user will use them, with the most likely action being added
@@ -368,19 +393,21 @@ public final class TextClassification implements Parcelable {
         */
        @NonNull
        public Builder addAction(@NonNull RemoteAction action) {
            return addAction(action, null);
        }

        /**
         * @param intent the intent in the remote action.
         * @see #addAction(RemoteAction)
         * @hide
         */
        @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
        public Builder addAction(RemoteAction action, @Nullable Intent intent) {
            Preconditions.checkArgument(action != null);
            mActions.add(action);
            mActionIntents.add(intent);
            return this;
        }

        /** @hide */
        public Builder addActions(Collection<RemoteAction> actions) {
            Objects.requireNonNull(actions);
            mActions.addAll(actions);
            return this;
        }

        /** @hide */
        public Builder clearActions() {
            mActions.clear();
            return this;
        }

@@ -465,16 +492,6 @@ public final class TextClassification implements Parcelable {
            return this;
        }

        /**
         * @see #setExtras(Bundle)
         * @hide
         */
        @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
        public Builder setForeignLanguageExtra(@Nullable Bundle extra) {
            mForeignLanguageExtra = extra;
            return this;
        }

        /**
         * Builds and returns a {@link TextClassification} object.
         */
+73 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.view.textclassifier;

import static com.google.common.truth.Truth.assertThat;

import android.app.PendingIntent;
import android.app.RemoteAction;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Icon;
import android.os.Bundle;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

@SmallTest
@RunWith(AndroidJUnit4.class)
public final class ConversationActionTest {

    @Test
    public void toBuilder() {
        final Context context = InstrumentationRegistry.getTargetContext();
        final PendingIntent intent = PendingIntent.getActivity(context, 0, new Intent(), 0);
        final Icon icon = Icon.createWithData(new byte[]{0}, 0, 1);
        final Bundle extras = new Bundle();
        extras.putInt("key", 5);
        final ConversationAction convAction =
                new ConversationAction.Builder(ConversationAction.TYPE_CALL_PHONE)
                        .setAction(new RemoteAction(icon, "title", "descr", intent))
                        .setConfidenceScore(0.5f)
                        .setExtras(extras)
                        .build();

        final ConversationAction fromBuilder = convAction.toBuilder().build();

        assertThat(fromBuilder.getType()).isEqualTo(convAction.getType());
        assertThat(fromBuilder.getAction()).isEqualTo(convAction.getAction());
        assertThat(fromBuilder.getConfidenceScore()).isEqualTo(convAction.getConfidenceScore());
        assertThat(fromBuilder.getExtras()).isEqualTo(convAction.getExtras());
        assertThat(fromBuilder.getTextReply()).isEqualTo(convAction.getTextReply());
    }

    @Test
    public void toBuilder_textReply() {
        final ConversationAction convAction =
                new ConversationAction.Builder(ConversationAction.TYPE_TEXT_REPLY)
                        .setTextReply(":P")
                        .build();

        final ConversationAction fromBuilder = convAction.toBuilder().build();

        assertThat(fromBuilder.getTextReply()).isEqualTo(convAction.getTextReply());
    }
}
Loading