Loading core/java/android/service/notification/NotificationAssistantService.java +8 −5 Original line number Diff line number Diff line Loading @@ -19,7 +19,7 @@ package android.service.notification; import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; import android.annotation.Nullable; import android.annotation.NonNull; import android.annotation.SdkConstant; import android.annotation.SystemApi; import android.annotation.TestApi; Loading Loading @@ -179,13 +179,13 @@ public abstract class NotificationAssistantService extends NotificationListenerS * @param isExpanded whether the notification is expanded. */ public void onNotificationExpansionChanged( String key, boolean isUserAction, boolean isExpanded) {} @NonNull String key, boolean isUserAction, boolean isExpanded) {} /** * Implement this to know when a direct reply is sent from a notification. * @param key the notification key */ public void onNotificationDirectReply(String key) {} public void onNotificationDirectReply(@NonNull String key) {} /** * Implement this to know when a suggested reply is sent. Loading @@ -193,7 +193,9 @@ public abstract class NotificationAssistantService extends NotificationListenerS * @param reply the reply that is just sent * @param source the source that provided the reply, e.g. SOURCE_FROM_APP */ public void onSuggestedReplySent(String key, CharSequence reply, @Source int source) {} public void onSuggestedReplySent(@NonNull String key, @NonNull CharSequence reply, @Source int source) { } /** * Implement this to know when an action is clicked. Loading @@ -201,7 +203,8 @@ public abstract class NotificationAssistantService extends NotificationListenerS * @param action the action that is just clicked * @param source the source that provided the action, e.g. SOURCE_FROM_APP */ public void onActionClicked(String key, @Nullable Notification.Action action, int source) { public void onActionClicked(@NonNull String key, @NonNull Notification.Action action, @Source int source) { } /** Loading core/java/android/view/textclassifier/ActionsSuggestionsHelper.java +27 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.view.textclassifier; import android.app.Person; import android.content.Context; import android.text.TextUtils; import android.util.ArrayMap; Loading @@ -28,7 +29,10 @@ import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.StringJoiner; import java.util.function.Function; import java.util.stream.Collectors; Loading Loading @@ -84,6 +88,29 @@ public final class ActionsSuggestionsHelper { new ActionsSuggestionsModel.ConversationMessage[nativeMessages.size()]); } /** * Returns the result id for logging. */ public static String createResultId( Context context, List<ConversationActions.Message> messages, int modelVersion, List<Locale> modelLocales) { final StringJoiner localesJoiner = new StringJoiner(","); for (Locale locale : modelLocales) { localesJoiner.add(locale.toLanguageTag()); } final String modelName = String.format( Locale.US, "%s_v%d", localesJoiner.toString(), modelVersion); final int hash = Objects.hash( messages.stream() .map(ConversationActions.Message::getText) .collect(Collectors.toList()), context.getPackageName()); return SelectionSessionLogger.SignatureParser.createSignature( SelectionSessionLogger.CLASSIFIER_ID, modelName, hash); } private static final class PersonEncoder { private final Map<Person, Integer> mMapping = new ArrayMap<>(); private int mNextUserId = FIRST_NON_LOCAL_USER; Loading core/java/android/view/textclassifier/TextClassifierEvent.java +22 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; /** * A text classifier event. Loading Loading @@ -498,4 +499,25 @@ public final class TextClassifierEvent implements Parcelable { } // TODO: Add build(boolean validate). } @Override public String toString() { StringBuilder out = new StringBuilder(128); out.append("TextClassifierEvent{"); out.append("mEventCategory=").append(mEventCategory); out.append(", mEventType=").append(mEventType); out.append(", mEventContext=").append(mEventContext); out.append(", mResultId=").append(mResultId); out.append(", mEventIndex=").append(mEventIndex); out.append(", mEventTime=").append(mEventTime); out.append(", mExtras=").append(mExtras); out.append(", mRelativeWordStartIndex=").append(mRelativeWordStartIndex); out.append(", mRelativeWordEndIndex=").append(mRelativeWordEndIndex); out.append(", mRelativeSuggestedWordStartIndex=").append(mRelativeSuggestedWordStartIndex); out.append(", mRelativeSuggestedWordEndIndex=").append(mRelativeSuggestedWordEndIndex); out.append(", mActionIndices=").append(Arrays.toString(mActionIndices)); out.append(", mLanguage=").append(mLanguage); out.append("}"); return out.toString(); } } core/java/android/view/textclassifier/TextClassifierImpl.java +15 −3 Original line number Diff line number Diff line Loading @@ -80,6 +80,8 @@ public final class TextClassifierImpl implements TextClassifier { private static final String LOG_TAG = DEFAULT_LOG_TAG; private static final boolean DEBUG = false; private static final File FACTORY_MODEL_DIR = new File("/etc/textclassifier/"); // Annotator private static final String ANNOTATOR_FACTORY_MODEL_FILENAME_REGEX = Loading Loading @@ -109,6 +111,8 @@ public final class TextClassifierImpl implements TextClassifier { @GuardedBy("mLock") // Do not access outside this lock. private LangIdModel mLangIdImpl; @GuardedBy("mLock") // Do not access outside this lock. private ModelFileManager.ModelFile mActionModelInUse; @GuardedBy("mLock") // Do not access outside this lock. private ActionsSuggestionsModel mActionsImpl; private final Object mLoggerLock = new Object(); Loading Loading @@ -342,8 +346,10 @@ public final class TextClassifierImpl implements TextClassifier { } @Override public void onTextClassifierEvent(@NonNull TextClassifierEvent event) { // TODO: Implement. public void onTextClassifierEvent(TextClassifierEvent event) { if (DEBUG) { Log.d(DEFAULT_LOG_TAG, "onTextClassifierEvent() called with: event = [" + event + "]"); } } /** @inheritDoc */ Loading Loading @@ -408,7 +414,12 @@ public final class TextClassifierImpl implements TextClassifier { .setConfidenceScore(nativeSuggestion.getScore()) .build()); } return new ConversationActions(conversationActions, /*id*/ null); String resultId = ActionsSuggestionsHelper.createResultId( mContext, request.getConversation(), mActionModelInUse.getVersion(), mActionModelInUse.getSupportedLocales()); return new ConversationActions(conversationActions, resultId); } catch (Throwable t) { // Avoid throwing from this method. Log the error. Log.e(LOG_TAG, "Error suggesting conversation actions.", t); Loading Loading @@ -517,6 +528,7 @@ public final class TextClassifierImpl implements TextClassifier { try { if (pfd != null) { mActionsImpl = new ActionsSuggestionsModel(pfd.getFd()); mActionModelInUse = bestModel; } } finally { maybeCloseAndLogError(pfd); Loading packages/ExtServices/src/android/ext/services/notification/Assistant.java +25 −14 Original line number Diff line number Diff line Loading @@ -117,7 +117,7 @@ public class Assistant extends NotificationAssistantService { mPackageManager = ActivityThread.getPackageManager(); mSettings = mSettingsFactory.createAndRegister(mHandler, getApplicationContext().getContentResolver(), getUserId(), this::updateThresholds); mSmartActionsHelper = new SmartActionsHelper(); mSmartActionsHelper = new SmartActionsHelper(getContext(), mSettings); mNotificationCategorizer = new NotificationCategorizer(); mAgingHelper = new AgingHelper(getContext(), mNotificationCategorizer, Loading Loading @@ -215,10 +215,8 @@ public class Assistant extends NotificationAssistantService { return null; } NotificationEntry entry = new NotificationEntry(mPackageManager, sbn, channel); ArrayList<Notification.Action> actions = mSmartActionsHelper.suggestActions(this, entry, mSettings); ArrayList<CharSequence> replies = mSmartActionsHelper.suggestReplies(this, entry, mSettings); ArrayList<Notification.Action> actions = mSmartActionsHelper.suggestActions(entry); ArrayList<CharSequence> replies = mSmartActionsHelper.suggestReplies(entry); return createEnqueuedNotificationAdjustment(entry, actions, replies); } Loading Loading @@ -343,6 +341,7 @@ public class Assistant extends NotificationAssistantService { if (entry != null) { entry.setSeen(); mAgingHelper.onNotificationSeen(entry); mSmartActionsHelper.onNotificationSeen(entry); } } } catch (Throwable e) { Loading @@ -351,34 +350,46 @@ public class Assistant extends NotificationAssistantService { } @Override public void onNotificationExpansionChanged(String key, boolean isUserAction, public void onNotificationExpansionChanged(@NonNull String key, boolean isUserAction, boolean isExpanded) { if (DEBUG) { Log.i(TAG, "onNotificationExpansionChanged " + key + ", isUserAction =" + isUserAction + ", isExpanded = isExpanded"); Log.d(TAG, "onNotificationExpansionChanged() called with: key = [" + key + "], isUserAction = [" + isUserAction + "], isExpanded = [" + isExpanded + "]"); } NotificationEntry entry = mLiveNotifications.get(key); if (entry != null) { entry.setExpanded(isExpanded); mSmartActionsHelper.onNotificationExpansionChanged(entry, isUserAction, isExpanded); } } @Override public void onNotificationDirectReply(String key) { public void onNotificationDirectReply(@NonNull String key) { if (DEBUG) Log.i(TAG, "onNotificationDirectReply " + key); mSmartActionsHelper.onNotificationDirectReply(key); } @Override public void onSuggestedReplySent(String key, CharSequence reply, int source) { public void onSuggestedReplySent(@NonNull String key, @NonNull CharSequence reply, @Source int source) { if (DEBUG) { Log.d(TAG, "onSuggestedReplySent() called with: key = [" + key + "], reply = [" + reply + "], source = [" + source + "]"); } mSmartActionsHelper.onSuggestedReplySent(key, reply, source); } @Override public void onActionClicked(String key, Notification.Action action, int source) { public void onActionClicked(@NonNull String key, @NonNull Notification.Action action, @Source int source) { if (DEBUG) { Log.d(TAG, "onActionClicked() called with: key = [" + key + "], action = [" + action.title Log.d(TAG, "onActionClicked() called with: key = [" + key + "], action = [" + action.title + "], source = [" + source + "]"); } mSmartActionsHelper.onActionClicked(key, action, source); } @Override Loading Loading
core/java/android/service/notification/NotificationAssistantService.java +8 −5 Original line number Diff line number Diff line Loading @@ -19,7 +19,7 @@ package android.service.notification; import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; import android.annotation.Nullable; import android.annotation.NonNull; import android.annotation.SdkConstant; import android.annotation.SystemApi; import android.annotation.TestApi; Loading Loading @@ -179,13 +179,13 @@ public abstract class NotificationAssistantService extends NotificationListenerS * @param isExpanded whether the notification is expanded. */ public void onNotificationExpansionChanged( String key, boolean isUserAction, boolean isExpanded) {} @NonNull String key, boolean isUserAction, boolean isExpanded) {} /** * Implement this to know when a direct reply is sent from a notification. * @param key the notification key */ public void onNotificationDirectReply(String key) {} public void onNotificationDirectReply(@NonNull String key) {} /** * Implement this to know when a suggested reply is sent. Loading @@ -193,7 +193,9 @@ public abstract class NotificationAssistantService extends NotificationListenerS * @param reply the reply that is just sent * @param source the source that provided the reply, e.g. SOURCE_FROM_APP */ public void onSuggestedReplySent(String key, CharSequence reply, @Source int source) {} public void onSuggestedReplySent(@NonNull String key, @NonNull CharSequence reply, @Source int source) { } /** * Implement this to know when an action is clicked. Loading @@ -201,7 +203,8 @@ public abstract class NotificationAssistantService extends NotificationListenerS * @param action the action that is just clicked * @param source the source that provided the action, e.g. SOURCE_FROM_APP */ public void onActionClicked(String key, @Nullable Notification.Action action, int source) { public void onActionClicked(@NonNull String key, @NonNull Notification.Action action, @Source int source) { } /** Loading
core/java/android/view/textclassifier/ActionsSuggestionsHelper.java +27 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.view.textclassifier; import android.app.Person; import android.content.Context; import android.text.TextUtils; import android.util.ArrayMap; Loading @@ -28,7 +29,10 @@ import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.StringJoiner; import java.util.function.Function; import java.util.stream.Collectors; Loading Loading @@ -84,6 +88,29 @@ public final class ActionsSuggestionsHelper { new ActionsSuggestionsModel.ConversationMessage[nativeMessages.size()]); } /** * Returns the result id for logging. */ public static String createResultId( Context context, List<ConversationActions.Message> messages, int modelVersion, List<Locale> modelLocales) { final StringJoiner localesJoiner = new StringJoiner(","); for (Locale locale : modelLocales) { localesJoiner.add(locale.toLanguageTag()); } final String modelName = String.format( Locale.US, "%s_v%d", localesJoiner.toString(), modelVersion); final int hash = Objects.hash( messages.stream() .map(ConversationActions.Message::getText) .collect(Collectors.toList()), context.getPackageName()); return SelectionSessionLogger.SignatureParser.createSignature( SelectionSessionLogger.CLASSIFIER_ID, modelName, hash); } private static final class PersonEncoder { private final Map<Person, Integer> mMapping = new ArrayMap<>(); private int mNextUserId = FIRST_NON_LOCAL_USER; Loading
core/java/android/view/textclassifier/TextClassifierEvent.java +22 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; /** * A text classifier event. Loading Loading @@ -498,4 +499,25 @@ public final class TextClassifierEvent implements Parcelable { } // TODO: Add build(boolean validate). } @Override public String toString() { StringBuilder out = new StringBuilder(128); out.append("TextClassifierEvent{"); out.append("mEventCategory=").append(mEventCategory); out.append(", mEventType=").append(mEventType); out.append(", mEventContext=").append(mEventContext); out.append(", mResultId=").append(mResultId); out.append(", mEventIndex=").append(mEventIndex); out.append(", mEventTime=").append(mEventTime); out.append(", mExtras=").append(mExtras); out.append(", mRelativeWordStartIndex=").append(mRelativeWordStartIndex); out.append(", mRelativeWordEndIndex=").append(mRelativeWordEndIndex); out.append(", mRelativeSuggestedWordStartIndex=").append(mRelativeSuggestedWordStartIndex); out.append(", mRelativeSuggestedWordEndIndex=").append(mRelativeSuggestedWordEndIndex); out.append(", mActionIndices=").append(Arrays.toString(mActionIndices)); out.append(", mLanguage=").append(mLanguage); out.append("}"); return out.toString(); } }
core/java/android/view/textclassifier/TextClassifierImpl.java +15 −3 Original line number Diff line number Diff line Loading @@ -80,6 +80,8 @@ public final class TextClassifierImpl implements TextClassifier { private static final String LOG_TAG = DEFAULT_LOG_TAG; private static final boolean DEBUG = false; private static final File FACTORY_MODEL_DIR = new File("/etc/textclassifier/"); // Annotator private static final String ANNOTATOR_FACTORY_MODEL_FILENAME_REGEX = Loading Loading @@ -109,6 +111,8 @@ public final class TextClassifierImpl implements TextClassifier { @GuardedBy("mLock") // Do not access outside this lock. private LangIdModel mLangIdImpl; @GuardedBy("mLock") // Do not access outside this lock. private ModelFileManager.ModelFile mActionModelInUse; @GuardedBy("mLock") // Do not access outside this lock. private ActionsSuggestionsModel mActionsImpl; private final Object mLoggerLock = new Object(); Loading Loading @@ -342,8 +346,10 @@ public final class TextClassifierImpl implements TextClassifier { } @Override public void onTextClassifierEvent(@NonNull TextClassifierEvent event) { // TODO: Implement. public void onTextClassifierEvent(TextClassifierEvent event) { if (DEBUG) { Log.d(DEFAULT_LOG_TAG, "onTextClassifierEvent() called with: event = [" + event + "]"); } } /** @inheritDoc */ Loading Loading @@ -408,7 +414,12 @@ public final class TextClassifierImpl implements TextClassifier { .setConfidenceScore(nativeSuggestion.getScore()) .build()); } return new ConversationActions(conversationActions, /*id*/ null); String resultId = ActionsSuggestionsHelper.createResultId( mContext, request.getConversation(), mActionModelInUse.getVersion(), mActionModelInUse.getSupportedLocales()); return new ConversationActions(conversationActions, resultId); } catch (Throwable t) { // Avoid throwing from this method. Log the error. Log.e(LOG_TAG, "Error suggesting conversation actions.", t); Loading Loading @@ -517,6 +528,7 @@ public final class TextClassifierImpl implements TextClassifier { try { if (pfd != null) { mActionsImpl = new ActionsSuggestionsModel(pfd.getFd()); mActionModelInUse = bestModel; } } finally { maybeCloseAndLogError(pfd); Loading
packages/ExtServices/src/android/ext/services/notification/Assistant.java +25 −14 Original line number Diff line number Diff line Loading @@ -117,7 +117,7 @@ public class Assistant extends NotificationAssistantService { mPackageManager = ActivityThread.getPackageManager(); mSettings = mSettingsFactory.createAndRegister(mHandler, getApplicationContext().getContentResolver(), getUserId(), this::updateThresholds); mSmartActionsHelper = new SmartActionsHelper(); mSmartActionsHelper = new SmartActionsHelper(getContext(), mSettings); mNotificationCategorizer = new NotificationCategorizer(); mAgingHelper = new AgingHelper(getContext(), mNotificationCategorizer, Loading Loading @@ -215,10 +215,8 @@ public class Assistant extends NotificationAssistantService { return null; } NotificationEntry entry = new NotificationEntry(mPackageManager, sbn, channel); ArrayList<Notification.Action> actions = mSmartActionsHelper.suggestActions(this, entry, mSettings); ArrayList<CharSequence> replies = mSmartActionsHelper.suggestReplies(this, entry, mSettings); ArrayList<Notification.Action> actions = mSmartActionsHelper.suggestActions(entry); ArrayList<CharSequence> replies = mSmartActionsHelper.suggestReplies(entry); return createEnqueuedNotificationAdjustment(entry, actions, replies); } Loading Loading @@ -343,6 +341,7 @@ public class Assistant extends NotificationAssistantService { if (entry != null) { entry.setSeen(); mAgingHelper.onNotificationSeen(entry); mSmartActionsHelper.onNotificationSeen(entry); } } } catch (Throwable e) { Loading @@ -351,34 +350,46 @@ public class Assistant extends NotificationAssistantService { } @Override public void onNotificationExpansionChanged(String key, boolean isUserAction, public void onNotificationExpansionChanged(@NonNull String key, boolean isUserAction, boolean isExpanded) { if (DEBUG) { Log.i(TAG, "onNotificationExpansionChanged " + key + ", isUserAction =" + isUserAction + ", isExpanded = isExpanded"); Log.d(TAG, "onNotificationExpansionChanged() called with: key = [" + key + "], isUserAction = [" + isUserAction + "], isExpanded = [" + isExpanded + "]"); } NotificationEntry entry = mLiveNotifications.get(key); if (entry != null) { entry.setExpanded(isExpanded); mSmartActionsHelper.onNotificationExpansionChanged(entry, isUserAction, isExpanded); } } @Override public void onNotificationDirectReply(String key) { public void onNotificationDirectReply(@NonNull String key) { if (DEBUG) Log.i(TAG, "onNotificationDirectReply " + key); mSmartActionsHelper.onNotificationDirectReply(key); } @Override public void onSuggestedReplySent(String key, CharSequence reply, int source) { public void onSuggestedReplySent(@NonNull String key, @NonNull CharSequence reply, @Source int source) { if (DEBUG) { Log.d(TAG, "onSuggestedReplySent() called with: key = [" + key + "], reply = [" + reply + "], source = [" + source + "]"); } mSmartActionsHelper.onSuggestedReplySent(key, reply, source); } @Override public void onActionClicked(String key, Notification.Action action, int source) { public void onActionClicked(@NonNull String key, @NonNull Notification.Action action, @Source int source) { if (DEBUG) { Log.d(TAG, "onActionClicked() called with: key = [" + key + "], action = [" + action.title Log.d(TAG, "onActionClicked() called with: key = [" + key + "], action = [" + action.title + "], source = [" + source + "]"); } mSmartActionsHelper.onActionClicked(key, action, source); } @Override Loading