diff options
| author | 2021-03-10 21:10:19 +0000 | |
|---|---|---|
| committer | 2021-03-10 21:10:19 +0000 | |
| commit | bbcb857d3a2ee45315e9cca18cf5b48effa6c64b (patch) | |
| tree | 7210f845c5398f895213c3cac2a530010c9cf7cf | |
| parent | 3074ceab621ff5115daa1552774b302567b1cd20 (diff) | |
| parent | 1a7ae5b90bb3c49c0dc3992fa8e7b3de486cc657 (diff) | |
Merge "CallStyle notifications now include their adjusted actions in the actions list." into sc-dev
| -rw-r--r-- | core/java/android/app/Notification.java | 196 | ||||
| -rwxr-xr-x | services/core/java/com/android/server/notification/NotificationManagerService.java | 12 |
2 files changed, 122 insertions, 86 deletions
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 59b0032a151c..ad2835c5ea2d 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -5445,8 +5445,12 @@ public class Notification implements Parcelable return p.allowColorization && mN.isColorized(); } - private boolean isCallActionColorCustomizable(StandardTemplateParams p) { - return isColorized(p) && mContext.getResources().getBoolean( + private boolean isCallActionColorCustomizable() { + // NOTE: this doesn't need to check StandardTemplateParams.allowColorization because + // that is only used for disallowing colorization of headers for the minimized state, + // and neither of those conditions applies when showing actions. + // Not requiring StandardTemplateParams as an argument simplifies the creation process. + return mN.isColorized() && mContext.getResources().getBoolean( R.bool.config_callNotificationActionColorsRequireColorized); } @@ -5512,13 +5516,13 @@ public class Notification implements Parcelable */ private @NonNull List<Notification.Action> getNonContextualActions() { if (mActions == null) return Collections.emptyList(); - List<Notification.Action> contextualActions = new ArrayList<>(); + List<Notification.Action> standardActions = new ArrayList<>(); for (Notification.Action action : mActions) { if (!action.isContextual()) { - contextualActions.add(action); + standardActions.add(action); } } - return contextualActions; + return standardActions; } private RemoteViews applyStandardTemplateWithActions(int layoutId, @@ -5538,16 +5542,29 @@ public class Notification implements Parcelable // filter them out here. List<Notification.Action> nonContextualActions = getNonContextualActions(); - int N = nonContextualActions.size(); - boolean emphazisedMode = mN.fullScreenIntent != null; + int numActions = Math.min(nonContextualActions.size(), MAX_ACTION_BUTTONS); + boolean emphazisedMode = mN.fullScreenIntent != null || p.mCallStyleActions; + if (p.mCallStyleActions) { + // Clear view padding to allow buttons to start on the left edge. + // This must be done before 'setEmphasizedMode' which sets top/bottom margins. + big.setViewPadding(R.id.actions, 0, 0, 0, 0); + // Add an optional indent that will make buttons start at the correct column when + // there is enough space to do so (and fall back to the left edge if not). + big.setInt(R.id.actions, "setCollapsibleIndentDimen", + R.dimen.call_notification_collapsible_indent); + } big.setBoolean(R.id.actions, "setEmphasizedMode", emphazisedMode); - if (N > 0 && !p.mHideActions) { + if (p.mCallStyleActions) { + // Use "wrap_content" (unlike normal emphasized mode) and allow prioritizing the + // required actions (Answer, Decline, and Hang Up). + big.setBoolean(R.id.actions, "setPrioritizedWrapMode", true); + } + if (numActions > 0 && !p.mHideActions) { big.setViewVisibility(R.id.actions_container, View.VISIBLE); big.setViewVisibility(R.id.actions, View.VISIBLE); big.setViewLayoutMarginDimen(R.id.notification_action_list_margin_target, RemoteViews.MARGIN_BOTTOM, 0); - if (N>MAX_ACTION_BUTTONS) N=MAX_ACTION_BUTTONS; - for (int i=0; i<N; i++) { + for (int i = 0; i < numActions; i++) { Action action = nonContextualActions.get(i); boolean actionHasValidInput = hasValidRemoteInput(action); @@ -5558,6 +5575,11 @@ public class Notification implements Parcelable // Clear the drawable button.setInt(R.id.action0, "setBackgroundResource", 0); } + if (p.mCallStyleActions && i > 0) { + // Clear start margin from non-first buttons to reduce the gap between them. + // (8dp remaining gap is from all buttons' standard 4dp inset). + button.setViewLayoutMarginDimen(R.id.action0, RemoteViews.MARGIN_START, 0); + } big.addView(R.id.actions, button); } } else { @@ -6019,7 +6041,7 @@ public class Notification implements Parcelable button.setColorStateList(R.id.action0, "setButtonBackground", ColorStateList.valueOf(background)); button.setBoolean(R.id.action0, "setHasStroke", !hasColorOverride); - if (p.mAllowActionIcons) { + if (p.mCallStyleActions) { button.setImageViewIcon(R.id.action0, action.getIcon()); boolean priority = action.getExtras().getBoolean(CallStyle.KEY_ACTION_PRIORITY); button.setBoolean(R.id.action0, "setWrapModePriority", priority); @@ -9265,6 +9287,17 @@ public class Notification implements Parcelable return this; } + /** @hide */ + @Override + public Notification buildStyled(Notification wip) { + wip = super.buildStyled(wip); + // ensure that the actions in the builder and notification are corrected. + mBuilder.mActions = getActionsListWithSystemActions(); + wip.actions = new Action[mBuilder.mActions.size()]; + mBuilder.mActions.toArray(wip.actions); + return wip; + } + /** * @hide */ @@ -9324,14 +9357,14 @@ public class Notification implements Parcelable } @NonNull - private Action makeNegativeAction(@NonNull StandardTemplateParams p) { + private Action makeNegativeAction() { if (mDeclineIntent == null) { - return makeAction(p, R.drawable.ic_call_decline, + return makeAction(R.drawable.ic_call_decline, R.string.call_notification_hang_up_action, mDeclineButtonColor, R.color.call_notification_decline_color, mHangUpIntent); } else { - return makeAction(p, R.drawable.ic_call_decline, + return makeAction(R.drawable.ic_call_decline, R.string.call_notification_decline_action, mDeclineButtonColor, R.color.call_notification_decline_color, mDeclineIntent); @@ -9339,18 +9372,17 @@ public class Notification implements Parcelable } @Nullable - private Action makeAnswerAction(@NonNull StandardTemplateParams p) { - return mAnswerIntent == null ? null : makeAction(p, R.drawable.ic_call_answer, + private Action makeAnswerAction() { + return mAnswerIntent == null ? null : makeAction(R.drawable.ic_call_answer, R.string.call_notification_answer_action, mAnswerButtonColor, R.color.call_notification_answer_color, mAnswerIntent); } @NonNull - private Action makeAction(@NonNull StandardTemplateParams p, - @DrawableRes int icon, @StringRes int title, + private Action makeAction(@DrawableRes int icon, @StringRes int title, @ColorInt Integer colorInt, @ColorRes int defaultColorRes, PendingIntent intent) { - if (colorInt == null || !mBuilder.isCallActionColorCustomizable(p)) { + if (colorInt == null || !mBuilder.isCallActionColorCustomizable()) { colorInt = mBuilder.mContext.getColor(defaultColorRes); } Action action = new Action.Builder(Icon.createWithResource("", icon), @@ -9362,29 +9394,62 @@ public class Notification implements Parcelable return action; } - private ArrayList<Action> makeActionsList(@NonNull StandardTemplateParams p) { - final Action negativeAction = makeNegativeAction(p); - final Action answerAction = makeAnswerAction(p); + private boolean isActionAddedByCallStyle(Action action) { + // This is an internal extra added by the style to these actions. If an app were to add + // this extra to the action themselves, the action would be dropped. :shrug: + return action != null && action.getExtras().getBoolean(KEY_ACTION_PRIORITY); + } - ArrayList<Action> actions = new ArrayList<>(MAX_ACTION_BUTTONS); - final Action lastAction; - if (answerAction == null) { - // If there's no answer action, put the hang up / decline action at the end - lastAction = negativeAction; - } else { - // Otherwise put the answer action at the end, and put the decline action at start. - actions.add(negativeAction); - lastAction = answerAction; - } - // For consistency with the standard actions bar, contextual actions are ignored. - for (Action action : mBuilder.getNonContextualActions()) { - if (actions.size() >= MAX_ACTION_BUTTONS - 1) { - break; + /** + * Gets the actions list for the call with the answer/decline/hangUp actions inserted in + * the correct place. This returns the correct result even if the system actions have + * already been added, and even if more actions were added since then. + * @hide + */ + @NonNull + public ArrayList<Action> getActionsListWithSystemActions() { + // Define the system actions we expect to see + final Action negativeAction = makeNegativeAction(); + final Action answerAction = makeAnswerAction(); + // Sort the expected actions into the correct order: + // * If there's no answer action, put the hang up / decline action at the end + // * Otherwise put the answer action at the end, and put the decline action at start. + final Action firstAction = answerAction == null ? null : negativeAction; + final Action lastAction = answerAction == null ? negativeAction : answerAction; + + // Start creating the result list. + int nonContextualActionSlotsRemaining = MAX_ACTION_BUTTONS; + ArrayList<Action> resultActions = new ArrayList<>(MAX_ACTION_BUTTONS); + if (firstAction != null) { + resultActions.add(firstAction); + --nonContextualActionSlotsRemaining; + } + + // Copy actions into the new list, correcting system actions. + if (mBuilder.mActions != null) { + for (Notification.Action action : mBuilder.mActions) { + if (action.isContextual()) { + // Always include all contextual actions + resultActions.add(action); + } else if (isActionAddedByCallStyle(action)) { + // Drop any old versions of system actions + } else { + // Copy non-contextual actions; decrement the remaining action slots. + resultActions.add(action); + --nonContextualActionSlotsRemaining; + } + // If there's exactly one action slot left, fill it with the lastAction. + if (nonContextualActionSlotsRemaining == 1) { + resultActions.add(lastAction); + --nonContextualActionSlotsRemaining; + } } - actions.add(action); } - actions.add(lastAction); - return actions; + // If there are any action slots left, the lastAction still needs to be added. + if (nonContextualActionSlotsRemaining >= 1) { + resultActions.add(lastAction); + } + return resultActions; } private RemoteViews makeCallLayout() { @@ -9397,19 +9462,15 @@ public class Notification implements Parcelable // Bind standard template StandardTemplateParams p = mBuilder.mParams.reset() .viewType(StandardTemplateParams.VIEW_TYPE_BIG) - .allowActionIcons(true) + .callStyleActions(true) .allowTextWithProgress(true) .hideLargeIcon(true) .text(text) .summaryText(mBuilder.processLegacyText(mVerificationText)); - RemoteViews contentView = mBuilder.applyStandardTemplate( + mBuilder.mActions = getActionsListWithSystemActions(); + RemoteViews contentView = mBuilder.applyStandardTemplateWithActions( mBuilder.getCallLayoutResource(), p, null /* result */); - // Bind actions. - mBuilder.resetStandardTemplateWithActions(contentView); - mBuilder.bindSnoozeAction(contentView, p); - bindCallActions(contentView, p); - // Bind some extra conversation-specific header fields. mBuilder.setTextViewColorPrimary(contentView, R.id.conversation_text, p); mBuilder.setTextViewColorSecondary(contentView, R.id.app_name_divider, p); @@ -9429,41 +9490,6 @@ public class Notification implements Parcelable return contentView; } - private void bindCallActions(RemoteViews view, StandardTemplateParams p) { - view.setViewVisibility(R.id.actions_container, View.VISIBLE); - view.setViewVisibility(R.id.actions, View.VISIBLE); - view.setViewLayoutMarginDimen(R.id.notification_action_list_margin_target, - RemoteViews.MARGIN_BOTTOM, 0); - - // Clear view padding to allow buttons to start on the left edge. - // This must be done before 'setEmphasizedMode' which sets top/bottom margins. - view.setViewPadding(R.id.actions, 0, 0, 0, 0); - // Add an optional indent that will make buttons start at the correct column when - // there is enough space to do so (and fall back to the left edge if not). - view.setInt(R.id.actions, "setCollapsibleIndentDimen", - R.dimen.call_notification_collapsible_indent); - - // Emphasize so that buttons have borders or colored backgrounds - boolean emphasizedMode = true; - view.setBoolean(R.id.actions, "setEmphasizedMode", emphasizedMode); - // Use "wrap_content" (unlike normal emphasized mode) and allow prioritizing the - // required actions (Answer, Decline, and Hang Up). - view.setBoolean(R.id.actions, "setPrioritizedWrapMode", true); - - // Create the buttons for the generated actions list. - int i = 0; - for (Action action : makeActionsList(p)) { - final RemoteViews button = mBuilder.generateActionButton(action, emphasizedMode, p); - if (i > 0) { - // Clear start margin from non-first buttons to reduce the gap between buttons. - // (8dp remaining gap is from all buttons' standard 4dp inset). - button.setViewLayoutMarginDimen(R.id.action0, RemoteViews.MARGIN_START, 0); - } - view.addView(R.id.actions, button); - ++i; - } - } - private void bindCallerVerification(RemoteViews contentView, StandardTemplateParams p) { String iconContentDescription = null; boolean showDivider = true; @@ -12121,7 +12147,7 @@ public class Notification implements Parcelable boolean mHideProgress; boolean mHideSnoozeButton; boolean mPromotePicture; - boolean mAllowActionIcons; + boolean mCallStyleActions; boolean mAllowTextWithProgress; CharSequence title; CharSequence text; @@ -12140,7 +12166,7 @@ public class Notification implements Parcelable mHideProgress = false; mHideSnoozeButton = false; mPromotePicture = false; - mAllowActionIcons = false; + mCallStyleActions = false; mAllowTextWithProgress = false; title = null; text = null; @@ -12181,8 +12207,8 @@ public class Notification implements Parcelable return this; } - final StandardTemplateParams allowActionIcons(boolean allowActionIcons) { - this.mAllowActionIcons = allowActionIcons; + final StandardTemplateParams callStyleActions(boolean callStyleActions) { + this.mCallStyleActions = callStyleActions; return this; } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 6f39fea5dd95..0cc9f9e150c6 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -134,7 +134,6 @@ import android.app.AlarmManager; import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.AutomaticZenRule; -import android.app.BroadcastOptions; import android.app.IActivityManager; import android.app.INotificationManager; import android.app.ITransientNotification; @@ -6082,6 +6081,17 @@ public class NotificationManagerService extends SystemService { } } + // Ensure CallStyle has all the correct actions + if ("android.app.Notification$CallStyle".equals( + notification.extras.getString(Notification.EXTRA_TEMPLATE))) { + Notification.Builder builder = + Notification.Builder.recoverBuilder(getContext(), notification); + Notification.CallStyle style = (Notification.CallStyle) builder.getStyle(); + List<Notification.Action> actions = style.getActionsListWithSystemActions(); + notification.actions = new Notification.Action[actions.size()]; + actions.toArray(notification.actions); + } + // Remote views? Are they too big? checkRemoteViews(pkg, tag, id, notification); } |