Merge "CallStyle notifications now include their adjusted actions in the actions list." into sc-dev
This commit is contained in:
@@ -5445,8 +5445,12 @@ public class Notification implements Parcelable
|
|||||||
return p.allowColorization && mN.isColorized();
|
return p.allowColorization && mN.isColorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isCallActionColorCustomizable(StandardTemplateParams p) {
|
private boolean isCallActionColorCustomizable() {
|
||||||
return isColorized(p) && mContext.getResources().getBoolean(
|
// 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);
|
R.bool.config_callNotificationActionColorsRequireColorized);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5512,13 +5516,13 @@ public class Notification implements Parcelable
|
|||||||
*/
|
*/
|
||||||
private @NonNull List<Notification.Action> getNonContextualActions() {
|
private @NonNull List<Notification.Action> getNonContextualActions() {
|
||||||
if (mActions == null) return Collections.emptyList();
|
if (mActions == null) return Collections.emptyList();
|
||||||
List<Notification.Action> contextualActions = new ArrayList<>();
|
List<Notification.Action> standardActions = new ArrayList<>();
|
||||||
for (Notification.Action action : mActions) {
|
for (Notification.Action action : mActions) {
|
||||||
if (!action.isContextual()) {
|
if (!action.isContextual()) {
|
||||||
contextualActions.add(action);
|
standardActions.add(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return contextualActions;
|
return standardActions;
|
||||||
}
|
}
|
||||||
|
|
||||||
private RemoteViews applyStandardTemplateWithActions(int layoutId,
|
private RemoteViews applyStandardTemplateWithActions(int layoutId,
|
||||||
@@ -5538,16 +5542,29 @@ public class Notification implements Parcelable
|
|||||||
// filter them out here.
|
// filter them out here.
|
||||||
List<Notification.Action> nonContextualActions = getNonContextualActions();
|
List<Notification.Action> nonContextualActions = getNonContextualActions();
|
||||||
|
|
||||||
int N = nonContextualActions.size();
|
int numActions = Math.min(nonContextualActions.size(), MAX_ACTION_BUTTONS);
|
||||||
boolean emphazisedMode = mN.fullScreenIntent != null;
|
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);
|
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_container, View.VISIBLE);
|
||||||
big.setViewVisibility(R.id.actions, View.VISIBLE);
|
big.setViewVisibility(R.id.actions, View.VISIBLE);
|
||||||
big.setViewLayoutMarginDimen(R.id.notification_action_list_margin_target,
|
big.setViewLayoutMarginDimen(R.id.notification_action_list_margin_target,
|
||||||
RemoteViews.MARGIN_BOTTOM, 0);
|
RemoteViews.MARGIN_BOTTOM, 0);
|
||||||
if (N>MAX_ACTION_BUTTONS) N=MAX_ACTION_BUTTONS;
|
for (int i = 0; i < numActions; i++) {
|
||||||
for (int i=0; i<N; i++) {
|
|
||||||
Action action = nonContextualActions.get(i);
|
Action action = nonContextualActions.get(i);
|
||||||
|
|
||||||
boolean actionHasValidInput = hasValidRemoteInput(action);
|
boolean actionHasValidInput = hasValidRemoteInput(action);
|
||||||
@@ -5558,6 +5575,11 @@ public class Notification implements Parcelable
|
|||||||
// Clear the drawable
|
// Clear the drawable
|
||||||
button.setInt(R.id.action0, "setBackgroundResource", 0);
|
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);
|
big.addView(R.id.actions, button);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -6019,7 +6041,7 @@ public class Notification implements Parcelable
|
|||||||
button.setColorStateList(R.id.action0, "setButtonBackground",
|
button.setColorStateList(R.id.action0, "setButtonBackground",
|
||||||
ColorStateList.valueOf(background));
|
ColorStateList.valueOf(background));
|
||||||
button.setBoolean(R.id.action0, "setHasStroke", !hasColorOverride);
|
button.setBoolean(R.id.action0, "setHasStroke", !hasColorOverride);
|
||||||
if (p.mAllowActionIcons) {
|
if (p.mCallStyleActions) {
|
||||||
button.setImageViewIcon(R.id.action0, action.getIcon());
|
button.setImageViewIcon(R.id.action0, action.getIcon());
|
||||||
boolean priority = action.getExtras().getBoolean(CallStyle.KEY_ACTION_PRIORITY);
|
boolean priority = action.getExtras().getBoolean(CallStyle.KEY_ACTION_PRIORITY);
|
||||||
button.setBoolean(R.id.action0, "setWrapModePriority", priority);
|
button.setBoolean(R.id.action0, "setWrapModePriority", priority);
|
||||||
@@ -9265,6 +9287,17 @@ public class Notification implements Parcelable
|
|||||||
return this;
|
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
|
* @hide
|
||||||
*/
|
*/
|
||||||
@@ -9324,14 +9357,14 @@ public class Notification implements Parcelable
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private Action makeNegativeAction(@NonNull StandardTemplateParams p) {
|
private Action makeNegativeAction() {
|
||||||
if (mDeclineIntent == null) {
|
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,
|
R.string.call_notification_hang_up_action,
|
||||||
mDeclineButtonColor, R.color.call_notification_decline_color,
|
mDeclineButtonColor, R.color.call_notification_decline_color,
|
||||||
mHangUpIntent);
|
mHangUpIntent);
|
||||||
} else {
|
} else {
|
||||||
return makeAction(p, R.drawable.ic_call_decline,
|
return makeAction(R.drawable.ic_call_decline,
|
||||||
R.string.call_notification_decline_action,
|
R.string.call_notification_decline_action,
|
||||||
mDeclineButtonColor, R.color.call_notification_decline_color,
|
mDeclineButtonColor, R.color.call_notification_decline_color,
|
||||||
mDeclineIntent);
|
mDeclineIntent);
|
||||||
@@ -9339,18 +9372,17 @@ public class Notification implements Parcelable
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private Action makeAnswerAction(@NonNull StandardTemplateParams p) {
|
private Action makeAnswerAction() {
|
||||||
return mAnswerIntent == null ? null : makeAction(p, R.drawable.ic_call_answer,
|
return mAnswerIntent == null ? null : makeAction(R.drawable.ic_call_answer,
|
||||||
R.string.call_notification_answer_action,
|
R.string.call_notification_answer_action,
|
||||||
mAnswerButtonColor, R.color.call_notification_answer_color,
|
mAnswerButtonColor, R.color.call_notification_answer_color,
|
||||||
mAnswerIntent);
|
mAnswerIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private Action makeAction(@NonNull StandardTemplateParams p,
|
private Action makeAction(@DrawableRes int icon, @StringRes int title,
|
||||||
@DrawableRes int icon, @StringRes int title,
|
|
||||||
@ColorInt Integer colorInt, @ColorRes int defaultColorRes, PendingIntent intent) {
|
@ColorInt Integer colorInt, @ColorRes int defaultColorRes, PendingIntent intent) {
|
||||||
if (colorInt == null || !mBuilder.isCallActionColorCustomizable(p)) {
|
if (colorInt == null || !mBuilder.isCallActionColorCustomizable()) {
|
||||||
colorInt = mBuilder.mContext.getColor(defaultColorRes);
|
colorInt = mBuilder.mContext.getColor(defaultColorRes);
|
||||||
}
|
}
|
||||||
Action action = new Action.Builder(Icon.createWithResource("", icon),
|
Action action = new Action.Builder(Icon.createWithResource("", icon),
|
||||||
@@ -9362,29 +9394,62 @@ public class Notification implements Parcelable
|
|||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArrayList<Action> makeActionsList(@NonNull StandardTemplateParams p) {
|
private boolean isActionAddedByCallStyle(Action action) {
|
||||||
final Action negativeAction = makeNegativeAction(p);
|
// This is an internal extra added by the style to these actions. If an app were to add
|
||||||
final Action answerAction = makeAnswerAction(p);
|
// 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;
|
* Gets the actions list for the call with the answer/decline/hangUp actions inserted in
|
||||||
if (answerAction == null) {
|
* the correct place. This returns the correct result even if the system actions have
|
||||||
// If there's no answer action, put the hang up / decline action at the end
|
* already been added, and even if more actions were added since then.
|
||||||
lastAction = negativeAction;
|
* @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 {
|
} else {
|
||||||
// Otherwise put the answer action at the end, and put the decline action at start.
|
// Copy non-contextual actions; decrement the remaining action slots.
|
||||||
actions.add(negativeAction);
|
resultActions.add(action);
|
||||||
lastAction = answerAction;
|
--nonContextualActionSlotsRemaining;
|
||||||
}
|
}
|
||||||
// For consistency with the standard actions bar, contextual actions are ignored.
|
// If there's exactly one action slot left, fill it with the lastAction.
|
||||||
for (Action action : mBuilder.getNonContextualActions()) {
|
if (nonContextualActionSlotsRemaining == 1) {
|
||||||
if (actions.size() >= MAX_ACTION_BUTTONS - 1) {
|
resultActions.add(lastAction);
|
||||||
break;
|
--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() {
|
private RemoteViews makeCallLayout() {
|
||||||
@@ -9397,19 +9462,15 @@ public class Notification implements Parcelable
|
|||||||
// Bind standard template
|
// Bind standard template
|
||||||
StandardTemplateParams p = mBuilder.mParams.reset()
|
StandardTemplateParams p = mBuilder.mParams.reset()
|
||||||
.viewType(StandardTemplateParams.VIEW_TYPE_BIG)
|
.viewType(StandardTemplateParams.VIEW_TYPE_BIG)
|
||||||
.allowActionIcons(true)
|
.callStyleActions(true)
|
||||||
.allowTextWithProgress(true)
|
.allowTextWithProgress(true)
|
||||||
.hideLargeIcon(true)
|
.hideLargeIcon(true)
|
||||||
.text(text)
|
.text(text)
|
||||||
.summaryText(mBuilder.processLegacyText(mVerificationText));
|
.summaryText(mBuilder.processLegacyText(mVerificationText));
|
||||||
RemoteViews contentView = mBuilder.applyStandardTemplate(
|
mBuilder.mActions = getActionsListWithSystemActions();
|
||||||
|
RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(
|
||||||
mBuilder.getCallLayoutResource(), p, null /* result */);
|
mBuilder.getCallLayoutResource(), p, null /* result */);
|
||||||
|
|
||||||
// Bind actions.
|
|
||||||
mBuilder.resetStandardTemplateWithActions(contentView);
|
|
||||||
mBuilder.bindSnoozeAction(contentView, p);
|
|
||||||
bindCallActions(contentView, p);
|
|
||||||
|
|
||||||
// Bind some extra conversation-specific header fields.
|
// Bind some extra conversation-specific header fields.
|
||||||
mBuilder.setTextViewColorPrimary(contentView, R.id.conversation_text, p);
|
mBuilder.setTextViewColorPrimary(contentView, R.id.conversation_text, p);
|
||||||
mBuilder.setTextViewColorSecondary(contentView, R.id.app_name_divider, p);
|
mBuilder.setTextViewColorSecondary(contentView, R.id.app_name_divider, p);
|
||||||
@@ -9429,41 +9490,6 @@ public class Notification implements Parcelable
|
|||||||
return contentView;
|
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) {
|
private void bindCallerVerification(RemoteViews contentView, StandardTemplateParams p) {
|
||||||
String iconContentDescription = null;
|
String iconContentDescription = null;
|
||||||
boolean showDivider = true;
|
boolean showDivider = true;
|
||||||
@@ -12121,7 +12147,7 @@ public class Notification implements Parcelable
|
|||||||
boolean mHideProgress;
|
boolean mHideProgress;
|
||||||
boolean mHideSnoozeButton;
|
boolean mHideSnoozeButton;
|
||||||
boolean mPromotePicture;
|
boolean mPromotePicture;
|
||||||
boolean mAllowActionIcons;
|
boolean mCallStyleActions;
|
||||||
boolean mAllowTextWithProgress;
|
boolean mAllowTextWithProgress;
|
||||||
CharSequence title;
|
CharSequence title;
|
||||||
CharSequence text;
|
CharSequence text;
|
||||||
@@ -12140,7 +12166,7 @@ public class Notification implements Parcelable
|
|||||||
mHideProgress = false;
|
mHideProgress = false;
|
||||||
mHideSnoozeButton = false;
|
mHideSnoozeButton = false;
|
||||||
mPromotePicture = false;
|
mPromotePicture = false;
|
||||||
mAllowActionIcons = false;
|
mCallStyleActions = false;
|
||||||
mAllowTextWithProgress = false;
|
mAllowTextWithProgress = false;
|
||||||
title = null;
|
title = null;
|
||||||
text = null;
|
text = null;
|
||||||
@@ -12181,8 +12207,8 @@ public class Notification implements Parcelable
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
final StandardTemplateParams allowActionIcons(boolean allowActionIcons) {
|
final StandardTemplateParams callStyleActions(boolean callStyleActions) {
|
||||||
this.mAllowActionIcons = allowActionIcons;
|
this.mCallStyleActions = callStyleActions;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -134,7 +134,6 @@ import android.app.AlarmManager;
|
|||||||
import android.app.AppGlobals;
|
import android.app.AppGlobals;
|
||||||
import android.app.AppOpsManager;
|
import android.app.AppOpsManager;
|
||||||
import android.app.AutomaticZenRule;
|
import android.app.AutomaticZenRule;
|
||||||
import android.app.BroadcastOptions;
|
|
||||||
import android.app.IActivityManager;
|
import android.app.IActivityManager;
|
||||||
import android.app.INotificationManager;
|
import android.app.INotificationManager;
|
||||||
import android.app.ITransientNotification;
|
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?
|
// Remote views? Are they too big?
|
||||||
checkRemoteViews(pkg, tag, id, notification);
|
checkRemoteViews(pkg, tag, id, notification);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user