/*
* Copyright (C) 2015 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.support.v7.internal.app;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.SystemClock;
import android.support.v7.appcompat.R;
import android.support.v4.app.NotificationBuilderWithBuilderAccessor;
import android.support.v4.app.NotificationCompatBase;
import android.util.TypedValue;
import android.view.View;
import android.widget.RemoteViews;
import java.text.NumberFormat;
import java.util.List;
/**
* Helper class to generate MediaStyle notifications for pre-Lollipop platforms. Overrides
* contentView and bigContentView of the notification.
* @hide
*/
public class NotificationCompatImplBase {
static final int MAX_MEDIA_BUTTONS_IN_COMPACT = 3;
static final int MAX_MEDIA_BUTTONS = 5;
public static <T extends NotificationCompatBase.Action> void overrideContentView(
NotificationBuilderWithBuilderAccessor builder,
Context context, CharSequence contentTitle, CharSequence contentText,
CharSequence contentInfo, int number, Bitmap largeIcon, CharSequence subText,
boolean useChronometer, long when, List<T> actions, int[] actionsToShowInCompact,
boolean showCancelButton, PendingIntent cancelButtonIntent) {
RemoteViews views = generateContentView(context, contentTitle, contentText, contentInfo,
number, largeIcon, subText, useChronometer, when, actions, actionsToShowInCompact,
showCancelButton, cancelButtonIntent);
builder.getBuilder().setContent(views);
if (showCancelButton) {
builder.getBuilder().setOngoing(true);
}
}
private static <T extends NotificationCompatBase.Action> RemoteViews generateContentView(
Context context, CharSequence contentTitle, CharSequence contentText,
CharSequence contentInfo, int number, Bitmap largeIcon, CharSequence subText,
boolean useChronometer, long when, List<T> actions, int[] actionsToShowInCompact,
boolean showCancelButton, PendingIntent cancelButtonIntent) {
RemoteViews view = applyStandardTemplate(context, contentTitle, contentText, contentInfo,
number, largeIcon, subText, useChronometer, when,
R.layout.notification_template_media, true /* fitIn1U */);
final int numActions = actions.size();
final int N = actionsToShowInCompact == null
? 0
: Math.min(actionsToShowInCompact.length, MAX_MEDIA_BUTTONS_IN_COMPACT);
view.removeAllViews(R.id.media_actions);
if (N > 0) {
for (int i = 0; i < N; i++) {
if (i >= numActions) {
throw new IllegalArgumentException(String.format(
"setShowActionsInCompactView: action %d out of bounds (max %d)",
i, numActions - 1));
}
final NotificationCompatBase.Action action = actions.get(actionsToShowInCompact[i]);
final RemoteViews button = generateMediaActionButton(context, action);
view.addView(R.id.media_actions, button);
}
}
if (showCancelButton) {
view.setViewVisibility(R.id.end_padder, View.GONE);
view.setViewVisibility(R.id.cancel_action, View.VISIBLE);
view.setOnClickPendingIntent(R.id.cancel_action, cancelButtonIntent);
view.setInt(R.id.cancel_action, "setAlpha",
context.getResources().getInteger(R.integer.cancel_button_image_alpha));
} else {
view.setViewVisibility(R.id.end_padder, View.VISIBLE);
view.setViewVisibility(R.id.cancel_action, View.GONE);
}
return view;
}
public static <T extends NotificationCompatBase.Action> void overrideBigContentView(
Notification n, Context context, CharSequence contentTitle, CharSequence contentText,
CharSequence contentInfo, int number, Bitmap largeIcon, CharSequence subText,
boolean useChronometer, long when, List<T> actions, boolean showCancelButton,
PendingIntent cancelButtonIntent) {
n.bigContentView = generateBigContentView(context, contentTitle, contentText, contentInfo,
number, largeIcon, subText, useChronometer, when, actions, showCancelButton,
cancelButtonIntent);
if (showCancelButton) {
n.flags |= Notification.FLAG_ONGOING_EVENT;
}
}
private static <T extends NotificationCompatBase.Action> RemoteViews generateBigContentView(
Context context, CharSequence contentTitle, CharSequence contentText,
CharSequence contentInfo, int number, Bitmap largeIcon, CharSequence subText,
boolean useChronometer, long when, List<T> actions, boolean showCancelButton,
PendingIntent cancelButtonIntent) {
final int actionCount = Math.min(actions.size(), MAX_MEDIA_BUTTONS);
RemoteViews big = applyStandardTemplate(context, contentTitle, contentText, contentInfo,
number, largeIcon, subText, useChronometer, when,
getBigLayoutResource(actionCount), false /* fitIn1U */);
big.removeAllViews(R.id.media_actions);
if (actionCount > 0) {
for (int i = 0; i < actionCount; i++) {
final RemoteViews button = generateMediaActionButton(context, actions.get(i));
big.addView(R.id.media_actions, button);
}
}
if (showCancelButton) {
big.setViewVisibility(R.id.cancel_action, View.VISIBLE);
big.setInt(R.id.cancel_action, "setAlpha",
context.getResources().getInteger(R.integer.cancel_button_image_alpha));
big.setOnClickPendingIntent(R.id.cancel_action, cancelButtonIntent);
} else {
big.setViewVisibility(R.id.cancel_action, View.GONE);
}
return big;
}
private static RemoteViews generateMediaActionButton(Context context,
NotificationCompatBase.Action action) {
final boolean tombstone = (action.getActionIntent() == null);
RemoteViews button = new RemoteViews(context.getPackageName(),
R.layout.notification_media_action);
button.setImageViewResource(R.id.action0, action.getIcon());
if (!tombstone) {
button.setOnClickPendingIntent(R.id.action0, action.getActionIntent());
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
button.setContentDescription(R.id.action0, action.getTitle());
}
return button;
}
private static int getBigLayoutResource(int actionCount) {
if (actionCount <= 3) {
return R.layout.notification_template_big_media_narrow;
} else {
return R.layout.notification_template_big_media;
}
}
private static RemoteViews applyStandardTemplate(Context context,
CharSequence contentTitle, CharSequence contentText, CharSequence contentInfo,
int number, Bitmap largeIcon, CharSequence subText, boolean useChronometer, long when,
int resId, boolean fitIn1U) {
RemoteViews contentView = new RemoteViews(context.getPackageName(), resId);
boolean showLine3 = false;
boolean showLine2 = false;
// On versions before Jellybean, the large icon was shown by SystemUI, so we need to hide
// it here.
if (largeIcon != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
contentView.setImageViewBitmap(R.id.icon, largeIcon);
} else {
contentView.setViewVisibility(R.id.icon, View.GONE);
}
if (contentTitle != null) {
contentView.setTextViewText(R.id.title, contentTitle);
}
if (contentText != null) {
contentView.setTextViewText(R.id.text, contentText);
showLine3 = true;
}
if (contentInfo != null) {
contentView.setTextViewText(R.id.info, contentInfo);
contentView.setViewVisibility(R.id.info, View.VISIBLE);
showLine3 = true;
} else if (number > 0) {
final int tooBig = context.getResources().getInteger(
R.integer.status_bar_notification_info_maxnum);
if (number > tooBig) {
contentView.setTextViewText(R.id.info, context.getResources().getString(
R.string.status_bar_notification_info_overflow));
} else {
NumberFormat f = NumberFormat.getIntegerInstance();
contentView.setTextViewText(R.id.info, f.format(number));
}
contentView.setViewVisibility(R.id.info, View.VISIBLE);
showLine3 = true;
} else {
contentView.setViewVisibility(R.id.info, View.GONE);
}
// Need to show three lines? Only allow on Jellybean+
if (subText != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
contentView.setTextViewText(R.id.text, subText);
if (contentText != null) {
contentView.setTextViewText(R.id.text2, contentText);
contentView.setViewVisibility(R.id.text2, View.VISIBLE);
showLine2 = true;
} else {
contentView.setViewVisibility(R.id.text2, View.GONE);
}
}
// RemoteViews.setViewPadding and RemoteViews.setTextViewTextSize is not available on ICS-
if (showLine2 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
if (fitIn1U) {
// need to shrink all the type to make sure everything fits
final Resources res = context.getResources();
final float subTextSize = res.getDimensionPixelSize(
R.dimen.notification_subtext_size);
contentView.setTextViewTextSize(R.id.text, TypedValue.COMPLEX_UNIT_PX, subTextSize);
}
// vertical centering
contentView.setViewPadding(R.id.line1, 0, 0, 0, 0);
}
if (when != 0) {
if (useChronometer) {
contentView.setViewVisibility(R.id.chronometer, View.VISIBLE);
contentView.setLong(R.id.chronometer, "setBase",
when + (SystemClock.elapsedRealtime() - System.currentTimeMillis()));
contentView.setBoolean(R.id.chronometer, "setStarted", true);
} else {
contentView.setViewVisibility(R.id.time, View.VISIBLE);
contentView.setLong(R.id.time, "setTime", when);
}
}
contentView.setViewVisibility(R.id.line3, showLine3 ? View.VISIBLE : View.GONE);
return contentView;
}
}