Merge "Remove Notification.DevFlags" into sc-dev

This commit is contained in:
Jeff DeCew
2021-03-23 19:50:27 +00:00
committed by Android (Google) Code Review
4 changed files with 48 additions and 188 deletions

View File

@@ -39,7 +39,6 @@ import android.annotation.StringRes;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.LocusId;
@@ -5217,8 +5216,7 @@ public class Notification implements Parcelable
R.dimen.notification_right_icon_size) / density;
float viewWidthDp = viewHeightDp; // icons are 1:1 by default
if (largeIconShown && (p.mPromotePicture
|| mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.S
|| DevFlags.shouldBackportSNotifRules(mContext.getContentResolver()))) {
|| mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.S)) {
Drawable drawable = mN.mLargeIcon.loadDrawable(mContext);
if (drawable != null) {
int iconWidth = drawable.getIntrinsicWidth();
@@ -5662,55 +5660,45 @@ public class Notification implements Parcelable
if (fromStyle && PLATFORM_STYLE_CLASSES.contains(mStyle.getClass())) {
return false;
}
final ContentResolver contentResolver = mContext.getContentResolver();
final int decorationType = DevFlags.getFullyCustomViewNotifDecoration(contentResolver);
return decorationType != DevFlags.DECORATION_NONE
&& (DevFlags.shouldBackportSNotifRules(contentResolver)
|| mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.S);
return mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.S;
}
private RemoteViews minimallyDecoratedContentView(@NonNull RemoteViews customContent) {
int decorationType =
DevFlags.getFullyCustomViewNotifDecoration(mContext.getContentResolver());
StandardTemplateParams p = mParams.reset()
.viewType(StandardTemplateParams.VIEW_TYPE_NORMAL)
.decorationType(decorationType)
.decorationType(StandardTemplateParams.DECORATION_MINIMAL)
.fillTextsFrom(this);
TemplateBindResult result = new TemplateBindResult();
RemoteViews standard = applyStandardTemplate(getBaseLayoutResource(), p, result);
buildCustomContentIntoTemplate(mContext, standard, customContent,
p, result, decorationType);
p, result);
return standard;
}
private RemoteViews minimallyDecoratedBigContentView(@NonNull RemoteViews customContent) {
int decorationType =
DevFlags.getFullyCustomViewNotifDecoration(mContext.getContentResolver());
StandardTemplateParams p = mParams.reset()
.viewType(StandardTemplateParams.VIEW_TYPE_BIG)
.decorationType(decorationType)
.decorationType(StandardTemplateParams.DECORATION_MINIMAL)
.fillTextsFrom(this);
TemplateBindResult result = new TemplateBindResult();
RemoteViews standard = applyStandardTemplateWithActions(getBigBaseLayoutResource(),
p, result);
buildCustomContentIntoTemplate(mContext, standard, customContent,
p, result, decorationType);
p, result);
return standard;
}
private RemoteViews minimallyDecoratedHeadsUpContentView(
@NonNull RemoteViews customContent) {
int decorationType =
DevFlags.getFullyCustomViewNotifDecoration(mContext.getContentResolver());
StandardTemplateParams p = mParams.reset()
.viewType(StandardTemplateParams.VIEW_TYPE_HEADS_UP)
.decorationType(decorationType)
.decorationType(StandardTemplateParams.DECORATION_MINIMAL)
.fillTextsFrom(this);
TemplateBindResult result = new TemplateBindResult();
RemoteViews standard = applyStandardTemplateWithActions(getHeadsUpBaseLayoutResource(),
p, result);
buildCustomContentIntoTemplate(mContext, standard, customContent,
p, result, decorationType);
p, result);
return standard;
}
@@ -5769,12 +5757,6 @@ public class Notification implements Parcelable
.fillTextsFrom(this);
result = applyStandardTemplateWithActions(getBigBaseLayoutResource(), p,
null /* result */);
} else if (DevFlags.shouldBackportSNotifRules(mContext.getContentResolver())
&& useExistingRemoteView()
&& fullyCustomViewRequiresDecoration(false /* fromStyle */)) {
// This "backport" logic is a special case to handle the UNDO style of notif
// so that we can see what that will look like when the app targets S.
result = minimallyDecoratedBigContentView(mN.contentView);
}
}
makeHeaderExpanded(result);
@@ -6864,24 +6846,18 @@ public class Notification implements Parcelable
private static void buildCustomContentIntoTemplate(@NonNull Context context,
@NonNull RemoteViews template, @Nullable RemoteViews customContent,
@NonNull StandardTemplateParams p, @NonNull TemplateBindResult result,
int decorationType) {
@NonNull StandardTemplateParams p, @NonNull TemplateBindResult result) {
int childIndex = -1;
if (customContent != null) {
// Need to clone customContent before adding, because otherwise it can no longer be
// parceled independently of remoteViews.
customContent = customContent.clone();
if (p.mHeaderless) {
if (decorationType <= DevFlags.DECORATION_PARTIAL) {
template.removeFromParent(R.id.notification_top_line);
}
// The vertical margins are bigger in the "two-line" scenario than the "one-line"
// scenario, but the 'compatible' decoration state is intended to have 3 lines,
// (1 for the top line views and 2 for the custom views), so in that one case we
// use the smaller 1-line margins. This gives the compatible case 88-16*2=56 dp of
// height, 24dp of which goes to the top line, leaving 32dp for the custom view.
boolean hasSecondLine = decorationType != DevFlags.DECORATION_FULL_COMPATIBLE;
Builder.setHeaderlessVerticalMargins(template, p, hasSecondLine);
template.removeFromParent(R.id.notification_top_line);
// We do not know how many lines ar emote view has, so we presume it has 2; this
// ensures that we don't under-pad the content, which could lead to abuse, at the
// cost of making single-line custom content over-padded.
Builder.setHeaderlessVerticalMargins(template, p, true /* hasSecondLine */);
} else {
// also update the end margin to account for the large icon or expander
Resources resources = context.getResources();
@@ -9042,8 +9018,7 @@ public class Notification implements Parcelable
template.setViewVisibility(R.id.media_actions, hasActions ? View.VISIBLE : View.GONE);
// Add custom view if provided by subclass.
buildCustomContentIntoTemplate(mBuilder.mContext, template, customContent, p, result,
DevFlags.DECORATION_PARTIAL);
buildCustomContentIntoTemplate(mBuilder.mContext, template, customContent, p, result);
return template;
}
@@ -9066,8 +9041,7 @@ public class Notification implements Parcelable
template.setViewVisibility(MEDIA_BUTTON_IDS[i], View.GONE);
}
}
buildCustomContentIntoTemplate(mBuilder.mContext, template, customContent, p, result,
DevFlags.DECORATION_PARTIAL);
buildCustomContentIntoTemplate(mBuilder.mContext, template, customContent, p, result);
return template;
}
}
@@ -9644,16 +9618,15 @@ public class Notification implements Parcelable
if (mBuilder.mActions.size() == 0) {
return makeStandardTemplateWithCustomContent(headsUpContentView);
}
int decorationType = getDecorationType();
TemplateBindResult result = new TemplateBindResult();
StandardTemplateParams p = mBuilder.mParams.reset()
.viewType(StandardTemplateParams.VIEW_TYPE_HEADS_UP)
.decorationType(decorationType)
.decorationType(StandardTemplateParams.DECORATION_PARTIAL)
.fillTextsFrom(mBuilder);
RemoteViews remoteViews = mBuilder.applyStandardTemplateWithActions(
mBuilder.getHeadsUpBaseLayoutResource(), p, result);
buildCustomContentIntoTemplate(mBuilder.mContext, remoteViews, headsUpContentView,
p, result, decorationType);
p, result);
return remoteViews;
}
@@ -9661,16 +9634,15 @@ public class Notification implements Parcelable
if (customContent == null) {
return null; // no custom view; use the default behavior
}
int decorationType = getDecorationType();
TemplateBindResult result = new TemplateBindResult();
StandardTemplateParams p = mBuilder.mParams.reset()
.viewType(StandardTemplateParams.VIEW_TYPE_NORMAL)
.decorationType(decorationType)
.decorationType(StandardTemplateParams.DECORATION_PARTIAL)
.fillTextsFrom(mBuilder);
RemoteViews remoteViews = mBuilder.applyStandardTemplate(
mBuilder.getBaseLayoutResource(), p, result);
buildCustomContentIntoTemplate(mBuilder.mContext, remoteViews, customContent,
p, result, decorationType);
p, result);
return remoteViews;
}
@@ -9681,24 +9653,18 @@ public class Notification implements Parcelable
if (bigContentView == null) {
return null; // no custom view; use the default behavior
}
int decorationType = getDecorationType();
TemplateBindResult result = new TemplateBindResult();
StandardTemplateParams p = mBuilder.mParams.reset()
.viewType(StandardTemplateParams.VIEW_TYPE_BIG)
.decorationType(decorationType)
.decorationType(StandardTemplateParams.DECORATION_PARTIAL)
.fillTextsFrom(mBuilder);
RemoteViews remoteViews = mBuilder.applyStandardTemplateWithActions(
mBuilder.getBigBaseLayoutResource(), p, result);
buildCustomContentIntoTemplate(mBuilder.mContext, remoteViews, bigContentView,
p, result, decorationType);
p, result);
return remoteViews;
}
private int getDecorationType() {
ContentResolver contentResolver = mBuilder.mContext.getContentResolver();
return DevFlags.getDecoratedCustomViewNotifDecoration(contentResolver);
}
/**
* @hide
*/
@@ -12091,6 +12057,22 @@ public class Notification implements Parcelable
}
private static class StandardTemplateParams {
/**
* Notifications will be minimally decorated with ONLY an icon and expander:
* <li>A large icon is never shown.
* <li>A progress bar is never shown.
* <li>The expanded and heads up states do not show actions, even if provided.
*/
public static final int DECORATION_MINIMAL = 1;
/**
* Notifications will be partially decorated with AT LEAST an icon and expander:
* <li>A large icon is shown if provided.
* <li>A progress bar is shown if provided and enough space remains below the content.
* <li>Actions are shown in the expanded and heads up states.
*/
public static final int DECORATION_PARTIAL = 2;
public static int VIEW_TYPE_UNSPECIFIED = 0;
public static int VIEW_TYPE_NORMAL = 1;
public static int VIEW_TYPE_BIG = 2;
@@ -12276,112 +12258,20 @@ public class Notification implements Parcelable
}
public StandardTemplateParams decorationType(int decorationType) {
boolean hideTitle = decorationType <= DevFlags.DECORATION_FULL_COMPATIBLE;
boolean hideOtherFields = decorationType <= DevFlags.DECORATION_MINIMAL;
hideTitle(hideTitle);
// These fields are removed by the decoration process, and thus would not show anyway;
// hiding them is a minimal time/space optimization.
hideAppName(true);
hideTitle(true);
hideSubText(true);
hideTime(true);
// Minimally decorated custom views do not show certain pieces of chrome that have
// always been shown when using DecoratedCustomViewStyle.
boolean hideOtherFields = decorationType <= DECORATION_MINIMAL;
hideLargeIcon(hideOtherFields);
hideProgress(hideOtherFields);
hideActions(hideOtherFields);
hideSnoozeButton(hideOtherFields);
return this;
}
}
/**
* A class to centrally access various developer flags related to notifications.
* This class is a non-final wrapper around Settings.Global which allows mocking for unit tests.
* TODO(b/176239013): Try to remove this before shipping S
* @hide
*/
public static class DevFlags {
/**
* Notifications will not be decorated. The custom content will be shown as-is.
*
* <p>NOTE: This option is not available for notifications with DecoratedCustomViewStyle,
* as that API contract includes decorations that this does not provide.
*/
public static final int DECORATION_NONE = 0;
/**
* Notifications will be minimally decorated with ONLY an icon and expander as follows:
* <li>A large icon is never shown.
* <li>A progress bar is never shown.
* <li>The expanded and heads up states do not show actions, even if provided.
* <li>The collapsed state gives the app's custom content 48dp of vertical space.
* <li>The collapsed state does NOT include the top line of views,
* like the alerted icon or work profile badge.
*
* <p>NOTE: This option is not available for notifications with DecoratedCustomViewStyle,
* as that API contract includes decorations that this does not provide.
*/
public static final int DECORATION_MINIMAL = 1;
/**
* Notifications will be partially decorated with AT LEAST an icon and expander as follows:
* <li>A large icon is shown if provided.
* <li>A progress bar is shown if provided and enough space remains below the content.
* <li>Actions are shown in the expanded and heads up states.
* <li>The collapsed state gives the app's custom content 48dp of vertical space.
* <li>The collapsed state does NOT include the top line of views,
* like the alerted icon or work profile badge.
*/
public static final int DECORATION_PARTIAL = 2;
/**
* Notifications will be fully decorated as follows:
* <li>A large icon is shown if provided.
* <li>A progress bar is shown if provided and enough space remains below the content.
* <li>Actions are shown in the expanded and heads up states.
* <li>The collapsed state gives the app's custom content 40dp of vertical space.
* <li>The collapsed state DOES include the top line of views,
* like the alerted icon or work profile badge.
* <li>The collapsed state's top line views will never show the title text.
*/
public static final int DECORATION_FULL_COMPATIBLE = 3;
/**
* Notifications will be fully decorated as follows:
* <li>A large icon is shown if provided.
* <li>A progress bar is shown if provided and enough space remains below the content.
* <li>Actions are shown in the expanded and heads up states.
* <li>The collapsed state gives the app's custom content 20dp of vertical space.
* <li>The collapsed state DOES include the top line of views
* like the alerted icon or work profile badge.
* <li>The collapsed state's top line views will contain the title text if provided.
*/
public static final int DECORATION_FULL_CONSTRAINED = 4;
/**
* Used by unit tests to force that this class returns its default values, which is required
* in cases where the ContentResolver instance is a mock.
* @hide
*/
public static boolean sForceDefaults;
/**
* @return if the S notification rules should be backported to apps not yet targeting S
* @hide
*/
public static boolean shouldBackportSNotifRules(@NonNull ContentResolver contentResolver) {
return false;
}
/**
* @return the decoration type to be applied to notifications with fully custom view.
* @hide
*/
public static int getFullyCustomViewNotifDecoration(
@NonNull ContentResolver contentResolver) {
return DECORATION_MINIMAL;
}
/**
* @return the decoration type to be applied to notifications with DecoratedCustomViewStyle.
* @hide
*/
public static int getDecoratedCustomViewNotifDecoration(
@NonNull ContentResolver contentResolver) {
return DECORATION_PARTIAL;
}
}
}

View File

@@ -656,11 +656,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
boolean beforeP = mEntry.targetSdk < Build.VERSION_CODES.P;
boolean beforeS = mEntry.targetSdk < Build.VERSION_CODES.S;
if (Notification.DevFlags.shouldBackportSNotifRules(mContext.getContentResolver())) {
// When back-porting S rules, if an app targets P/Q/R then enforce the new S rule on
// that notification. If it's before P though, we still want to enforce legacy rules.
beforeS = beforeP;
}
int smallHeight;
View expandedView = layout.getExpandedChild();

View File

@@ -125,9 +125,7 @@ import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.internal.util.collections.Sets;
@@ -222,16 +220,6 @@ public class DevicePolicyManagerTest extends DpmTestBase {
private static final String PROFILE_OFF_SUSPENSION_TEXT = "suspension_text";
private static final String PROFILE_OFF_SUSPENSION_SOON_TEXT = "suspension_tomorrow_text";
@BeforeClass
public static void setUpClass() {
Notification.DevFlags.sForceDefaults = true;
}
@AfterClass
public static void tearDownClass() {
Notification.DevFlags.sForceDefaults = false;
}
@Before
public void setUp() throws Exception {

View File

@@ -50,9 +50,7 @@ import com.android.connectivity.resources.R;
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -104,17 +102,6 @@ public class NetworkNotificationManagerTest {
NetworkNotificationManager mManager;
@BeforeClass
public static void setUpClass() {
Notification.DevFlags.sForceDefaults = true;
}
@AfterClass
public static void tearDownClass() {
Notification.DevFlags.sForceDefaults = false;
}
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);