Loading api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -5596,6 +5596,7 @@ package android.app { method public android.graphics.drawable.Icon getIcon(); method public android.app.RemoteInput[] getRemoteInputs(); method public int getSemanticAction(); method public boolean isAuthenticationRequired(); method public boolean isContextual(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.Notification.Action> CREATOR; Loading Loading @@ -5625,6 +5626,7 @@ package android.app { method @NonNull public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Extender); method @NonNull public android.os.Bundle getExtras(); method @NonNull public android.app.Notification.Action.Builder setAllowGeneratedReplies(boolean); method @NonNull public android.app.Notification.Action.Builder setAuthenticationRequired(boolean); method @NonNull public android.app.Notification.Action.Builder setContextual(boolean); method @NonNull public android.app.Notification.Action.Builder setSemanticAction(int); } core/java/android/app/Notification.java +44 −8 Original line number Diff line number Diff line Loading @@ -1492,6 +1492,7 @@ public class Notification implements Parcelable private boolean mAllowGeneratedReplies = true; private final @SemanticAction int mSemanticAction; private final boolean mIsContextual; private boolean mAuthenticationRequired; /** * Small icon representing the action. Loading Loading @@ -1528,6 +1529,7 @@ public class Notification implements Parcelable mAllowGeneratedReplies = in.readInt() == 1; mSemanticAction = in.readInt(); mIsContextual = in.readInt() == 1; mAuthenticationRequired = in.readInt() == 1; } /** Loading @@ -1536,13 +1538,14 @@ public class Notification implements Parcelable @Deprecated public Action(int icon, CharSequence title, PendingIntent intent) { this(Icon.createWithResource("", icon), title, intent, new Bundle(), null, true, SEMANTIC_ACTION_NONE, false /* isContextual */); SEMANTIC_ACTION_NONE, false /* isContextual */, false /* requireAuth */); } /** Keep in sync with {@link Notification.Action.Builder#Builder(Action)}! */ private Action(Icon icon, CharSequence title, PendingIntent intent, Bundle extras, RemoteInput[] remoteInputs, boolean allowGeneratedReplies, @SemanticAction int semanticAction, boolean isContextual) { @SemanticAction int semanticAction, boolean isContextual, boolean requireAuth) { this.mIcon = icon; if (icon != null && icon.getType() == Icon.TYPE_RESOURCE) { this.icon = icon.getResId(); Loading @@ -1554,6 +1557,7 @@ public class Notification implements Parcelable this.mAllowGeneratedReplies = allowGeneratedReplies; this.mSemanticAction = semanticAction; this.mIsContextual = isContextual; this.mAuthenticationRequired = requireAuth; } /** Loading Loading @@ -1623,6 +1627,17 @@ public class Notification implements Parcelable return getParcelableArrayFromBundle(mExtras, EXTRA_DATA_ONLY_INPUTS, RemoteInput.class); } /** * Returns whether the OS should only send this action's {@link PendingIntent} on an * unlocked device. * * If the device is locked when the action is invoked, the OS should show the keyguard and * require successful authentication before invoking the intent. */ public boolean isAuthenticationRequired() { return mAuthenticationRequired; } /** * Builder class for {@link Action} objects. */ Loading @@ -1635,6 +1650,7 @@ public class Notification implements Parcelable @Nullable private ArrayList<RemoteInput> mRemoteInputs; private @SemanticAction int mSemanticAction; private boolean mIsContextual; private boolean mAuthenticationRequired; /** * Construct a new builder for {@link Action} object. Loading @@ -1654,7 +1670,7 @@ public class Notification implements Parcelable * @param intent the {@link PendingIntent} to fire when users trigger this action */ public Builder(Icon icon, CharSequence title, PendingIntent intent) { this(icon, title, intent, new Bundle(), null, true, SEMANTIC_ACTION_NONE); this(icon, title, intent, new Bundle(), null, true, SEMANTIC_ACTION_NONE, false); } /** Loading @@ -1665,23 +1681,25 @@ public class Notification implements Parcelable public Builder(Action action) { this(action.getIcon(), action.title, action.actionIntent, new Bundle(action.mExtras), action.getRemoteInputs(), action.getAllowGeneratedReplies(), action.getSemanticAction()); action.getAllowGeneratedReplies(), action.getSemanticAction(), action.isAuthenticationRequired()); } private Builder(@Nullable Icon icon, @Nullable CharSequence title, @Nullable PendingIntent intent, @NonNull Bundle extras, @Nullable RemoteInput[] remoteInputs, boolean allowGeneratedReplies, @SemanticAction int semanticAction) { @SemanticAction int semanticAction, boolean authRequired) { mIcon = icon; mTitle = title; mIntent = intent; mExtras = extras; if (remoteInputs != null) { mRemoteInputs = new ArrayList<RemoteInput>(remoteInputs.length); mRemoteInputs = new ArrayList<>(remoteInputs.length); Collections.addAll(mRemoteInputs, remoteInputs); } mAllowGeneratedReplies = allowGeneratedReplies; mSemanticAction = semanticAction; mAuthenticationRequired = authRequired; } /** Loading Loading @@ -1775,6 +1793,21 @@ public class Notification implements Parcelable return this; } /** * Sets whether the OS should only send this action's {@link PendingIntent} on an * unlocked device. * * If this is true and the device is locked when the action is invoked, the OS will * show the keyguard and require successful authentication before invoking the intent. * If this is false and the device is locked, the OS will decide whether authentication * should be required. */ @NonNull public Builder setAuthenticationRequired(boolean authenticationRequired) { mAuthenticationRequired = authenticationRequired; return this; } /** * Throws an NPE if we are building a contextual action missing one of the fields * necessary to display the action. Loading Loading @@ -1827,7 +1860,8 @@ public class Notification implements Parcelable RemoteInput[] textInputsArr = textInputs.isEmpty() ? null : textInputs.toArray(new RemoteInput[textInputs.size()]); return new Action(mIcon, mTitle, mIntent, mExtras, textInputsArr, mAllowGeneratedReplies, mSemanticAction, mIsContextual); mAllowGeneratedReplies, mSemanticAction, mIsContextual, mAuthenticationRequired); } } Loading @@ -1841,7 +1875,8 @@ public class Notification implements Parcelable getRemoteInputs(), getAllowGeneratedReplies(), getSemanticAction(), isContextual()); isContextual(), isAuthenticationRequired()); } @Override Loading Loading @@ -1870,6 +1905,7 @@ public class Notification implements Parcelable out.writeInt(mAllowGeneratedReplies ? 1 : 0); out.writeInt(mSemanticAction); out.writeInt(mIsContextual ? 1 : 0); out.writeInt(mAuthenticationRequired ? 1 : 0); } public static final @android.annotation.NonNull Parcelable.Creator<Action> CREATOR = Loading non-updatable-api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -5596,6 +5596,7 @@ package android.app { method public android.graphics.drawable.Icon getIcon(); method public android.app.RemoteInput[] getRemoteInputs(); method public int getSemanticAction(); method public boolean isAuthenticationRequired(); method public boolean isContextual(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.Notification.Action> CREATOR; Loading Loading @@ -5625,6 +5626,7 @@ package android.app { method @NonNull public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Extender); method @NonNull public android.os.Bundle getExtras(); method @NonNull public android.app.Notification.Action.Builder setAllowGeneratedReplies(boolean); method @NonNull public android.app.Notification.Action.Builder setAuthenticationRequired(boolean); method @NonNull public android.app.Notification.Action.Builder setContextual(boolean); method @NonNull public android.app.Notification.Action.Builder setSemanticAction(int); } packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +21 −6 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dump.DumpManager import com.android.systemui.plugins.ActivityStarter import com.android.systemui.statusbar.notification.MediaNotificationProcessor import com.android.systemui.statusbar.notification.row.HybridGroupManager import com.android.systemui.util.Assert Loading Loading @@ -97,6 +98,7 @@ class MediaDataManager( dumpManager: DumpManager, mediaTimeoutListener: MediaTimeoutListener, mediaResumeListener: MediaResumeListener, private val activityStarter: ActivityStarter, private var useMediaResumption: Boolean, private val useQsMediaPlayer: Boolean ) : Dumpable { Loading @@ -113,10 +115,11 @@ class MediaDataManager( dumpManager: DumpManager, broadcastDispatcher: BroadcastDispatcher, mediaTimeoutListener: MediaTimeoutListener, mediaResumeListener: MediaResumeListener mediaResumeListener: MediaResumeListener, activityStarter: ActivityStarter ) : this(context, backgroundExecutor, foregroundExecutor, mediaControllerFactory, broadcastDispatcher, dumpManager, mediaTimeoutListener, mediaResumeListener, Utils.useMediaResumption(context), Utils.useQsMediaPlayer(context)) activityStarter, Utils.useMediaResumption(context), Utils.useQsMediaPlayer(context)) private val appChangeReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { Loading Loading @@ -403,10 +406,13 @@ class MediaDataManager( } val runnable = if (action.actionIntent != null) { Runnable { try { action.actionIntent.send() } catch (e: PendingIntent.CanceledException) { Log.d(TAG, "Intent canceled", e) if (action.isAuthenticationRequired()) { activityStarter.dismissKeyguardThenExecute ({ var result = sendPendingIntent(action.actionIntent) result }, {}, true) } else { sendPendingIntent(action.actionIntent) } } } else { Loading Loading @@ -449,6 +455,15 @@ class MediaDataManager( return null } private fun sendPendingIntent(intent: PendingIntent): Boolean { return try { intent.send() true } catch (e: PendingIntent.CanceledException) { Log.d(TAG, "Intent canceled", e) false } } /** * Load a bitmap from a URI * @param uri the uri to load Loading packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java +35 −23 Original line number Diff line number Diff line Loading @@ -161,7 +161,9 @@ public class NotificationRemoteInputManager implements Dumpable { ActivityManager.getService().resumeAppSwitches(); } catch (RemoteException e) { } return mCallback.handleRemoteViewClick(view, pendingIntent, () -> { Notification.Action action = getActionFromView(view, entry, pendingIntent); return mCallback.handleRemoteViewClick(view, pendingIntent, action == null ? false : action.isAuthenticationRequired(), () -> { Pair<Intent, ActivityOptions> options = response.getLaunchOptions(view); options.second.setLaunchWindowingMode( WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY); Loading @@ -170,47 +172,56 @@ public class NotificationRemoteInputManager implements Dumpable { }); } private void logActionClick( View view, NotificationEntry entry, PendingIntent actionIntent) { private @Nullable Notification.Action getActionFromView(View view, NotificationEntry entry, PendingIntent actionIntent) { Integer actionIndex = (Integer) view.getTag(com.android.internal.R.id.notification_action_index_tag); if (actionIndex == null) { // Custom action button, not logging. return; return null; } ViewParent parent = view.getParent(); if (entry == null) { Log.w(TAG, "Couldn't determine notification for click."); return; } StatusBarNotification statusBarNotification = entry.getSbn(); String key = statusBarNotification.getKey(); int buttonIndex = -1; // If this is a default template, determine the index of the button. if (view.getId() == com.android.internal.R.id.action0 && parent != null && parent instanceof ViewGroup) { ViewGroup actionGroup = (ViewGroup) parent; buttonIndex = actionGroup.indexOfChild(view); return null; } final int count = mEntryManager.getActiveNotificationsCount(); final int rank = mEntryManager .getActiveNotificationUnfiltered(key).getRanking().getRank(); // Notification may be updated before this function is executed, and thus play safe // here and verify that the action object is still the one that where the click happens. StatusBarNotification statusBarNotification = entry.getSbn(); Notification.Action[] actions = statusBarNotification.getNotification().actions; if (actions == null || actionIndex >= actions.length) { Log.w(TAG, "statusBarNotification.getNotification().actions is null or invalid"); return; return null ; } final Notification.Action action = statusBarNotification.getNotification().actions[actionIndex]; if (!Objects.equals(action.actionIntent, actionIntent)) { Log.w(TAG, "actionIntent does not match"); return null; } return action; } private void logActionClick( View view, NotificationEntry entry, PendingIntent actionIntent) { Notification.Action action = getActionFromView(view, entry, actionIntent); if (action == null) { return; } ViewParent parent = view.getParent(); String key = entry.getSbn().getKey(); int buttonIndex = -1; // If this is a default template, determine the index of the button. if (view.getId() == com.android.internal.R.id.action0 && parent != null && parent instanceof ViewGroup) { ViewGroup actionGroup = (ViewGroup) parent; buttonIndex = actionGroup.indexOfChild(view); } final int count = mEntryManager.getActiveNotificationsCount(); final int rank = mEntryManager .getActiveNotificationUnfiltered(key).getRanking().getRank(); NotificationVisibility.NotificationLocation location = NotificationLogger.getNotificationLocation( mEntryManager.getActiveNotificationUnfiltered(key)); Loading Loading @@ -813,11 +824,12 @@ public class NotificationRemoteInputManager implements Dumpable { * * @param view * @param pendingIntent * @param appRequestedAuth * @param defaultHandler * @return true iff the click was handled */ boolean handleRemoteViewClick(View view, PendingIntent pendingIntent, ClickHandler defaultHandler); boolean appRequestedAuth, ClickHandler defaultHandler); } /** Loading Loading
api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -5596,6 +5596,7 @@ package android.app { method public android.graphics.drawable.Icon getIcon(); method public android.app.RemoteInput[] getRemoteInputs(); method public int getSemanticAction(); method public boolean isAuthenticationRequired(); method public boolean isContextual(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.Notification.Action> CREATOR; Loading Loading @@ -5625,6 +5626,7 @@ package android.app { method @NonNull public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Extender); method @NonNull public android.os.Bundle getExtras(); method @NonNull public android.app.Notification.Action.Builder setAllowGeneratedReplies(boolean); method @NonNull public android.app.Notification.Action.Builder setAuthenticationRequired(boolean); method @NonNull public android.app.Notification.Action.Builder setContextual(boolean); method @NonNull public android.app.Notification.Action.Builder setSemanticAction(int); }
core/java/android/app/Notification.java +44 −8 Original line number Diff line number Diff line Loading @@ -1492,6 +1492,7 @@ public class Notification implements Parcelable private boolean mAllowGeneratedReplies = true; private final @SemanticAction int mSemanticAction; private final boolean mIsContextual; private boolean mAuthenticationRequired; /** * Small icon representing the action. Loading Loading @@ -1528,6 +1529,7 @@ public class Notification implements Parcelable mAllowGeneratedReplies = in.readInt() == 1; mSemanticAction = in.readInt(); mIsContextual = in.readInt() == 1; mAuthenticationRequired = in.readInt() == 1; } /** Loading @@ -1536,13 +1538,14 @@ public class Notification implements Parcelable @Deprecated public Action(int icon, CharSequence title, PendingIntent intent) { this(Icon.createWithResource("", icon), title, intent, new Bundle(), null, true, SEMANTIC_ACTION_NONE, false /* isContextual */); SEMANTIC_ACTION_NONE, false /* isContextual */, false /* requireAuth */); } /** Keep in sync with {@link Notification.Action.Builder#Builder(Action)}! */ private Action(Icon icon, CharSequence title, PendingIntent intent, Bundle extras, RemoteInput[] remoteInputs, boolean allowGeneratedReplies, @SemanticAction int semanticAction, boolean isContextual) { @SemanticAction int semanticAction, boolean isContextual, boolean requireAuth) { this.mIcon = icon; if (icon != null && icon.getType() == Icon.TYPE_RESOURCE) { this.icon = icon.getResId(); Loading @@ -1554,6 +1557,7 @@ public class Notification implements Parcelable this.mAllowGeneratedReplies = allowGeneratedReplies; this.mSemanticAction = semanticAction; this.mIsContextual = isContextual; this.mAuthenticationRequired = requireAuth; } /** Loading Loading @@ -1623,6 +1627,17 @@ public class Notification implements Parcelable return getParcelableArrayFromBundle(mExtras, EXTRA_DATA_ONLY_INPUTS, RemoteInput.class); } /** * Returns whether the OS should only send this action's {@link PendingIntent} on an * unlocked device. * * If the device is locked when the action is invoked, the OS should show the keyguard and * require successful authentication before invoking the intent. */ public boolean isAuthenticationRequired() { return mAuthenticationRequired; } /** * Builder class for {@link Action} objects. */ Loading @@ -1635,6 +1650,7 @@ public class Notification implements Parcelable @Nullable private ArrayList<RemoteInput> mRemoteInputs; private @SemanticAction int mSemanticAction; private boolean mIsContextual; private boolean mAuthenticationRequired; /** * Construct a new builder for {@link Action} object. Loading @@ -1654,7 +1670,7 @@ public class Notification implements Parcelable * @param intent the {@link PendingIntent} to fire when users trigger this action */ public Builder(Icon icon, CharSequence title, PendingIntent intent) { this(icon, title, intent, new Bundle(), null, true, SEMANTIC_ACTION_NONE); this(icon, title, intent, new Bundle(), null, true, SEMANTIC_ACTION_NONE, false); } /** Loading @@ -1665,23 +1681,25 @@ public class Notification implements Parcelable public Builder(Action action) { this(action.getIcon(), action.title, action.actionIntent, new Bundle(action.mExtras), action.getRemoteInputs(), action.getAllowGeneratedReplies(), action.getSemanticAction()); action.getAllowGeneratedReplies(), action.getSemanticAction(), action.isAuthenticationRequired()); } private Builder(@Nullable Icon icon, @Nullable CharSequence title, @Nullable PendingIntent intent, @NonNull Bundle extras, @Nullable RemoteInput[] remoteInputs, boolean allowGeneratedReplies, @SemanticAction int semanticAction) { @SemanticAction int semanticAction, boolean authRequired) { mIcon = icon; mTitle = title; mIntent = intent; mExtras = extras; if (remoteInputs != null) { mRemoteInputs = new ArrayList<RemoteInput>(remoteInputs.length); mRemoteInputs = new ArrayList<>(remoteInputs.length); Collections.addAll(mRemoteInputs, remoteInputs); } mAllowGeneratedReplies = allowGeneratedReplies; mSemanticAction = semanticAction; mAuthenticationRequired = authRequired; } /** Loading Loading @@ -1775,6 +1793,21 @@ public class Notification implements Parcelable return this; } /** * Sets whether the OS should only send this action's {@link PendingIntent} on an * unlocked device. * * If this is true and the device is locked when the action is invoked, the OS will * show the keyguard and require successful authentication before invoking the intent. * If this is false and the device is locked, the OS will decide whether authentication * should be required. */ @NonNull public Builder setAuthenticationRequired(boolean authenticationRequired) { mAuthenticationRequired = authenticationRequired; return this; } /** * Throws an NPE if we are building a contextual action missing one of the fields * necessary to display the action. Loading Loading @@ -1827,7 +1860,8 @@ public class Notification implements Parcelable RemoteInput[] textInputsArr = textInputs.isEmpty() ? null : textInputs.toArray(new RemoteInput[textInputs.size()]); return new Action(mIcon, mTitle, mIntent, mExtras, textInputsArr, mAllowGeneratedReplies, mSemanticAction, mIsContextual); mAllowGeneratedReplies, mSemanticAction, mIsContextual, mAuthenticationRequired); } } Loading @@ -1841,7 +1875,8 @@ public class Notification implements Parcelable getRemoteInputs(), getAllowGeneratedReplies(), getSemanticAction(), isContextual()); isContextual(), isAuthenticationRequired()); } @Override Loading Loading @@ -1870,6 +1905,7 @@ public class Notification implements Parcelable out.writeInt(mAllowGeneratedReplies ? 1 : 0); out.writeInt(mSemanticAction); out.writeInt(mIsContextual ? 1 : 0); out.writeInt(mAuthenticationRequired ? 1 : 0); } public static final @android.annotation.NonNull Parcelable.Creator<Action> CREATOR = Loading
non-updatable-api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -5596,6 +5596,7 @@ package android.app { method public android.graphics.drawable.Icon getIcon(); method public android.app.RemoteInput[] getRemoteInputs(); method public int getSemanticAction(); method public boolean isAuthenticationRequired(); method public boolean isContextual(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.Notification.Action> CREATOR; Loading Loading @@ -5625,6 +5626,7 @@ package android.app { method @NonNull public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Extender); method @NonNull public android.os.Bundle getExtras(); method @NonNull public android.app.Notification.Action.Builder setAllowGeneratedReplies(boolean); method @NonNull public android.app.Notification.Action.Builder setAuthenticationRequired(boolean); method @NonNull public android.app.Notification.Action.Builder setContextual(boolean); method @NonNull public android.app.Notification.Action.Builder setSemanticAction(int); }
packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +21 −6 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dump.DumpManager import com.android.systemui.plugins.ActivityStarter import com.android.systemui.statusbar.notification.MediaNotificationProcessor import com.android.systemui.statusbar.notification.row.HybridGroupManager import com.android.systemui.util.Assert Loading Loading @@ -97,6 +98,7 @@ class MediaDataManager( dumpManager: DumpManager, mediaTimeoutListener: MediaTimeoutListener, mediaResumeListener: MediaResumeListener, private val activityStarter: ActivityStarter, private var useMediaResumption: Boolean, private val useQsMediaPlayer: Boolean ) : Dumpable { Loading @@ -113,10 +115,11 @@ class MediaDataManager( dumpManager: DumpManager, broadcastDispatcher: BroadcastDispatcher, mediaTimeoutListener: MediaTimeoutListener, mediaResumeListener: MediaResumeListener mediaResumeListener: MediaResumeListener, activityStarter: ActivityStarter ) : this(context, backgroundExecutor, foregroundExecutor, mediaControllerFactory, broadcastDispatcher, dumpManager, mediaTimeoutListener, mediaResumeListener, Utils.useMediaResumption(context), Utils.useQsMediaPlayer(context)) activityStarter, Utils.useMediaResumption(context), Utils.useQsMediaPlayer(context)) private val appChangeReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { Loading Loading @@ -403,10 +406,13 @@ class MediaDataManager( } val runnable = if (action.actionIntent != null) { Runnable { try { action.actionIntent.send() } catch (e: PendingIntent.CanceledException) { Log.d(TAG, "Intent canceled", e) if (action.isAuthenticationRequired()) { activityStarter.dismissKeyguardThenExecute ({ var result = sendPendingIntent(action.actionIntent) result }, {}, true) } else { sendPendingIntent(action.actionIntent) } } } else { Loading Loading @@ -449,6 +455,15 @@ class MediaDataManager( return null } private fun sendPendingIntent(intent: PendingIntent): Boolean { return try { intent.send() true } catch (e: PendingIntent.CanceledException) { Log.d(TAG, "Intent canceled", e) false } } /** * Load a bitmap from a URI * @param uri the uri to load Loading
packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java +35 −23 Original line number Diff line number Diff line Loading @@ -161,7 +161,9 @@ public class NotificationRemoteInputManager implements Dumpable { ActivityManager.getService().resumeAppSwitches(); } catch (RemoteException e) { } return mCallback.handleRemoteViewClick(view, pendingIntent, () -> { Notification.Action action = getActionFromView(view, entry, pendingIntent); return mCallback.handleRemoteViewClick(view, pendingIntent, action == null ? false : action.isAuthenticationRequired(), () -> { Pair<Intent, ActivityOptions> options = response.getLaunchOptions(view); options.second.setLaunchWindowingMode( WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY); Loading @@ -170,47 +172,56 @@ public class NotificationRemoteInputManager implements Dumpable { }); } private void logActionClick( View view, NotificationEntry entry, PendingIntent actionIntent) { private @Nullable Notification.Action getActionFromView(View view, NotificationEntry entry, PendingIntent actionIntent) { Integer actionIndex = (Integer) view.getTag(com.android.internal.R.id.notification_action_index_tag); if (actionIndex == null) { // Custom action button, not logging. return; return null; } ViewParent parent = view.getParent(); if (entry == null) { Log.w(TAG, "Couldn't determine notification for click."); return; } StatusBarNotification statusBarNotification = entry.getSbn(); String key = statusBarNotification.getKey(); int buttonIndex = -1; // If this is a default template, determine the index of the button. if (view.getId() == com.android.internal.R.id.action0 && parent != null && parent instanceof ViewGroup) { ViewGroup actionGroup = (ViewGroup) parent; buttonIndex = actionGroup.indexOfChild(view); return null; } final int count = mEntryManager.getActiveNotificationsCount(); final int rank = mEntryManager .getActiveNotificationUnfiltered(key).getRanking().getRank(); // Notification may be updated before this function is executed, and thus play safe // here and verify that the action object is still the one that where the click happens. StatusBarNotification statusBarNotification = entry.getSbn(); Notification.Action[] actions = statusBarNotification.getNotification().actions; if (actions == null || actionIndex >= actions.length) { Log.w(TAG, "statusBarNotification.getNotification().actions is null or invalid"); return; return null ; } final Notification.Action action = statusBarNotification.getNotification().actions[actionIndex]; if (!Objects.equals(action.actionIntent, actionIntent)) { Log.w(TAG, "actionIntent does not match"); return null; } return action; } private void logActionClick( View view, NotificationEntry entry, PendingIntent actionIntent) { Notification.Action action = getActionFromView(view, entry, actionIntent); if (action == null) { return; } ViewParent parent = view.getParent(); String key = entry.getSbn().getKey(); int buttonIndex = -1; // If this is a default template, determine the index of the button. if (view.getId() == com.android.internal.R.id.action0 && parent != null && parent instanceof ViewGroup) { ViewGroup actionGroup = (ViewGroup) parent; buttonIndex = actionGroup.indexOfChild(view); } final int count = mEntryManager.getActiveNotificationsCount(); final int rank = mEntryManager .getActiveNotificationUnfiltered(key).getRanking().getRank(); NotificationVisibility.NotificationLocation location = NotificationLogger.getNotificationLocation( mEntryManager.getActiveNotificationUnfiltered(key)); Loading Loading @@ -813,11 +824,12 @@ public class NotificationRemoteInputManager implements Dumpable { * * @param view * @param pendingIntent * @param appRequestedAuth * @param defaultHandler * @return true iff the click was handled */ boolean handleRemoteViewClick(View view, PendingIntent pendingIntent, ClickHandler defaultHandler); boolean appRequestedAuth, ClickHandler defaultHandler); } /** Loading