Merge "Remove Activity Recognition from the Android Code."
diff --git a/Android.mk b/Android.mk
index e3cc275..9f7bf99 100644
--- a/Android.mk
+++ b/Android.mk
@@ -80,6 +80,8 @@
# ==== hiddenapi lists =======================================
.KATI_RESTAT: $(INTERNAL_PLATFORM_HIDDENAPI_FLAGS)
$(INTERNAL_PLATFORM_HIDDENAPI_FLAGS): \
+ PRIVATE_FLAGS_INPUTS := $(PRIVATE_FLAGS_INPUTS) $(SOONG_HIDDENAPI_FLAGS)
+$(INTERNAL_PLATFORM_HIDDENAPI_FLAGS): \
frameworks/base/tools/hiddenapi/generate_hiddenapi_lists.py \
frameworks/base/config/hiddenapi-greylist.txt \
frameworks/base/config/hiddenapi-greylist-max-p.txt \
@@ -87,7 +89,8 @@
frameworks/base/config/hiddenapi-force-blacklist.txt \
$(INTERNAL_PLATFORM_HIDDENAPI_PUBLIC_LIST) \
$(INTERNAL_PLATFORM_HIDDENAPI_PRIVATE_LIST) \
- $(INTERNAL_PLATFORM_REMOVED_DEX_API_FILE)
+ $(INTERNAL_PLATFORM_REMOVED_DEX_API_FILE) \
+ $(SOONG_HIDDENAPI_FLAGS)
frameworks/base/tools/hiddenapi/generate_hiddenapi_lists.py \
--public $(INTERNAL_PLATFORM_HIDDENAPI_PUBLIC_LIST) \
--private $(INTERNAL_PLATFORM_HIDDENAPI_PRIVATE_LIST) \
diff --git a/api/current.txt b/api/current.txt
index 02d703f..e7c9b24 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -24027,6 +24027,7 @@
method public android.view.Surface getSurface();
method public int getWidth();
method public static android.media.ImageReader newInstance(int, int, int, int);
+ method public static android.media.ImageReader newInstance(int, int, int, int, long);
method public void setOnImageAvailableListener(android.media.ImageReader.OnImageAvailableListener, android.os.Handler);
}
@@ -24040,6 +24041,7 @@
method public int getFormat();
method public int getMaxImages();
method public static android.media.ImageWriter newInstance(android.view.Surface, int);
+ method public static android.media.ImageWriter newInstance(android.view.Surface, int, int);
method public void queueInputImage(android.media.Image);
method public void setOnImageReleasedListener(android.media.ImageWriter.OnImageReleasedListener, android.os.Handler);
}
@@ -52681,7 +52683,6 @@
method public final void notifyViewDisappeared(android.view.autofill.AutofillId);
method public final void notifyViewTextChanged(android.view.autofill.AutofillId, java.lang.CharSequence, int);
method public final void notifyViewsDisappeared(android.view.autofill.AutofillId, int[]);
- field public static final int FLAG_USER_INPUT = 1; // 0x1
}
public final class ContentCaptureSessionId implements android.os.Parcelable {
diff --git a/api/system-current.txt b/api/system-current.txt
index d179bde..e9743f7 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1336,7 +1336,7 @@
}
public class CrossProfileApps {
- method public void startAnyActivity(android.content.ComponentName, android.os.UserHandle);
+ method public void startActivity(android.content.ComponentName, android.os.UserHandle);
}
public final class InstantAppInfo implements android.os.Parcelable {
@@ -2901,6 +2901,7 @@
method public int getConstellationType();
method public float getExcessPathLengthMeters();
method public float getExcessPathLengthUncertaintyMeters();
+ method public float getProbSatIsLos();
method public android.location.GnssReflectingPlane getReflectingPlane();
method public int getSatId();
method public int getSingleSatCorrectionFlags();
@@ -2908,13 +2909,12 @@
method public boolean hasExcessPathLengthUncertainty();
method public boolean hasReflectingPlane();
method public boolean hasSatelliteLineOfSight();
- method public boolean isSatelliteLineOfSight();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssSingleSatCorrection> CREATOR;
field public static final int HAS_EXCESS_PATH_LENGTH_MASK = 2; // 0x2
field public static final int HAS_EXCESS_PATH_LENGTH_UNC_MASK = 4; // 0x4
+ field public static final int HAS_PROB_SAT_IS_LOS_MASK = 1; // 0x1
field public static final int HAS_REFLECTING_PLANE_MASK = 8; // 0x8
- field public static final int HAS_SAT_IS_LOS_MASK = 1; // 0x1
}
public static class GnssSingleSatCorrection.Builder {
@@ -2924,9 +2924,9 @@
method public android.location.GnssSingleSatCorrection.Builder setConstellationType(int);
method public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthMeters(float);
method public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthUncertaintyMeters(float);
+ method public android.location.GnssSingleSatCorrection.Builder setProbSatIsLos(float);
method public android.location.GnssSingleSatCorrection.Builder setReflectingPlane(android.location.GnssReflectingPlane);
method public android.location.GnssSingleSatCorrection.Builder setSatId(int);
- method public android.location.GnssSingleSatCorrection.Builder setSatIsLos(boolean);
method public android.location.GnssSingleSatCorrection.Builder setSingleSatCorrectionFlags(int);
}
@@ -3933,10 +3933,10 @@
method public abstract void onEnrolleeSuccess(int);
method public abstract void onFailure(int);
method public abstract void onProgress(int);
- field public static final int EASY_CONNECT_EVENT_FAILURE = -7; // 0xfffffff9
field public static final int EASY_CONNECT_EVENT_FAILURE_AUTHENTICATION = -2; // 0xfffffffe
field public static final int EASY_CONNECT_EVENT_FAILURE_BUSY = -5; // 0xfffffffb
field public static final int EASY_CONNECT_EVENT_FAILURE_CONFIGURATION = -4; // 0xfffffffc
+ field public static final int EASY_CONNECT_EVENT_FAILURE_GENERIC = -7; // 0xfffffff9
field public static final int EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK = -9; // 0xfffffff7
field public static final int EASY_CONNECT_EVENT_FAILURE_INVALID_URI = -1; // 0xffffffff
field public static final int EASY_CONNECT_EVENT_FAILURE_NOT_COMPATIBLE = -3; // 0xfffffffd
@@ -5106,6 +5106,8 @@
method public static void removeOnPropertyChangedListener(android.provider.DeviceConfig.OnPropertyChangedListener);
method public static void resetToDefaults(int, java.lang.String);
method public static boolean setProperty(java.lang.String, java.lang.String, java.lang.String, boolean);
+ field public static final java.lang.String NAMESPACE_AUTOFILL = "autofill";
+ field public static final java.lang.String NAMESPACE_CONTENT_CAPTURE = "content_capture";
field public static final java.lang.String NAMESPACE_GAME_DRIVER = "game_driver";
field public static final java.lang.String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot";
}
@@ -5744,6 +5746,7 @@
field public static final java.lang.String EUICC_SERVICE_INTERFACE = "android.service.euicc.EuiccService";
field public static final java.lang.String EXTRA_RESOLUTION_ALLOW_POLICY_RULES = "android.service.euicc.extra.RESOLUTION_ALLOW_POLICY_RULES";
field public static final java.lang.String EXTRA_RESOLUTION_CALLING_PACKAGE = "android.service.euicc.extra.RESOLUTION_CALLING_PACKAGE";
+ field public static final java.lang.String EXTRA_RESOLUTION_CARD_ID = "android.service.euicc.extra.RESOLUTION_CARD_ID";
field public static final java.lang.String EXTRA_RESOLUTION_CONFIRMATION_CODE = "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE";
field public static final java.lang.String EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED = "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE_RETRIED";
field public static final java.lang.String EXTRA_RESOLUTION_CONSENT = "android.service.euicc.extra.RESOLUTION_CONSENT";
@@ -8335,7 +8338,6 @@
public final class ContentCaptureEvent implements android.os.Parcelable {
method public int describeContents();
method public long getEventTime();
- method public int getFlags();
method public android.view.autofill.AutofillId getId();
method public java.util.List<android.view.autofill.AutofillId> getIds();
method public java.lang.CharSequence getText();
diff --git a/api/test-current.txt b/api/test-current.txt
index fbba73c..0853182 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -2124,6 +2124,33 @@
}
+package android.view.inspector {
+
+ public abstract class InspectableNodeName implements java.lang.annotation.Annotation {
+ }
+
+ public abstract class InspectableProperty implements java.lang.annotation.Annotation {
+ }
+
+ public static abstract class InspectableProperty.EnumMap implements java.lang.annotation.Annotation {
+ }
+
+ public static abstract class InspectableProperty.FlagMap implements java.lang.annotation.Annotation {
+ }
+
+ public static final class InspectableProperty.ValueType extends java.lang.Enum {
+ method public static android.view.inspector.InspectableProperty.ValueType valueOf(java.lang.String);
+ method public static final android.view.inspector.InspectableProperty.ValueType[] values();
+ enum_constant public static final android.view.inspector.InspectableProperty.ValueType COLOR;
+ enum_constant public static final android.view.inspector.InspectableProperty.ValueType GRAVITY;
+ enum_constant public static final android.view.inspector.InspectableProperty.ValueType INFERRED;
+ enum_constant public static final android.view.inspector.InspectableProperty.ValueType INT_ENUM;
+ enum_constant public static final android.view.inspector.InspectableProperty.ValueType INT_FLAG;
+ enum_constant public static final android.view.inspector.InspectableProperty.ValueType NONE;
+ }
+
+}
+
package android.widget {
public abstract class AbsListView extends android.widget.AdapterView implements android.widget.Filter.FilterListener android.text.TextWatcher android.view.ViewTreeObserver.OnGlobalLayoutListener android.view.ViewTreeObserver.OnTouchModeChangeListener {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 72819cb..b8d748d 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -384,9 +384,7 @@
STANDARD_LAYOUTS.add(R.layout.notification_template_material_messaging);
STANDARD_LAYOUTS.add(R.layout.notification_template_material_media);
STANDARD_LAYOUTS.add(R.layout.notification_template_material_big_media);
- STANDARD_LAYOUTS.add(R.layout.notification_template_ambient_header);
STANDARD_LAYOUTS.add(R.layout.notification_template_header);
- STANDARD_LAYOUTS.add(R.layout.notification_template_material_ambient);
}
/**
@@ -4570,9 +4568,7 @@
if (p.title != null) {
contentView.setViewVisibility(R.id.title, View.VISIBLE);
contentView.setTextViewText(R.id.title, processTextSpans(p.title));
- if (!p.ambient) {
- setTextViewColorPrimary(contentView, R.id.title, p);
- }
+ setTextViewColorPrimary(contentView, R.id.title, p);
contentView.setViewLayoutWidth(R.id.title, showProgress
? ViewGroup.LayoutParams.WRAP_CONTENT
: ViewGroup.LayoutParams.MATCH_PARENT);
@@ -4581,9 +4577,7 @@
int textId = showProgress ? com.android.internal.R.id.text_line_1
: com.android.internal.R.id.text;
contentView.setTextViewText(textId, processTextSpans(p.text));
- if (!p.ambient) {
- setTextViewColorSecondary(contentView, textId, p);
- }
+ setTextViewColorSecondary(contentView, textId, p);
contentView.setViewVisibility(textId, View.VISIBLE);
}
@@ -4842,7 +4836,7 @@
if (mN.mLargeIcon == null && mN.largeIcon != null) {
mN.mLargeIcon = Icon.createWithBitmap(mN.largeIcon);
}
- boolean showLargeIcon = mN.mLargeIcon != null && !p.hideLargeIcon && !p.ambient;
+ boolean showLargeIcon = mN.mLargeIcon != null && !p.hideLargeIcon;
if (showLargeIcon) {
contentView.setViewVisibility(R.id.right_icon, View.VISIBLE);
contentView.setImageViewIcon(R.id.right_icon, mN.mLargeIcon);
@@ -4856,7 +4850,7 @@
* @return if the reply icon is visible
*/
private boolean bindReplyIcon(RemoteViews contentView, StandardTemplateParams p) {
- boolean actionVisible = !p.hideReplyIcon && !p.ambient;
+ boolean actionVisible = !p.hideReplyIcon;
Action action = null;
if (actionVisible) {
action = findReplyAction();
@@ -4896,21 +4890,18 @@
private void bindNotificationHeader(RemoteViews contentView, StandardTemplateParams p) {
bindSmallIcon(contentView, p);
bindHeaderAppName(contentView, p);
- if (!p.ambient) {
- // Ambient view does not have these
- bindHeaderText(contentView, p);
- bindHeaderTextSecondary(contentView, p);
- bindHeaderChronometerAndTime(contentView, p);
- bindProfileBadge(contentView, p);
- bindAlertedIcon(contentView, p);
- }
+ bindHeaderText(contentView, p);
+ bindHeaderTextSecondary(contentView, p);
+ bindHeaderChronometerAndTime(contentView, p);
+ bindProfileBadge(contentView, p);
+ bindAlertedIcon(contentView, p);
bindActivePermissions(contentView, p);
bindExpandButton(contentView, p);
mN.mUsesStandardHeader = true;
}
private void bindActivePermissions(RemoteViews contentView, StandardTemplateParams p) {
- int color = p.ambient ? resolveAmbientColor(p) : getNeutralColor(p);
+ int color = getNeutralColor(p);
contentView.setDrawableTint(R.id.camera, false, color, PorterDuff.Mode.SRC_ATOP);
contentView.setDrawableTint(R.id.mic, false, color, PorterDuff.Mode.SRC_ATOP);
contentView.setDrawableTint(R.id.overlay, false, color, PorterDuff.Mode.SRC_ATOP);
@@ -5021,13 +5012,12 @@
if (isColorized(p)) {
setTextViewColorPrimary(contentView, R.id.app_name_text, p);
} else {
- contentView.setTextColor(R.id.app_name_text,
- p.ambient ? resolveAmbientColor(p) : getSecondaryTextColor(p));
+ contentView.setTextColor(R.id.app_name_text, getSecondaryTextColor(p));
}
}
private boolean isColorized(StandardTemplateParams p) {
- return p.allowColorization && !p.ambient && mN.isColorized();
+ return p.allowColorization && mN.isColorized();
}
private void bindSmallIcon(RemoteViews contentView, StandardTemplateParams p) {
@@ -5097,7 +5087,7 @@
List<Notification.Action> nonContextualActions = filterOutContextualActions(mActions);
int N = nonContextualActions.size();
- boolean emphazisedMode = mN.fullScreenIntent != null && !p.ambient;
+ boolean emphazisedMode = mN.fullScreenIntent != null;
big.setBoolean(R.id.actions, "setEmphasizedMode", emphazisedMode);
if (N > 0) {
big.setViewVisibility(R.id.actions_container, View.VISIBLE);
@@ -5122,7 +5112,7 @@
}
CharSequence[] replyText = mN.extras.getCharSequenceArray(EXTRA_REMOTE_INPUT_HISTORY);
- if (!p.ambient && validRemoteInput && replyText != null
+ if (validRemoteInput && replyText != null
&& replyText.length > 0 && !TextUtils.isEmpty(replyText[0])
&& p.maxRemoteInputHistory > 0) {
boolean showSpinner = mN.extras.getBoolean(EXTRA_SHOW_REMOTE_INPUT_SPINNER);
@@ -5239,11 +5229,10 @@
* Construct a RemoteViews for the final notification header only. This will not be
* colorized.
*
- * @param ambient if true, generate the header for the ambient display layout.
* @hide
*/
- public RemoteViews makeNotificationHeader(boolean ambient) {
- return makeNotificationHeader(mParams.reset().ambient(ambient).fillTextsFrom(this));
+ public RemoteViews makeNotificationHeader() {
+ return makeNotificationHeader(mParams.reset().fillTextsFrom(this));
}
/**
@@ -5256,8 +5245,7 @@
// Headers on their own are never colorized
p.disallowColorization();
RemoteViews header = new BuilderRemoteViews(mContext.getApplicationInfo(),
- p.ambient ? R.layout.notification_template_ambient_header
- : R.layout.notification_template_header);
+ R.layout.notification_template_header);
resetNotificationHeader(header);
bindNotificationHeader(header, p);
return header;
@@ -5269,11 +5257,7 @@
* @hide
*/
public RemoteViews makeAmbientNotification() {
- RemoteViews ambient = applyStandardTemplateWithActions(
- R.layout.notification_template_material_ambient,
- mParams.reset().ambient(true).fillTextsFrom(this).hasProgress(false),
- null /* result */);
- return ambient;
+ return createHeadsUpContentView(false /* increasedHeight */);
}
private void hideLine1Text(RemoteViews result) {
@@ -5377,14 +5361,8 @@
}
mN.extras = publicExtras;
RemoteViews view;
- if (ambient) {
- publicExtras.putCharSequence(EXTRA_TITLE,
- mContext.getString(com.android.internal.R.string.notification_hidden_text));
- view = makeAmbientNotification();
- } else{
- view = makeNotificationHeader(false /* ambient */);
- view.setBoolean(R.id.notification_header, "setExpandOnlyOnButton", true);
- }
+ view = makeNotificationHeader();
+ view.setBoolean(R.id.notification_header, "setExpandOnlyOnButton", true);
mN.extras = savedBundle;
mN.mLargeIcon = largeIcon;
mN.largeIcon = largeIconLegacy;
@@ -5404,7 +5382,6 @@
public RemoteViews makeLowPriorityContentView(boolean useRegularSubtext) {
StandardTemplateParams p = mParams.reset()
.forceDefaultColor()
- .ambient(false)
.fillTextsFrom(this);
if (!useRegularSubtext || TextUtils.isEmpty(mParams.summaryText)) {
p.summaryText(createSummaryText());
@@ -5495,8 +5472,7 @@
if (isColorized(p)) {
setTextViewColorPrimary(button, R.id.action0, p);
} else if (getRawColor(p) != COLOR_DEFAULT && mTintActionButtons) {
- button.setTextColor(R.id.action0,
- p.ambient ? resolveAmbientColor(p) : resolveContrastColor(p));
+ button.setTextColor(R.id.action0, resolveContrastColor(p));
}
}
button.setIntTag(R.id.action0, R.id.notification_action_index_tag,
@@ -5589,13 +5565,8 @@
}
private CharSequence processLegacyText(CharSequence charSequence) {
- return processLegacyText(charSequence, false /* ambient */);
- }
-
- private CharSequence processLegacyText(CharSequence charSequence, boolean ambient) {
boolean isAlreadyLightText = isLegacy() || textColorsNeedInversion();
- boolean wantLightText = ambient;
- if (isAlreadyLightText != wantLightText) {
+ if (isAlreadyLightText) {
return getColorUtil().invertCharSequenceColors(charSequence);
} else {
return charSequence;
@@ -5609,9 +5580,7 @@
StandardTemplateParams p) {
boolean colorable = !isLegacy() || getColorUtil().isGrayscaleIcon(mContext, smallIcon);
int color;
- if (p.ambient) {
- color = resolveAmbientColor(p);
- } else if (isColorized(p)) {
+ if (isColorized(p)) {
color = getPrimaryTextColor(p);
} else {
color = resolveContrastColor(p);
@@ -5698,17 +5667,6 @@
return mNeutralColor;
}
- int resolveAmbientColor(StandardTemplateParams p) {
- int rawColor = getRawColor(p);
- if (mCachedAmbientColorIsFor == rawColor && mCachedAmbientColorIsFor != COLOR_INVALID) {
- return mCachedAmbientColor;
- }
- final int contrasted = ContrastColorUtil.resolveAmbientColor(mContext, rawColor);
-
- mCachedAmbientColorIsFor = rawColor;
- return mCachedAmbientColor = contrasted;
- }
-
/**
* Apply the unstyled operations and return a new {@link Notification} object.
* @hide
@@ -10144,7 +10102,6 @@
private static class StandardTemplateParams {
boolean hasProgress = true;
- boolean ambient = false;
CharSequence title;
CharSequence text;
CharSequence headerTextSecondary;
@@ -10157,7 +10114,6 @@
final StandardTemplateParams reset() {
hasProgress = true;
- ambient = false;
title = null;
text = null;
summaryText = null;
@@ -10213,22 +10169,15 @@
return this;
}
- final StandardTemplateParams ambient(boolean ambient) {
- Preconditions.checkState(title == null && text == null, "must set ambient before text");
- this.ambient = ambient;
- return this;
- }
-
final StandardTemplateParams fillTextsFrom(Builder b) {
Bundle extras = b.mN.extras;
- this.title = b.processLegacyText(extras.getCharSequence(EXTRA_TITLE), ambient);
+ this.title = b.processLegacyText(extras.getCharSequence(EXTRA_TITLE));
- // Big text notifications should contain their content when viewed in ambient mode.
CharSequence text = extras.getCharSequence(EXTRA_BIG_TEXT);
- if (!ambient || TextUtils.isEmpty(text)) {
+ if (TextUtils.isEmpty(text)) {
text = extras.getCharSequence(EXTRA_TEXT);
}
- this.text = b.processLegacyText(text, ambient);
+ this.text = b.processLegacyText(text);
this.summaryText = extras.getCharSequence(EXTRA_SUB_TEXT);
return this;
}
diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java
index 740fd7f..b7366f1 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
@@ -76,9 +77,23 @@
}
/**
- * Starts the specified activity of the caller package in the specified profile if the caller
- * has {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES} permission and
- * both the caller and target user profiles are in the same user group.
+ * @deprecated use {@link #startActivity(ComponentName, UserHandle)} instead.
+ *
+ * @removed
+ * @hide
+ */
+ @Deprecated
+ @UnsupportedAppUsage
+ public void startAnyActivity(@NonNull ComponentName component, @NonNull UserHandle targetUser) {
+ startActivity(component, targetUser);
+ }
+
+ /**
+ * Starts the specified activity of the caller package in the specified profile. Unlike
+ * {@link #startMainActivity}, this can start any activity of the caller package, not just
+ * the main activity.
+ * The caller must have the {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES}
+ * permission and both the caller and target user profiles must be in the same profile group.
*
* @param component The ComponentName of the activity to launch. It must be exported.
* @param targetUser The UserHandle of the profile, must be one of the users returned by
@@ -88,7 +103,7 @@
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_PROFILES)
- public void startAnyActivity(@NonNull ComponentName component, @NonNull UserHandle targetUser) {
+ public void startActivity(@NonNull ComponentName component, @NonNull UserHandle targetUser) {
try {
mService.startActivityAsUser(mContext.getIApplicationThread(),
mContext.getPackageName(), component, targetUser.getIdentifier(), false);
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 766c566..983ea9f 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -136,17 +136,6 @@
public static final String EXTRA_PIN_ITEM_REQUEST =
"android.content.pm.extra.PIN_ITEM_REQUEST";
- /**
- * Metadata key that specifies vouched certs, so any apps signed by a cert in vouched certs
- * will not show hidden icon in launcher even it does not have a launcher visible activity.
- *
- * If an app has this metadata in manifest, it won't be eligible to hide its icon even if its
- * cert is in vouched certs list.
- *
- * @hide
- */
- public static final String VOUCHED_CERTS_KEY = "vouched_certs";
-
private final Context mContext;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final ILauncherApps mService;
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 77796d9..d8564d5 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -855,13 +855,9 @@
try {
if (file.endsWith(".xml")) {
if (file.startsWith("res/color/")) {
- ColorStateList csl = loadColorStateList(wrapper, value, id, null);
- dr = (csl != null ? new ColorStateListDrawable(csl) : null);
+ dr = loadColorOrXmlDrawable(wrapper, value, id, density, file);
} else {
- final XmlResourceParser rp = loadXmlResourceParser(
- file, id, value.assetCookie, "drawable");
- dr = Drawable.createFromXmlForDensity(wrapper, rp, density, null);
- rp.close();
+ dr = loadXmlDrawable(wrapper, value, id, density, file);
}
} else {
final InputStream is = mAssets.openNonAsset(
@@ -915,6 +911,33 @@
return dr;
}
+ private Drawable loadColorOrXmlDrawable(@NonNull Resources wrapper, @NonNull TypedValue value,
+ int id, int density, String file) {
+ try {
+ ColorStateList csl = loadColorStateList(wrapper, value, id, null);
+ return new ColorStateListDrawable(csl);
+ } catch (NotFoundException originalException) {
+ // If we fail to load as color, try as normal XML drawable
+ try {
+ return loadXmlDrawable(wrapper, value, id, density, file);
+ } catch (Exception ignored) {
+ // If fallback also fails, throw the original exception
+ throw originalException;
+ }
+ }
+ }
+
+ private Drawable loadXmlDrawable(@NonNull Resources wrapper, @NonNull TypedValue value,
+ int id, int density, String file)
+ throws IOException, XmlPullParserException {
+ try (
+ XmlResourceParser rp =
+ loadXmlResourceParser(file, id, value.assetCookie, "drawable")
+ ) {
+ return Drawable.createFromXmlForDensity(wrapper, rp, density, null);
+ }
+ }
+
/**
* Loads a font from XML or resources stream.
*/
diff --git a/core/java/android/hardware/display/ColorDisplayManager.java b/core/java/android/hardware/display/ColorDisplayManager.java
index aefcf8c..70a9f08 100644
--- a/core/java/android/hardware/display/ColorDisplayManager.java
+++ b/core/java/android/hardware/display/ColorDisplayManager.java
@@ -104,6 +104,16 @@
return context.getResources().getBoolean(R.bool.config_displayWhiteBalanceAvailable);
}
+ /**
+ * Check if the color transforms are color accelerated. Some transforms are experimental only
+ * on non-accelerated platforms due to the performance implications.
+ *
+ * @hide
+ */
+ public static boolean isColorTransformAccelerated(Context context) {
+ return context.getResources().getBoolean(R.bool.config_setColorTransformAccelerated);
+ }
+
private static class ColorDisplayManagerInternal {
private static ColorDisplayManagerInternal sInstance;
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index e84a518..ca39051 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -846,7 +846,16 @@
return contains(dir.getAbsolutePath(), file.getAbsolutePath());
}
- /** {@hide} */
+ /**
+ * Test if a file lives under the given directory, either as a direct child
+ * or a distant grandchild.
+ * <p>
+ * Both files <em>must</em> have been resolved using
+ * {@link File#getCanonicalFile()} to avoid symlink or path traversal
+ * attacks.
+ *
+ * @hide
+ */
public static boolean contains(String dirPath, String filePath) {
if (dirPath.equals(filePath)) {
return true;
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index af8146e..9015703 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -60,6 +60,24 @@
public static final String NAMESPACE_GAME_DRIVER = "game_driver";
/**
+ * Namespace for autofill feature that provides suggestions across all apps when
+ * the user interacts with input fields.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String NAMESPACE_AUTOFILL = "autofill";
+
+ /**
+ * Namespace for content capture feature used by on-device machine intelligence
+ * to provide suggestions in a privacy-safe manner.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
+
+ /**
* Namespace for all input-related features that are used at the native level.
* These features are applied at reboot.
*
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index fb511e3..d5de13c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10958,6 +10958,21 @@
public static final String DATA_STALL_EVALUATION_TYPE = "data_stall_evaluation_type";
/**
+ * Whether to try cellular data recovery when a bad network is reported.
+ *
+ * @hide
+ */
+ public static final String DATA_STALL_RECOVERY_ON_BAD_NETWORK =
+ "data_stall_recovery_on_bad_network";
+
+ /**
+ * Minumim duration in millisecodns between cellular data recovery attempts
+ *
+ * @hide
+ */
+ public static final String MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS =
+ "min_duration_between_recovery_steps";
+ /**
* Whether network service discovery is enabled.
*
* @hide
diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java
index 4be1f9c..4dc10cd 100644
--- a/core/java/android/service/euicc/EuiccService.java
+++ b/core/java/android/service/euicc/EuiccService.java
@@ -184,6 +184,12 @@
public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED =
"android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE_RETRIED";
+ /**
+ * Intent extra set for resolution requests containing an int indicating the current card Id.
+ */
+ public static final String EXTRA_RESOLUTION_CARD_ID =
+ "android.service.euicc.extra.RESOLUTION_CARD_ID";
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = { "RESULT_" }, value = {
diff --git a/core/java/android/util/Half.java b/core/java/android/util/Half.java
index 5718d99..70d049a 100644
--- a/core/java/android/util/Half.java
+++ b/core/java/android/util/Half.java
@@ -162,6 +162,7 @@
private static final int FP32_EXPONENT_MASK = 0xff;
private static final int FP32_SIGNIFICAND_MASK = 0x7fffff;
private static final int FP32_EXPONENT_BIAS = 127;
+ private static final int FP32_QNAN_MASK = 0x400000;
private static final int FP32_DENORMAL_MAGIC = 126 << 23;
private static final float FP32_DENORMAL_FLOAT = Float.intBitsToFloat(FP32_DENORMAL_MAGIC);
@@ -903,6 +904,9 @@
outM = m << 13;
if (e == 0x1f) { // Infinite or NaN
outE = 0xff;
+ if (outM != 0) { // SNaNs are quieted
+ outM |= FP32_QNAN_MASK;
+ }
} else {
outE = e - FP16_EXPONENT_BIAS + FP32_EXPONENT_BIAS;
}
diff --git a/core/java/android/view/contentcapture/ChildContentCaptureSession.java b/core/java/android/view/contentcapture/ChildContentCaptureSession.java
index 0b39c3a..63c21f3 100644
--- a/core/java/android/view/contentcapture/ChildContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ChildContentCaptureSession.java
@@ -88,9 +88,8 @@
}
@Override
- void internalNotifyViewTextChanged(@NonNull AutofillId id, @Nullable CharSequence text,
- int flags) {
- getMainCaptureSession().notifyViewTextChanged(mId, id, text, flags);
+ void internalNotifyViewTextChanged(@NonNull AutofillId id, @Nullable CharSequence text) {
+ getMainCaptureSession().notifyViewTextChanged(mId, id, text);
}
@Override
diff --git a/core/java/android/view/contentcapture/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java
index a3b285d..43963c3 100644
--- a/core/java/android/view/contentcapture/ContentCaptureEvent.java
+++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java
@@ -81,7 +81,6 @@
private final @NonNull String mSessionId;
private final int mType;
private final long mEventTime;
- private final int mFlags;
private @Nullable AutofillId mId;
private @Nullable ArrayList<AutofillId> mIds;
private @Nullable ViewNode mNode;
@@ -90,21 +89,15 @@
private @Nullable ContentCaptureContext mClientContext;
/** @hide */
- public ContentCaptureEvent(@NonNull String sessionId, int type, long eventTime, int flags) {
+ public ContentCaptureEvent(@NonNull String sessionId, int type, long eventTime) {
mSessionId = sessionId;
mType = type;
mEventTime = eventTime;
- mFlags = flags;
- }
-
- /** @hide */
- public ContentCaptureEvent(@NonNull String sessionId, int type, int flags) {
- this(sessionId, type, System.currentTimeMillis(), flags);
}
/** @hide */
public ContentCaptureEvent(@NonNull String sessionId, int type) {
- this(sessionId, type, /* flags= */ 0);
+ this(sessionId, type, System.currentTimeMillis());
}
/** @hide */
@@ -212,16 +205,6 @@
}
/**
- * Gets optional flags associated with the event.
- *
- * @return either {@code 0} or
- * {@link android.view.contentcapture.ContentCaptureSession#FLAG_USER_INPUT}.
- */
- public int getFlags() {
- return mFlags;
- }
-
- /**
* Gets the whole metadata of the node associated with the event.
*
* <p>Only set on {@link #TYPE_VIEW_APPEARED} events.
@@ -268,9 +251,6 @@
public void dump(@NonNull PrintWriter pw) {
pw.print("type="); pw.print(getTypeAsString(mType));
pw.print(", time="); pw.print(mEventTime);
- if (mFlags > 0) {
- pw.print(", flags="); pw.print(mFlags);
- }
if (mId != null) {
pw.print(", id="); pw.print(mId);
}
@@ -300,9 +280,6 @@
if (mType == TYPE_SESSION_STARTED && mParentSessionId != null) {
string.append(", parent=").append(mParentSessionId);
}
- if (mFlags > 0) {
- string.append(", flags=").append(mFlags);
- }
if (mId != null) {
string.append(", id=").append(mId);
}
@@ -329,7 +306,6 @@
parcel.writeString(mSessionId);
parcel.writeInt(mType);
parcel.writeLong(mEventTime);
- parcel.writeInt(mFlags);
parcel.writeParcelable(mId, flags);
parcel.writeTypedList(mIds);
ViewNode.writeToParcel(parcel, mNode, flags);
@@ -350,9 +326,7 @@
final String sessionId = parcel.readString();
final int type = parcel.readInt();
final long eventTime = parcel.readLong();
- final int flags = parcel.readInt();
- final ContentCaptureEvent event =
- new ContentCaptureEvent(sessionId, type, eventTime, flags);
+ final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, type, eventTime);
final AutofillId id = parcel.readParcelable(null);
if (id != null) {
event.setAutofillId(id);
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index 21914e2..b620ab1 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -51,12 +51,6 @@
private static final String TAG = ContentCaptureSession.class.getSimpleName();
/**
- * Used on {@link #notifyViewTextChanged(AutofillId, CharSequence, int)} to indicate that the
- * text change was caused by user input (for example, through IME).
- */
- public static final int FLAG_USER_INPUT = 0x1;
-
- /**
* Initial state, when there is no session.
*
* @hide
@@ -375,8 +369,7 @@
*
* @param id of the node.
* @param text new text.
- * @param flags either {@code 0} or {@link #FLAG_USER_INPUT} when the value was explicitly
- * changed by the user (for example, through the keyboard).
+ * @param flags currently ignored.
*/
public final void notifyViewTextChanged(@NonNull AutofillId id, @Nullable CharSequence text,
int flags) {
@@ -384,11 +377,11 @@
if (!isContentCaptureEnabled()) return;
- internalNotifyViewTextChanged(id, text, flags);
+ internalNotifyViewTextChanged(id, text);
}
- abstract void internalNotifyViewTextChanged(@NonNull AutofillId id, @Nullable CharSequence text,
- int flags);
+ abstract void internalNotifyViewTextChanged(@NonNull AutofillId id,
+ @Nullable CharSequence text);
/**
* Creates a {@link ViewStructure} for a "standard" view.
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index af56af3..103d7e6 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -490,9 +490,8 @@
}
@Override
- void internalNotifyViewTextChanged(@NonNull AutofillId id, @Nullable CharSequence text,
- int flags) {
- notifyViewTextChanged(mId, id, text, flags);
+ void internalNotifyViewTextChanged(@NonNull AutofillId id, @Nullable CharSequence text) {
+ notifyViewTextChanged(mId, id, text);
}
@Override
@@ -533,9 +532,9 @@
}
void notifyViewTextChanged(@NonNull String sessionId, @NonNull AutofillId id,
- @Nullable CharSequence text, int flags) {
+ @Nullable CharSequence text) {
mHandler.sendMessage(obtainMessage(MainContentCaptureSession::handleSendEvent, this,
- new ContentCaptureEvent(sessionId, TYPE_VIEW_TEXT_CHANGED, flags).setAutofillId(id)
+ new ContentCaptureEvent(sessionId, TYPE_VIEW_TEXT_CHANGED).setAutofillId(id)
.setText(text), /* forceFlush= */ false));
}
diff --git a/core/java/android/view/inspector/InspectableNodeName.java b/core/java/android/view/inspector/InspectableNodeName.java
index ea94ad4..7b9a507 100644
--- a/core/java/android/view/inspector/InspectableNodeName.java
+++ b/core/java/android/view/inspector/InspectableNodeName.java
@@ -19,6 +19,8 @@
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.SOURCE;
+import android.annotation.TestApi;
+
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@@ -39,6 +41,7 @@
*/
@Target({TYPE})
@Retention(SOURCE)
+@TestApi
public @interface InspectableNodeName {
/**
* The display name for nodes of this type.
diff --git a/core/java/android/view/inspector/InspectableProperty.java b/core/java/android/view/inspector/InspectableProperty.java
index a57470c..355ff1d 100644
--- a/core/java/android/view/inspector/InspectableProperty.java
+++ b/core/java/android/view/inspector/InspectableProperty.java
@@ -20,6 +20,7 @@
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.SOURCE;
+import android.annotation.TestApi;
import android.content.res.Resources;
import java.lang.annotation.Retention;
@@ -40,6 +41,7 @@
*/
@Target({METHOD})
@Retention(SOURCE)
+@TestApi
public @interface InspectableProperty {
/**
* The name of the property.
@@ -86,7 +88,6 @@
*
* @return An array of {@link EnumMap}, empty if not applicable
* @see android.annotation.IntDef
- * @see IntEnumMapping
*/
EnumMap[] enumMapping() default {};
@@ -109,6 +110,7 @@
*/
@Target({TYPE})
@Retention(SOURCE)
+ @TestApi
@interface EnumMap {
/**
* The string name of this enumeration value.
@@ -133,6 +135,7 @@
*/
@Target({TYPE})
@Retention(SOURCE)
+ @TestApi
@interface FlagMap {
/**
* The string name of this flag.
@@ -167,15 +170,22 @@
*
* @hide
*/
+ @TestApi
enum ValueType {
/**
* No special handling, property is considered to be a numeric value.
+ *
+ * @hide
*/
+ @TestApi
NONE,
/**
* The default the annotation processor infers the value type from context.
+ *
+ * @hide
*/
+ @TestApi
INFERRED,
/**
@@ -184,7 +194,9 @@
* This is inferred if {@link #enumMapping()} is specified.
*
* @see EnumMap
+ * @hide
*/
+ @TestApi
INT_ENUM,
/**
@@ -193,7 +205,9 @@
* This is inferred if {@link #flagMapping()} is specified.
*
* @see FlagMap
+ * @hide
*/
+ @TestApi
INT_FLAG,
/**
@@ -203,7 +217,9 @@
* {@link android.annotation.ColorLong} on the getter method.
*
* @see android.graphics.Color
+ * @hide
*/
+ @TestApi
COLOR,
/**
@@ -212,7 +228,9 @@
* This type is not inferred, and is non-trivial to represent using {@link FlagMap}.
*
* @see android.view.Gravity
+ * @hide
*/
+ @TestApi
GRAVITY
}
}
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 798825f..26a474c 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -22,12 +22,12 @@
#include <utils/Log.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
-#include <cutils/sched_policy.h>
#include <utils/String8.h>
#include <utils/Vector.h>
#include <meminfo/procmeminfo.h>
#include <meminfo/sysmeminfo.h>
#include <processgroup/processgroup.h>
+#include <processgroup/sched_policy.h>
#include <string>
#include <vector>
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 057e02a..7aee833 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -62,13 +62,13 @@
#include <android-base/stringprintf.h>
#include <cutils/fs.h>
#include <cutils/multiuser.h>
-#include <cutils/sched_policy.h>
#include <private/android_filesystem_config.h>
#include <utils/String8.h>
#include <selinux/android.h>
#include <seccomp_policy.h>
#include <stats_event_list.h>
#include <processgroup/processgroup.h>
+#include <processgroup/sched_policy.h>
#include "core_jni_helpers.h"
#include <nativehelper/JNIHelp.h>
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 248c57b..ea0c8e2 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2210,8 +2210,9 @@
<permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"
android:protectionLevel="signature|installer" />
- <!-- @SystemApi Allows an application to start an activity within its managed profile from
- the personal profile.
+ <!-- @SystemApi Allows an application to start its own activities, but on a different profile
+ associated with the user. For example, an application running on the main profile of a user
+ can start an activity on a managed profile of that user.
This permission is not available to third party applications.
@hide -->
<permission android:name="android.permission.INTERACT_ACROSS_PROFILES"
@@ -4764,6 +4765,11 @@
android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
+ <service android:name="com.android.server.ZramWriteback"
+ android:exported="false"
+ android:permission="android.permission.BIND_JOB_SERVICE" >
+ </service>
+
<service android:name="com.android.server.backup.FullBackupJob"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE" >
diff --git a/core/res/res/layout/notification_template_ambient_header.xml b/core/res/res/layout/notification_template_ambient_header.xml
deleted file mode 100644
index be5d9b4..0000000
--- a/core/res/res/layout/notification_template_ambient_header.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2017 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.
- -->
-
-<!-- hack to work around <include /> not being supported at the top level -->
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:paddingStart="@dimen/notification_extra_margin_ambient"
- android:paddingEnd="@dimen/notification_extra_margin_ambient"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
- <include
- layout="@layout/notification_template_header"
- android:theme="@style/Theme.DeviceDefault.Notification.Ambient"/>
-</FrameLayout>
diff --git a/core/res/res/layout/notification_template_material_ambient.xml b/core/res/res/layout/notification_template_material_ambient.xml
deleted file mode 100644
index 2c6064e..0000000
--- a/core/res/res/layout/notification_template_material_ambient.xml
+++ /dev/null
@@ -1,94 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2017 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.
- -->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/status_bar_latest_event_content"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:tag="ambient"
- android:paddingStart="@dimen/notification_extra_margin_ambient"
- android:paddingEnd="@dimen/notification_extra_margin_ambient"
- >
- <include layout="@layout/notification_template_ambient_header"
- android:theme="@style/Theme.DeviceDefault.Notification.Ambient" />
-
- <LinearLayout
- android:id="@+id/notification_action_list_margin_target"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="top"
- android:layout_marginTop="@dimen/notification_content_margin_top"
- android:layout_marginBottom="@dimen/notification_action_list_height"
- android:paddingTop="4dp"
- android:paddingBottom="6dp"
- android:clipToPadding="false"
- android:orientation="vertical">
-
- <LinearLayout
- android:id="@+id/notification_main_column"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="top"
- android:layout_weight="1"
- android:paddingStart="@dimen/notification_content_margin_start"
- android:paddingEnd="@dimen/notification_content_margin_end"
- android:clipToPadding="false"
- android:minHeight="@dimen/notification_min_content_height"
- android:orientation="vertical"
- >
- <TextView android:id="@+id/title"
- android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="top|center_horizontal"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal"
- android:textSize="@dimen/notification_ambient_title_text_size"
- android:textColor="#ffffffff"
- />
- <TextView android:id="@+id/text"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:textAppearance="@style/TextAppearance.DeviceDefault.Notification"
- android:singleLine="false"
- android:layout_weight="1"
- android:gravity="top|center_horizontal"
- android:visibility="gone"
- android:textSize="@dimen/notification_ambient_text_size"
- android:textColor="#eeffffff"
- android:layout_marginTop="4dp"
- android:ellipsize="end"
- android:maxLines="3"
- />
- </LinearLayout>
- <FrameLayout android:id="@+id/actions_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="bottom">
- <com.android.internal.widget.NotificationActionListLayout
- android:id="@+id/actions"
- android:layout_width="match_parent"
- android:layout_height="@dimen/notification_action_list_height"
- android:paddingEnd="4dp"
- android:orientation="horizontal"
- android:gravity="center"
- android:visibility="gone"
- />
- </FrameLayout>
- </LinearLayout>
-</FrameLayout>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index c1ae026..c6f4ed0 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3722,4 +3722,7 @@
<!-- If the sensor that silences alerts is available or not. -->
<bool name="config_silenceSensorAvailable">false</bool>
+
+ <!-- Enable Zram writeback feature to allow unused pages in zram be written to flash. -->
+ <bool name="config_zramWriteback">false</bool>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 05a156b..c870683 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -194,9 +194,6 @@
<!-- The margin for text at the end of the image view for media notifications -->
<dimen name="notification_media_image_margin_end">72dp</dimen>
- <!-- The additional margin on the sides of the ambient view. -->
- <dimen name="notification_extra_margin_ambient">16dp</dimen>
-
<!-- The height of the notification action list -->
<dimen name="notification_action_list_height">60dp</dimen>
@@ -233,9 +230,6 @@
<!-- The bottom padding for the notification header -->
<dimen name="notification_header_padding_bottom">16dp</dimen>
- <!-- The margin at the top of the notification header when dozing. -->
- <dimen name="notification_header_margin_top_ambient">3dp</dimen>
-
<!-- The margin at the bottom of the notification header. -->
<dimen name="notification_header_margin_bottom">0dp</dimen>
@@ -400,11 +394,6 @@
<dimen name="notification_title_text_size">14sp</dimen>
<!-- Size of smaller notification text (see TextAppearance.StatusBar.EventContent.Line2, Info, Time) -->
<dimen name="notification_subtext_size">12sp</dimen>
- <!-- Size of notification text (see TextAppearance.StatusBar.EventContent) -->
- <dimen name="notification_ambient_text_size">16sp</dimen>
- <!-- Size of notification text titles (see TextAppearance.StatusBar.EventContent.Title) -->
- <dimen name="notification_ambient_title_text_size">24sp</dimen>
-
<!-- Top padding for notifications in the standard layout. -->
<dimen name="notification_top_pad">10dp</dimen>
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index 200ef2f..79afe69 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -271,9 +271,6 @@
<style name="TextAppearance.DeviceDefault.Notification.Info" parent="TextAppearance.Material.Notification.Info">
<item name="fontFamily">@string/config_bodyFontFamily</item>
</style>
- <style name="TextAppearance.DeviceDefault.Notification.Info.Ambient" parent="TextAppearance.Material.Notification.Info.Ambient">
- <item name="fontFamily">@string/config_bodyFontFamily</item>
- </style>
<style name="TextAppearance.DeviceDefault.Widget" parent="TextAppearance.Material.Widget">
<item name="fontFamily">@string/config_bodyFontFamily</item>
</style>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 5a7199d..63ac0e6 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -487,10 +487,6 @@
<style name="TextAppearance.Material.Notification.Time" parent="TextAppearance.Material.Notification.Info" />
- <style name="TextAppearance.Material.Notification.Info.Ambient">
- <item name="textSize">@dimen/notification_text_size</item>
- </style>
-
<style name="TextAppearance.Material.Notification.Emphasis">
<item name="textColor">#66000000</item>
</style>
@@ -1308,10 +1304,5 @@
<item name="gravity">top</item>
</style>
- <style name="Notification.Header.Ambient">
- <item name="layout_marginTop">@dimen/notification_header_margin_top_ambient</item>
- <item name="gravity">top|center_horizontal</item>
- </style>
-
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index d36dbfc..cc4599e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3074,8 +3074,6 @@
<java-symbol type="dimen" name="config_appTransitionAnimationDurationScaleDefault" />
- <java-symbol type="layout" name="notification_template_material_ambient" />
-
<!-- Network Recommendation -->
<java-symbol type="string" name="config_defaultNetworkRecommendationProviderPackage" />
@@ -3235,8 +3233,6 @@
<java-symbol type="string" name="time_picker_text_input_mode_description"/>
<java-symbol type="string" name="time_picker_radial_mode_description"/>
- <java-symbol type="layout" name="notification_template_ambient_header" />
-
<!-- resolver activity -->
<java-symbol type="drawable" name="resolver_icon_placeholder" />
@@ -3541,4 +3537,6 @@
<java-symbol type="bool" name="config_skipSensorAvailable" />
<java-symbol type="bool" name="config_silenceSensorAvailable" />
+
+ <java-symbol type="bool" name="config_zramWriteback" />
</resources>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index d60313a..75a727b 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -1711,8 +1711,4 @@
<item name="notificationHeaderTextAppearance">@style/TextAppearance.DeviceDefault.Notification.Info</item>
</style>
- <style name="Theme.DeviceDefault.Notification.Ambient" parent="@style/Theme.Material.Notification.Ambient">
- <item name="notificationHeaderTextAppearance">@style/TextAppearance.DeviceDefault.Notification.Info.Ambient</item>
- </style>
-
</resources>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index ccaf041..6b7698e 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -1341,14 +1341,6 @@
<item name="notificationHeaderIconSize">@dimen/notification_header_icon_size</item>
</style>
- <!-- Theme for inflating ambient notification -->
- <style name="Theme.Material.Notification.Ambient">
- <item name="notificationHeaderStyle">@style/Notification.Header.Ambient</item>
- <item name="notificationHeaderTextAppearance">@style/TextAppearance.Material.Notification.Info.Ambient</item>
- <item name="notificationHeaderAppNameVisibility">gone</item>
- <item name="notificationHeaderIconSize">@dimen/notification_header_icon_size_ambient</item>
- </style>
-
<!-- Default theme for Settings and activities launched from Settings. -->
<style name="Theme.Material.Settings" parent="Theme.Material.Light.LightStatusBar">
<item name="homeAsUpIndicator">@drawable/ic_ab_back_material_settings</item>
diff --git a/core/tests/BroadcastRadioTests/Android.mk b/core/tests/BroadcastRadioTests/Android.mk
index 24f0cf0..6b0484e 100644
--- a/core/tests/BroadcastRadioTests/Android.mk
+++ b/core/tests/BroadcastRadioTests/Android.mk
@@ -25,7 +25,7 @@
# LOCAL_SDK_VERSION := current
LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util android-support-test testng
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util androidx.test.rules testng
LOCAL_JAVA_LIBRARIES := android.test.base
diff --git a/core/tests/BroadcastRadioTests/AndroidManifest.xml b/core/tests/BroadcastRadioTests/AndroidManifest.xml
index d9b5522..ce12cc9 100644
--- a/core/tests/BroadcastRadioTests/AndroidManifest.xml
+++ b/core/tests/BroadcastRadioTests/AndroidManifest.xml
@@ -24,7 +24,7 @@
</application>
<instrumentation
- android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="android.hardware.radio.tests"
android:label="Tests for Broadcast Radio APIs" >
</instrumentation>
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
index fdaba08..d2bd1e1 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
@@ -15,22 +15,29 @@
*/
package android.hardware.radio.tests.functional;
+import static org.junit.Assert.*;
+import static org.junit.Assume.*;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.after;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.atMost;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.testng.Assert.assertThrows;
+
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.radio.ProgramSelector;
import android.hardware.radio.RadioManager;
import android.hardware.radio.RadioTuner;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.MediumTest;
import android.util.Log;
-import java.lang.reflect.Constructor;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
@@ -41,19 +48,10 @@
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
-import static org.junit.Assert.*;
-import static org.junit.Assume.*;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Mockito.after;
-import static org.mockito.Mockito.atLeast;
-import static org.mockito.Mockito.atMost;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.testng.Assert.assertThrows;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
/**
* A test for broadcast radio API.
diff --git a/core/tests/coretests/README b/core/tests/coretests/README
index ea282a0..34beb45 100644
--- a/core/tests/coretests/README
+++ b/core/tests/coretests/README
@@ -30,9 +30,9 @@
adb install -r ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
adb shell am instrument -w \
- com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
-To run a tests within a specific package, add the following argument AFTER -w:
+To run a tests within a specific package, add -e AFTER -w and before the runner class:
-e package android.content.pm
diff --git a/core/tests/coretests/res/color/drawable_in_color_dir_invalid.xml b/core/tests/coretests/res/color/drawable_in_color_dir_invalid.xml
new file mode 100644
index 0000000..8d630b0
--- /dev/null
+++ b/core/tests/coretests/res/color/drawable_in_color_dir_invalid.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+
+<!-- This drawable is purposely in the color directory to test a backwards compatible fallback. -->
+<layer-list
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@android:id/icon" android:drawable="@string/app_name" />
+</layer-list>
\ No newline at end of file
diff --git a/core/tests/coretests/res/color/drawable_in_color_dir_valid.xml b/core/tests/coretests/res/color/drawable_in_color_dir_valid.xml
new file mode 100644
index 0000000..d140475
--- /dev/null
+++ b/core/tests/coretests/res/color/drawable_in_color_dir_valid.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+
+<!-- This drawable is purposely in the color directory to test a backwards compatible fallback. -->
+<layer-list
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@android:id/background" android:drawable="@drawable/test32x24" />
+ <item android:id="@android:id/icon" android:drawable="@drawable/test16x12" />
+</layer-list>
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/content/res/ResourcesDrawableTest.java b/core/tests/coretests/src/android/content/res/ResourcesDrawableTest.java
new file mode 100644
index 0000000..c4df88b
--- /dev/null
+++ b/core/tests/coretests/src/android/content/res/ResourcesDrawableTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 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.content.res;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.graphics.drawable.ColorStateListDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.frameworks.coretests.R;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ResourcesDrawableTest {
+
+ @Test
+ public void testLoadColorAsDrawable() {
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ Resources resources = context.getResources();
+ Drawable drawable = resources.getDrawable(R.color.color1);
+ assertTrue(drawable instanceof ColorStateListDrawable);
+ }
+
+ @Test
+ public void testLoadColorAsDrawableFailureThrowsOriginalException() throws Throwable {
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ Resources resources = context.getResources();
+
+ Exception exception = null;
+
+ try {
+ resources.getDrawable(R.color.drawable_in_color_dir_invalid);
+ } catch (Exception e) {
+ exception = e;
+ }
+
+ assertNotNull(
+ "Loading drawable_in_color_dir_invalid should throw an exception",
+ exception
+ );
+
+ assertEquals(
+ "Can't find ColorStateList from drawable resource ID #0x"
+ + Integer.toHexString(R.color.drawable_in_color_dir_invalid),
+ exception.getCause().getCause().getMessage()
+ );
+ }
+
+ @Test
+ public void testLoadNormalDrawableInColorDir() {
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ Resources resources = context.getResources();
+ Drawable drawable = resources.getDrawable(R.color.drawable_in_color_dir_valid);
+ assertTrue(drawable instanceof LayerDrawable);
+ }
+}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 93af013..0fb1c7c 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -199,6 +199,7 @@
Settings.Global.DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD,
Settings.Global.DATA_STALL_EVALUATION_TYPE,
Settings.Global.DATA_STALL_MIN_EVALUATE_INTERVAL,
+ Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK,
Settings.Global.DATA_STALL_VALID_DNS_TIME_THRESHOLD,
Settings.Global.DEBUG_APP,
Settings.Global.DEBUG_VIEW_ATTRIBUTES,
@@ -312,6 +313,7 @@
Settings.Global.MDC_INITIAL_MAX_RETRY,
Settings.Global.MHL_INPUT_SWITCHING_ENABLED,
Settings.Global.MHL_POWER_CHARGE_ENABLED,
+ Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS,
Settings.Global.MOBILE_DATA, // Candidate for backup?
Settings.Global.MOBILE_DATA_ALWAYS_ON,
Settings.Global.MODE_RINGER,
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
index 05c0df7..ff97aa1 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
@@ -151,7 +151,7 @@
}
@Override
- void internalNotifyViewTextChanged(AutofillId id, CharSequence text, int flags) {
+ void internalNotifyViewTextChanged(AutofillId id, CharSequence text) {
throw new UnsupportedOperationException("should not have been called");
}
}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
index d161059..cc2d8d2 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
@@ -38,16 +38,11 @@
LOCAL_MIN_SDK_VERSION := 8
-LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex \
- -D jack.dex.output.multidex.legacy=true
-
include $(BUILD_PACKAGE)
-ifndef LOCAL_JACK_ENABLED
-$(mainDexList): $(full_classes_pre_proguard_jar) | $(MAINDEXCLASSES)
+$(mainDexList): $(full_classes_pre_proguard_jar) $(MAINDEXCLASSES) $(PROGUARD_DEPS)
$(hide) mkdir -p $(dir $@)
- $(MAINDEXCLASSES) $< 1>$@
+ PROGUARD_HOME=$(PROGUARD_HOME) $(MAINDEXCLASSES) $< 1>$@
echo "com/android/multidexlegacyandexception/Test.class" >> $@
$(built_dex_intermediate): $(mainDexList)
-endif
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
index cf8fc92..c577eef 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
@@ -38,9 +38,9 @@
include $(BUILD_PACKAGE)
-$(mainDexList): $(full_classes_pre_proguard_jar) | $(MAINDEXCLASSES)
+$(mainDexList): $(full_classes_pre_proguard_jar) $(MAINDEXCLASSES) $(PROGUARD_DEPS)
$(hide) mkdir -p $(dir $@)
- $(MAINDEXCLASSES) $< 1>$@
+ PROGUARD_HOME=$(PROGUARD_HOME) $(MAINDEXCLASSES) $< 1>$@
echo "com/android/multidexlegacytestapp/Test.class" >> $@
$(built_dex_intermediate): $(mainDexList)
@@ -69,9 +69,9 @@
include $(BUILD_PACKAGE)
-$(mainDexList2): $(full_classes_pre_proguard_jar) | $(MAINDEXCLASSES)
+$(mainDexList2): $(full_classes_pre_proguard_jar) $(MAINDEXCLASSES) $(PROGUARD_DEPS)
$(hide) mkdir -p $(dir $@)
- $(MAINDEXCLASSES) $< 1>$@
+ PROGUARD_HOME=$(PROGUARD_HOME) $(MAINDEXCLASSES) $< 1>$@
echo "com/android/multidexlegacytestapp/Test.class" >> $@
$(built_dex_intermediate): $(mainDexList2)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
index 2ce50b3..da40940 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
@@ -30,14 +30,13 @@
$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
-LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.dex.output.multidex.legacy=true
LOCAL_DEX_PREOPT := false
include $(BUILD_PACKAGE)
-$(mainDexList): $(full_classes_pre_proguard_jar) | $(MAINDEXCLASSES)
+$(mainDexList): $(full_classes_pre_proguard_jar) $(MAINDEXCLASSES) $(PROGUARD_DEPS)
$(hide) mkdir -p $(dir $@)
- $(MAINDEXCLASSES) $< 1>$@
+ PROGUARD_HOME=$(PROGUARD_HOME) $(MAINDEXCLASSES) $< 1>$@
$(built_dex_intermediate): $(mainDexList)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
index 8b0c750..665e22d 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
@@ -35,9 +35,9 @@
include $(BUILD_PACKAGE)
-$(mainDexList): $(full_classes_pre_proguard_jar) | $(MAINDEXCLASSES)
+$(mainDexList): $(full_classes_pre_proguard_jar) $(MAINDEXCLASSES) $(PROGUARD_DEPS)
$(hide) mkdir -p $(dir $@)
- $(MAINDEXCLASSES) $< 1>$@
+ PROGUARD_HOME=$(PROGUARD_HOME) $(MAINDEXCLASSES) $< 1>$@
echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
$(built_dex_intermediate): $(mainDexList)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
index a36c993..c827fa8 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
@@ -35,9 +35,9 @@
include $(BUILD_PACKAGE)
-$(mainDexList): $(full_classes_pre_proguard_jar) | $(MAINDEXCLASSES)
+$(mainDexList): $(full_classes_pre_proguard_jar) $(MAINDEXCLASSES) $(PROGUARD_DEPS)
$(hide) mkdir -p $(dir $@)
- $(MAINDEXCLASSES) $< 1>$@
+ PROGUARD_HOME=$(PROGUARD_HOME) $(MAINDEXCLASSES) $< 1>$@
echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
$(built_dex_intermediate): $(mainDexList)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
index 6b7418c..3d6ad7d 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
@@ -35,9 +35,9 @@
include $(BUILD_PACKAGE)
-$(mainDexList): $(full_classes_pre_proguard_jar) | $(MAINDEXCLASSES)
+$(mainDexList): $(full_classes_pre_proguard_jar) $(MAINDEXCLASSES) $(PROGUARD_DEPS)
$(hide) mkdir -p $(dir $@)
- $(MAINDEXCLASSES) $< 1>$@
+ PROGUARD_HOME=$(PROGUARD_HOME) $(MAINDEXCLASSES) $< 1>$@
echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
$(built_dex_intermediate): $(mainDexList)
diff --git a/location/java/android/location/GnssSingleSatCorrection.java b/location/java/android/location/GnssSingleSatCorrection.java
index 6c757f9..3922d2f 100644
--- a/location/java/android/location/GnssSingleSatCorrection.java
+++ b/location/java/android/location/GnssSingleSatCorrection.java
@@ -16,11 +16,14 @@
package android.location;
+import android.annotation.FloatRange;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.util.Preconditions;
+
/**
* A container with measurement corrections for a single visible satellite
*
@@ -31,9 +34,9 @@
/**
* Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
- * #mSatIsLos}.
+ * #mProbSatIsLos}.
*/
- public static final int HAS_SAT_IS_LOS_MASK = 1 << 0;
+ public static final int HAS_PROB_SAT_IS_LOS_MASK = 1 << 0;
/**
* Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
@@ -78,9 +81,11 @@
private float mCarrierFrequencyHz;
/**
- * True if the satellite is estimated to be in Line-of-Sight condition at the given location.
+ * The probability that the satellite is estimated to be in Line-of-Sight condition at the given
+ * location.
*/
- private boolean mSatIsLos;
+ @FloatRange(from = 0f, to = 1f)
+ private float mProbSatIsLos;
/**
* Excess path length to be subtracted from pseudorange before using it in calculating location.
@@ -103,7 +108,7 @@
mSatId = builder.mSatId;
mConstellationType = builder.mConstellationType;
mCarrierFrequencyHz = builder.mCarrierFrequencyHz;
- mSatIsLos = builder.mSatIsLos;
+ mProbSatIsLos = builder.mProbSatIsLos;
mExcessPathLengthMeters = builder.mExcessPathLengthMeters;
mExcessPathLengthUncertaintyMeters = builder.mExcessPathLengthUncertaintyMeters;
mReflectingPlane = builder.mReflectingPlane;
@@ -152,9 +157,13 @@
return mCarrierFrequencyHz;
}
- /** True if the satellite is line-of-sight */
- public boolean isSatelliteLineOfSight() {
- return mSatIsLos;
+ /**
+ * Returns the probability that the satellite is in line-of-sight condition at the given
+ * location.
+ */
+ @FloatRange(from = 0f, to = 1f)
+ public float getProbSatIsLos() {
+ return mProbSatIsLos;
}
/**
@@ -180,9 +189,9 @@
return mReflectingPlane;
}
- /** Returns {@code true} if {@link #isSatelliteLineOfSight()} is valid. */
+ /** Returns {@code true} if {@link #getProbSatIsLos()} is valid. */
public boolean hasSatelliteLineOfSight() {
- return (mSingleSatCorrectionFlags & HAS_SAT_IS_LOS_MASK) != 0;
+ return (mSingleSatCorrectionFlags & HAS_PROB_SAT_IS_LOS_MASK) != 0;
}
/** Returns {@code true} if {@link #getExcessPathLengthMeters()} is valid. */
@@ -215,7 +224,7 @@
.setConstellationType(parcel.readInt())
.setSatId(parcel.readInt())
.setCarrierFrequencyHz(parcel.readFloat())
- .setSatIsLos(parcel.readBoolean())
+ .setProbSatIsLos(parcel.readFloat())
.setExcessPathLengthMeters(parcel.readFloat())
.setExcessPathLengthUncertaintyMeters(parcel.readFloat())
.setReflectingPlane(
@@ -239,7 +248,7 @@
builder.append(String.format(format, "ConstellationType = ", mConstellationType));
builder.append(String.format(format, "SatId = ", mSatId));
builder.append(String.format(format, "CarrierFrequencyHz = ", mCarrierFrequencyHz));
- builder.append(String.format(format, "SatIsLos = ", mSatIsLos));
+ builder.append(String.format(format, "ProbSatIsLos = ", mProbSatIsLos));
builder.append(String.format(format, "ExcessPathLengthMeters = ", mExcessPathLengthMeters));
builder.append(
String.format(
@@ -256,7 +265,7 @@
parcel.writeInt(mConstellationType);
parcel.writeInt(mSatId);
parcel.writeFloat(mCarrierFrequencyHz);
- parcel.writeBoolean(mSatIsLos);
+ parcel.writeFloat(mProbSatIsLos);
parcel.writeFloat(mExcessPathLengthMeters);
parcel.writeFloat(mExcessPathLengthUncertaintyMeters);
mReflectingPlane.writeToParcel(parcel, flags);
@@ -274,7 +283,7 @@
private int mConstellationType;
private int mSatId;
private float mCarrierFrequencyHz;
- private boolean mSatIsLos;
+ private float mProbSatIsLos;
private float mExcessPathLengthMeters;
private float mExcessPathLengthUncertaintyMeters;
private GnssReflectingPlane mReflectingPlane;
@@ -303,10 +312,16 @@
return this;
}
- /** Sets the line=of-sight state of the satellite */
- public Builder setSatIsLos(boolean satIsLos) {
- mSatIsLos = satIsLos;
- mSingleSatCorrectionFlags = (byte) (mSingleSatCorrectionFlags | HAS_SAT_IS_LOS_MASK);
+ /**
+ * Sets the line-of-sight probability of the satellite at the given location in the range
+ * between 0 and 1.
+ */
+ public Builder setProbSatIsLos(@FloatRange(from = 0f, to = 1f) float probSatIsLos) {
+ Preconditions.checkArgumentInRange(probSatIsLos, 0, 1,
+ "probSatIsLos should be between 0 and 1.");
+ mProbSatIsLos = probSatIsLos;
+ mSingleSatCorrectionFlags =
+ (byte) (mSingleSatCorrectionFlags | HAS_PROB_SAT_IS_LOS_MASK);
return this;
}
diff --git a/location/tests/locationtests/src/android/location/GnssMeasurementCorrectionsTest.java b/location/tests/locationtests/src/android/location/GnssMeasurementCorrectionsTest.java
index c18d58f..d6227bb 100644
--- a/location/tests/locationtests/src/android/location/GnssMeasurementCorrectionsTest.java
+++ b/location/tests/locationtests/src/android/location/GnssMeasurementCorrectionsTest.java
@@ -59,7 +59,7 @@
assertEquals(GnssStatus.CONSTELLATION_GPS, singleSatCorrection.getConstellationType());
assertEquals(11, singleSatCorrection.getSatId());
assertEquals(1575430000f, singleSatCorrection.getCarrierFrequencyHz());
- assertEquals(false, singleSatCorrection.isSatelliteLineOfSight());
+ assertEquals(0.9f, singleSatCorrection.getProbSatIsLos());
assertEquals(50.0f, singleSatCorrection.getExcessPathLengthMeters());
assertEquals(55.0f, singleSatCorrection.getExcessPathLengthUncertaintyMeters());
GnssReflectingPlane reflectingPlane = singleSatCorrection.getReflectingPlane();
@@ -88,7 +88,7 @@
.setConstellationType(GnssStatus.CONSTELLATION_GPS)
.setSatId(11)
.setCarrierFrequencyHz(1575430000f)
- .setSatIsLos(false)
+ .setProbSatIsLos(0.9f)
.setExcessPathLengthMeters(50.0f)
.setExcessPathLengthUncertaintyMeters(55.0f)
.setReflectingPlane(generateTestReflectingPlane());
diff --git a/location/tests/locationtests/src/android/location/GnssSingleSatCorrectionsTest.java b/location/tests/locationtests/src/android/location/GnssSingleSatCorrectionsTest.java
index 2e54ae4..f358806 100644
--- a/location/tests/locationtests/src/android/location/GnssSingleSatCorrectionsTest.java
+++ b/location/tests/locationtests/src/android/location/GnssSingleSatCorrectionsTest.java
@@ -44,7 +44,7 @@
assertEquals(GnssStatus.CONSTELLATION_GALILEO, singleSatCorrection.getConstellationType());
assertEquals(12, singleSatCorrection.getSatId());
assertEquals(1575420000f, singleSatCorrection.getCarrierFrequencyHz());
- assertEquals(true, singleSatCorrection.isSatelliteLineOfSight());
+ assertEquals(0.1f, singleSatCorrection.getProbSatIsLos());
assertEquals(10.0f, singleSatCorrection.getExcessPathLengthMeters());
assertEquals(5.0f, singleSatCorrection.getExcessPathLengthUncertaintyMeters());
GnssReflectingPlane reflectingPlane = singleSatCorrection.getReflectingPlane();
@@ -58,7 +58,7 @@
.setConstellationType(singleSatCorr.getConstellationType())
.setSatId(singleSatCorr.getSatId())
.setCarrierFrequencyHz(singleSatCorr.getCarrierFrequencyHz())
- .setSatIsLos(singleSatCorr.isSatelliteLineOfSight())
+ .setProbSatIsLos(singleSatCorr.getProbSatIsLos())
.setExcessPathLengthMeters(singleSatCorr.getExcessPathLengthMeters())
.setExcessPathLengthUncertaintyMeters(
singleSatCorr.getExcessPathLengthUncertaintyMeters())
@@ -72,7 +72,7 @@
.setConstellationType(GnssStatus.CONSTELLATION_GALILEO)
.setSatId(12)
.setCarrierFrequencyHz(1575420000f)
- .setSatIsLos(true)
+ .setProbSatIsLos(0.1f)
.setExcessPathLengthMeters(10.0f)
.setExcessPathLengthUncertaintyMeters(5.0f)
.setReflectingPlane(GnssReflectingPlaneTest.generateTestReflectingPlane());
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 8ec0e35..9ac147b 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -150,7 +150,7 @@
* consumer end-points. For example, if the application intends to send the images to
* {@link android.media.MediaCodec} or {@link android.media.MediaRecorder} for hardware video
* encoding, the format and usage flag combination needs to be
- * {@link ImageFormat#PRIVATE PRIVATE} and {@link HardwareBuffer#USAGE0_VIDEO_ENCODE}. When an
+ * {@link ImageFormat#PRIVATE PRIVATE} and {@link HardwareBuffer#USAGE_VIDEO_ENCODE}. When an
* {@link ImageReader} object is created with a valid size and such format/usage flag
* combination, the application can send the {@link Image images} to an {@link ImageWriter} that
* is created with the input {@link android.view.Surface} provided by the
@@ -173,7 +173,7 @@
* ImageReaders using other format such as {@link ImageFormat#YUV_420_888 YUV_420_888}.
* </p>
* <p>
- * Note that not all format and usage flag combination is supported by the
+ * Note that not all format and usage flag combinations are supported by the
* {@link ImageReader}. Below are the supported combinations by the {@link ImageReader}
* (assuming the consumer end-points support the such image consumption, e.g., hardware video
* encoding).
@@ -186,13 +186,13 @@
* <td>non-{@link android.graphics.ImageFormat#PRIVATE PRIVATE} formats defined by
* {@link android.graphics.ImageFormat ImageFormat} or
* {@link android.graphics.PixelFormat PixelFormat}</td>
- * <td>{@link HardwareBuffer#USAGE0_CPU_READ} or
- * {@link HardwareBuffer#USAGE0_CPU_READ_OFTEN}</td>
+ * <td>{@link HardwareBuffer#USAGE_CPU_READ_RARELY} or
+ * {@link HardwareBuffer#USAGE_CPU_READ_OFTEN}</td>
* </tr>
* <tr>
* <td>{@link android.graphics.ImageFormat#PRIVATE}</td>
- * <td>{@link HardwareBuffer#USAGE0_VIDEO_ENCODE} or
- * {@link HardwareBuffer#USAGE0_GPU_SAMPLED_IMAGE}, or combined</td>
+ * <td>{@link HardwareBuffer#USAGE_VIDEO_ENCODE} or
+ * {@link HardwareBuffer#USAGE_GPU_SAMPLED_IMAGE}, or combined</td>
* </tr>
* </table>
* Using other combinations may result in {@link IllegalArgumentException}.
@@ -208,11 +208,10 @@
* become available for access through {@link #acquireLatestImage()} or
* {@link #acquireNextImage()}. Must be greater than 0.
* @param usage The intended usage of the images produced by this ImageReader. It needs
- * to be one of the Usage0 defined by {@link HardwareBuffer}, or an
+ * to be one of the Usage defined by {@link HardwareBuffer}, or an
* {@link IllegalArgumentException} will be thrown.
* @see Image
* @see HardwareBuffer
- * @hide
*/
public static ImageReader newInstance(int width, int height, int format, int maxImages,
long usage) {
diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java
index 4c0153f..dd09afc 100644
--- a/media/java/android/media/ImageWriter.java
+++ b/media/java/android/media/ImageWriter.java
@@ -168,7 +168,6 @@
* {@link ImageFormat} or {@link PixelFormat}.
*
* @return a new ImageWriter instance.
- * @hide
*/
public static ImageWriter newInstance(Surface surface, int maxImages, int format) {
if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) {
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 9245c30..e2ba23e 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -47,8 +47,6 @@
<dimen name="bottom_text_spacing_digital">0dp</dimen>
<!-- Slice subtitle -->
<dimen name="widget_label_font_size">16dp</dimen>
- <!-- Slice offset when pulsing -->
- <dimen name="widget_pulsing_bottom_padding">48dp</dimen>
<!-- Clock without header -->
<dimen name="widget_big_font_size">64dp</dimen>
<!-- Clock with header -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 5a00b45..ab0bbe1 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -66,9 +66,7 @@
<item name="status_bar_icon_scale_factor" format="float" type="dimen">1.0</item>
<dimen name="group_overflow_number_size">@*android:dimen/notification_text_size</dimen>
- <dimen name="group_overflow_number_size_dark">16sp</dimen>
<dimen name="group_overflow_number_padding">@*android:dimen/notification_content_margin_end</dimen>
- <dimen name="group_overflow_number_extra_padding_dark">@*android:dimen/notification_extra_margin_ambient</dimen>
<!-- max height of a notification such that the content can still fade out when closing -->
<dimen name="max_notification_fadeout_height">100dp</dimen>
@@ -94,9 +92,6 @@
<!-- Height of a large notification in the status bar -->
<dimen name="notification_max_height">294dp</dimen>
- <!-- Height of an ambient notification on ambient display -->
- <dimen name="notification_ambient_height">400dp</dimen>
-
<!-- Height of a heads up notification in the status bar for legacy custom views -->
<dimen name="notification_max_heads_up_height_legacy">128dp</dimen>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 22a0b36..fa675b7 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -64,48 +64,16 @@
<item name="hybridNotificationTextStyle">@style/hybrid_notification_text</item>
</style>
- <style name="HybridNotification.Ambient">
- <item name="hybridNotificationStyle">@style/hybrid_notification_ambient</item>
- <item name="hybridNotificationTitleStyle">@style/hybrid_notification_title_ambient</item>
- <item name="hybridNotificationTextStyle">@style/hybrid_notification_text_ambient</item>
- </style>
-
- <style name="hybrid_notification_ambient">
- <item name="android:paddingStart">@*android:dimen/notification_extra_margin_ambient</item>
- <item name="android:paddingEnd">@*android:dimen/notification_extra_margin_ambient</item>
- <item name="android:orientation">vertical</item>
- </style>
-
<style name="hybrid_notification">
<item name="android:paddingStart">@*android:dimen/notification_content_margin_start</item>
<item name="android:paddingEnd">12dp</item>
</style>
- <style name="hybrid_notification_title_ambient">
- <item name="android:layout_marginTop">@*android:dimen/notification_header_margin_top_ambient</item>
- <item name="android:paddingStart">@*android:dimen/notification_content_margin_start</item>
- <item name="android:paddingEnd">@*android:dimen/notification_content_margin_end</item>
- <item name="android:textAppearance">@*android:style/Notification.Header.Ambient</item>
- <item name="android:layout_gravity">top|center_horizontal</item>
- <item name="android:textSize">@*android:dimen/notification_ambient_title_text_size</item>
- <item name="android:textColor">#ffffffff</item>
- </style>
-
<style name="hybrid_notification_title">
<item name="android:paddingEnd">4dp</item>
<item name="android:textAppearance">@*android:style/TextAppearance.Material.Notification.Title</item>
</style>
- <style name="hybrid_notification_text_ambient">
- <item name="android:paddingStart">@*android:dimen/notification_content_margin_start</item>
- <item name="android:paddingEnd">@*android:dimen/notification_content_margin_end</item>
- <item name="android:textSize">@*android:dimen/notification_ambient_text_size</item>
- <item name="android:textColor">#eeffffff</item>
- <item name="android:gravity">top|center_horizontal</item>
- <item name="android:ellipsize">end</item>
- <item name="android:maxLines">3</item>
- </style>
-
<style name="hybrid_notification_text"
parent="@*android:style/Widget.Material.Notification.Text">
<item name="android:paddingEnd">4dp</item>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index 669e6ff..bac7844 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -90,7 +90,7 @@
*/
private Runnable mContentChangeListener;
private Slice mSlice;
- private boolean mPulsing;
+ private boolean mHasHeader;
public KeyguardSliceView(Context context) {
this(context, null, 0);
@@ -150,10 +150,18 @@
Dependency.get(ConfigurationController.class).removeCallback(this);
}
+ /**
+ * Returns whether the current visible slice has a title/header.
+ */
+ public boolean hasHeader() {
+ return mHasHeader;
+ }
+
private void showSlice() {
Trace.beginSection("KeyguardSliceView#showSlice");
- if (mPulsing || mSlice == null) {
+ if (mSlice == null) {
mRow.setVisibility(GONE);
+ mHasHeader = false;
if (mContentChangeListener != null) {
mContentChangeListener.run();
}
@@ -162,7 +170,7 @@
ListContent lc = new ListContent(getContext(), mSlice);
SliceContent headerContent = lc.getHeader();
- boolean hasHeader = headerContent != null
+ mHasHeader = headerContent != null
&& !headerContent.getSliceItem().hasHint(HINT_LIST_ITEM);
List<SliceContent> subItems = new ArrayList<>();
for (int i = 0; i < lc.getRowItems().size(); i++) {
@@ -177,7 +185,7 @@
mClickActions.clear();
final int subItemsCount = subItems.size();
final int blendedColor = getTextColor();
- final int startIndex = hasHeader ? 1 : 0; // First item is header; skip it
+ final int startIndex = mHasHeader ? 1 : 0; // First item is header; skip it
mRow.setVisibility(subItemsCount > 0 ? VISIBLE : GONE);
for (int i = startIndex; i < subItemsCount; i++) {
RowContent rc = (RowContent) subItems.get(i);
@@ -189,7 +197,7 @@
button = new KeyguardSliceButton(mContext);
button.setTextColor(blendedColor);
button.setTag(itemTag);
- final int viewIndex = i - (hasHeader ? 1 : 0);
+ final int viewIndex = i - (mHasHeader ? 1 : 0);
mRow.addView(button, viewIndex);
}
@@ -234,18 +242,6 @@
Trace.endSection();
}
- public void setPulsing(boolean pulsing, boolean animate) {
- mPulsing = pulsing;
- LayoutTransition transition = getLayoutTransition();
- if (!animate) {
- setLayoutTransition(null);
- }
- showSlice();
- if (!animate) {
- setLayoutTransition(transition);
- }
- }
-
public void setDarkAmount(float darkAmount) {
mDarkAmount = darkAmount;
mRow.setDarkAmount(darkAmount);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 7ae4c41..bb549ad 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -72,7 +72,6 @@
private ArraySet<View> mVisibleInDoze;
private boolean mPulsing;
- private boolean mWasPulsing;
private float mDarkAmount = 0;
private int mTextColor;
private int mLastLayoutHeight;
@@ -210,7 +209,7 @@
private void onSliceContentChanged() {
LinearLayout.LayoutParams layoutParams =
(LinearLayout.LayoutParams) mClockView.getLayoutParams();
- layoutParams.bottomMargin = mPulsing ? mSmallClockPadding : 0;
+ layoutParams.bottomMargin = mKeyguardSlice.hasHeader() ? mSmallClockPadding : 0;
mClockView.setLayoutParams(layoutParams);
}
@@ -220,16 +219,16 @@
@Override
public void onLayoutChange(View view, int left, int top, int right, int bottom,
int oldLeft, int oldTop, int oldRight, int oldBottom) {
- int heightOffset = mPulsing || mWasPulsing ? 0 : getHeight() - mLastLayoutHeight;
+ boolean smallClock = mKeyguardSlice.hasHeader();
+ int heightOffset = smallClock ? 0 : getHeight() - mLastLayoutHeight;
long duration = KeyguardSliceView.DEFAULT_ANIM_DURATION;
- long delay = mPulsing || mWasPulsing ? 0 : duration / 4;
- mWasPulsing = false;
+ long delay = smallClock ? 0 : duration / 4;
boolean shouldAnimate = mKeyguardSlice.getLayoutTransition() != null
&& mKeyguardSlice.getLayoutTransition().isRunning();
if (view == mClockView) {
- float clockScale = mPulsing ? mSmallClockScale : 1;
- Paint.Style style = mPulsing ? Paint.Style.FILL_AND_STROKE : Paint.Style.FILL;
+ float clockScale = smallClock ? mSmallClockScale : 1;
+ Paint.Style style = smallClock ? Paint.Style.FILL_AND_STROKE : Paint.Style.FILL;
mClockView.animate().cancel();
if (shouldAnimate) {
mClockView.setY(oldTop + heightOffset);
@@ -434,15 +433,11 @@
}
}
- public void setPulsing(boolean pulsing, boolean animate) {
+ public void setPulsing(boolean pulsing) {
if (mPulsing == pulsing) {
return;
}
- if (mPulsing) {
- mWasPulsing = true;
- }
mPulsing = pulsing;
- mKeyguardSlice.setPulsing(pulsing, animate);
updateDozeVisibleViews();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index bd9ca1a..9ef9c94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -65,12 +65,12 @@
private static final String TAG = "NotificationShelf";
private static final long SHELF_IN_TRANSLATION_DURATION = 200;
- private boolean mDark;
private NotificationIconContainer mShelfIcons;
private int[] mTmp = new int[2];
private boolean mHideBackground;
private int mIconAppearTopPadding;
private int mShelfAppearTranslation;
+ private float mDarkShelfPadding;
private int mStatusBarHeight;
private int mStatusBarPaddingStart;
private AmbientState mAmbientState;
@@ -140,6 +140,7 @@
mStatusBarPaddingStart = res.getDimensionPixelOffset(R.dimen.status_bar_padding_start);
mPaddingBetweenElements = res.getDimensionPixelSize(R.dimen.notification_divider_height);
mShelfAppearTranslation = res.getDimensionPixelSize(R.dimen.shelf_appear_translation);
+ mDarkShelfPadding = res.getDimensionPixelSize(R.dimen.widget_bottom_separator_padding);
ViewGroup.LayoutParams layoutParams = getLayoutParams();
layoutParams.height = res.getDimensionPixelOffset(R.dimen.notification_shelf_height);
@@ -165,11 +166,11 @@
@Override
public void setDark(boolean dark, boolean fade, long delay) {
- super.setDark(dark, fade, delay);
if (mDark == dark) return;
- mDark = dark;
+ super.setDark(dark, fade, delay);
mShelfIcons.setDark(dark, fade, delay);
updateInteractiveness();
+ updateOutline();
}
/**
@@ -218,10 +219,9 @@
float awakenTranslation = Math.max(Math.min(viewEnd, maxShelfEnd) - viewState.height,
getFullyClosedTranslation());
- float darkTranslation = mAmbientState.getDarkTopPadding();
float yRatio = mAmbientState.hasPulsingNotifications() ?
0 : mAmbientState.getDarkAmount();
- viewState.yTranslation = MathUtils.lerp(awakenTranslation, darkTranslation, yRatio);
+ viewState.yTranslation = awakenTranslation + mDarkShelfPadding * yRatio;
viewState.zTranslation = ambientState.getBaseZHeight();
// For the small display size, it's not enough to make the icon not covered by
// the top cutout so the denominator add the height of cutout.
@@ -763,18 +763,14 @@
}
}
- public boolean hidesBackground() {
- return mHideBackground;
- }
-
@Override
protected boolean needsOutline() {
- return !mHideBackground && super.needsOutline();
+ return !mHideBackground && !mDark && super.needsOutline();
}
@Override
protected boolean shouldHideBackground() {
- return super.shouldHideBackground() || mHideBackground;
+ return super.shouldHideBackground() || mHideBackground || mDark;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 8b0a682..c34d567 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -105,7 +105,7 @@
private final DoubleTapHelper mDoubleTapHelper;
private boolean mDimmed;
- private boolean mDark;
+ protected boolean mDark;
protected int mBgTint = NO_COLOR;
private float mBgAlpha = 1f;
@@ -140,7 +140,6 @@
private FalsingManager mFalsingManager;
private float mNormalBackgroundVisibilityAmount;
- private ValueAnimator mFadeInFromDarkAnimator;
private float mDimmedBackgroundFadeInAmount = -1;
private ValueAnimator.AnimatorUpdateListener mBackgroundVisibilityUpdater
= new ValueAnimator.AnimatorUpdateListener() {
@@ -150,22 +149,6 @@
mDimmedBackgroundFadeInAmount = mBackgroundDimmed.getAlpha();
}
};
- private AnimatorListenerAdapter mFadeInEndListener = new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- mFadeInFromDarkAnimator = null;
- mDimmedBackgroundFadeInAmount = -1;
- updateBackground();
- }
- };
- private ValueAnimator.AnimatorUpdateListener mUpdateOutlineListener
- = new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- updateOutlineAlpha();
- }
- };
private FakeShadowView mFakeShadow;
private int mCurrentBackgroundTint;
private int mTargetTint;
@@ -465,22 +448,11 @@
mDark = dark;
updateBackground();
updateBackgroundTint(false);
- if (!dark && fade && !shouldHideBackground()) {
- fadeInFromDark(delay);
- }
- updateOutlineAlpha();
}
private void updateOutlineAlpha() {
- if (mDark) {
- setOutlineAlpha(0f);
- return;
- }
float alpha = NotificationStackScrollLayout.BACKGROUND_ALPHA_DIMMED;
alpha = (alpha + (1.0f - alpha) * mNormalBackgroundVisibilityAmount);
- if (mFadeInFromDarkAnimator != null) {
- alpha *= mFadeInFromDarkAnimator.getAnimatedFraction();
- }
setOutlineAlpha(alpha);
}
@@ -638,36 +610,6 @@
}
/**
- * Fades in the background when exiting dark mode.
- */
- private void fadeInFromDark(long delay) {
- final View background = mDimmed ? mBackgroundDimmed : mBackgroundNormal;
- background.setAlpha(0f);
- mBackgroundVisibilityUpdater.onAnimationUpdate(null);
- background.animate()
- .alpha(1f)
- .setDuration(DARK_ANIMATION_LENGTH)
- .setStartDelay(delay)
- .setInterpolator(Interpolators.ALPHA_IN)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationCancel(Animator animation) {
- // Jump state if we are cancelled
- background.setAlpha(1f);
- }
- })
- .setUpdateListener(mBackgroundVisibilityUpdater)
- .start();
- mFadeInFromDarkAnimator = TimeAnimator.ofFloat(0.0f, 1.0f);
- mFadeInFromDarkAnimator.setDuration(DARK_ANIMATION_LENGTH);
- mFadeInFromDarkAnimator.setStartDelay(delay);
- mFadeInFromDarkAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
- mFadeInFromDarkAnimator.addListener(mFadeInEndListener);
- mFadeInFromDarkAnimator.addUpdateListener(mUpdateOutlineListener);
- mFadeInFromDarkAnimator.start();
- }
-
- /**
* Fades the background when the dimmed state changes.
*/
private void fadeDimmedBackground() {
@@ -708,9 +650,7 @@
public void onAnimationEnd(Animator animation) {
updateBackground();
mBackgroundAnimator = null;
- if (mFadeInFromDarkAnimator == null) {
- mDimmedBackgroundFadeInAmount = -1;
- }
+ mDimmedBackgroundFadeInAmount = -1;
}
});
mBackgroundAnimator.addUpdateListener(mBackgroundVisibilityUpdater);
@@ -736,7 +676,7 @@
mBackgroundNormal.setVisibility(mActivated ? VISIBLE : INVISIBLE);
} else if (mDimmed) {
// When groups are animating to the expanded state from the lockscreen, show the
- // normal background instead of the dimmed background
+ // normal background instead of the dimmed background.
final boolean dontShowDimmed = isGroupExpansionChanging() && isChildInGroup();
mBackgroundDimmed.setVisibility(dontShowDimmed ? View.INVISIBLE : View.VISIBLE);
mBackgroundNormal.setVisibility((mActivated || dontShowDimmed)
@@ -760,7 +700,7 @@
}
protected boolean shouldHideBackground() {
- return mDark;
+ return false;
}
private void cancelFadeAnimations() {
@@ -1023,14 +963,11 @@
/**
* @param withTint should a possible tint be factored in?
- * @param withOverRide should the value be interpolated with {@link #mOverrideTint}
+ * @param withOverride should the value be interpolated with {@link #mOverrideTint}
* @return the calculated background color
*/
- private int calculateBgColor(boolean withTint, boolean withOverRide) {
- if (withTint && mDark) {
- return getContext().getColor(R.color.notification_material_background_dark_color);
- }
- if (withOverRide && mOverrideTint != NO_COLOR) {
+ private int calculateBgColor(boolean withTint, boolean withOverride) {
+ if (withOverride && mOverrideTint != NO_COLOR) {
int defaultTint = calculateBgColor(withTint, false);
return NotificationUtils.interpolateColors(defaultTint, mOverrideTint, mOverrideAmount);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index df0189f..296c061 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -132,7 +132,6 @@
}
private LayoutListener mLayoutListener;
- private boolean mDark;
private boolean mLowPriorityStateUpdated;
private final NotificationInflater mNotificationInflater;
private int mIconTransformContentShift;
@@ -146,7 +145,6 @@
private int mNotificationMinHeight;
private int mNotificationMinHeightLarge;
private int mNotificationMaxHeight;
- private int mNotificationAmbientHeight;
private int mIncreasedPaddingBetweenElements;
private int mNotificationLaunchHeight;
private boolean mMustStayOnScreen;
@@ -677,8 +675,7 @@
if (headsUpWrapper != null) {
headsUpHeight = Math.max(headsUpHeight, headsUpWrapper.getMinLayoutHeight());
}
- layout.setHeights(minHeight, headsUpHeight, mNotificationMaxHeight,
- mNotificationAmbientHeight);
+ layout.setHeights(minHeight, headsUpHeight, mNotificationMaxHeight, headsUpHeight);
}
public StatusBarNotification getStatusBarNotification() {
@@ -1647,8 +1644,6 @@
R.dimen.notification_min_height_increased);
mNotificationMaxHeight = NotificationUtils.getFontScaledHeight(mContext,
R.dimen.notification_max_height);
- mNotificationAmbientHeight = NotificationUtils.getFontScaledHeight(mContext,
- R.dimen.notification_ambient_height);
mMaxHeadsUpHeightBeforeN = NotificationUtils.getFontScaledHeight(mContext,
R.dimen.notification_max_heads_up_height_legacy);
mMaxHeadsUpHeightBeforeP = NotificationUtils.getFontScaledHeight(mContext,
@@ -2008,8 +2003,10 @@
@Override
public void setDark(boolean dark, boolean fade, long delay) {
+ if (mDark == dark) {
+ return;
+ }
super.setDark(dark, fade, delay);
- mDark = dark;
if (!mIsAmbientPulsing) {
// Only fade the showing view of the pulsing notification.
fade = false;
@@ -2018,9 +2015,6 @@
if (showing != null) {
showing.setDark(dark, fade, delay);
}
- if (mIsSummaryWithChildren) {
- mChildrenContainer.setDark(dark, fade, delay);
- }
updateShelfIconColor();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java
index 33badaf..90ff4a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java
@@ -39,14 +39,10 @@
private final NotificationDozeHelper mDozer;
private final ViewGroup mParent;
- private float mOverflowNumberSizeDark;
- private int mOverflowNumberPaddingDark;
private float mOverflowNumberSize;
private int mOverflowNumberPadding;
private int mOverflowNumberColor;
- private int mOverflowNumberColorDark;
- private float mDarkAmount = 0f;
public HybridGroupManager(Context ctx, ViewGroup parent) {
mContext = ctx;
@@ -59,12 +55,8 @@
Resources res = mContext.getResources();
mOverflowNumberSize = res.getDimensionPixelSize(
R.dimen.group_overflow_number_size);
- mOverflowNumberSizeDark = res.getDimensionPixelSize(
- R.dimen.group_overflow_number_size_dark);
mOverflowNumberPadding = res.getDimensionPixelSize(
R.dimen.group_overflow_number_padding);
- mOverflowNumberPaddingDark = mOverflowNumberPadding + res.getDimensionPixelSize(
- R.dimen.group_overflow_number_extra_padding_dark);
}
private HybridNotificationView inflateHybridViewWithStyle(int style) {
@@ -86,13 +78,11 @@
}
private void updateOverFlowNumberColor(TextView numberView) {
- numberView.setTextColor(NotificationUtils.interpolateColors(
- mOverflowNumberColor, mOverflowNumberColorDark, mDarkAmount));
+ numberView.setTextColor(mOverflowNumberColor);
}
- public void setOverflowNumberColor(TextView numberView, int colorRegular, int colorDark) {
+ public void setOverflowNumberColor(TextView numberView, int colorRegular) {
mOverflowNumberColor = colorRegular;
- mOverflowNumberColorDark = colorDark;
if (numberView != null) {
updateOverFlowNumberColor(numberView);
}
@@ -107,7 +97,7 @@
public HybridNotificationView bindAmbientFromNotification(HybridNotificationView reusableView,
Notification notification) {
return bindFromNotificationWithStyle(reusableView, notification,
- R.style.HybridNotification_Ambient);
+ R.style.HybridNotification);
}
private HybridNotificationView bindFromNotificationWithStyle(
@@ -150,6 +140,11 @@
R.plurals.notification_group_overflow_description, number), number);
reusableView.setContentDescription(contentDescription);
+ reusableView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mOverflowNumberSize);
+ reusableView.setPaddingRelative(reusableView.getPaddingStart(),
+ reusableView.getPaddingTop(), mOverflowNumberPadding,
+ reusableView.getPaddingBottom());
+ updateOverFlowNumberColor(reusableView);
return reusableView;
}
@@ -163,16 +158,4 @@
}
return titleView;
}
-
- public void setOverflowNumberDark(TextView view, boolean dark, boolean fade, long delay) {
- mDozer.setIntensityDark((f)->{
- mDarkAmount = f;
- updateOverFlowNumberColor(view);
- }, dark, fade, delay, view);
- view.setTextSize(TypedValue.COMPLEX_UNIT_PX,
- dark ? mOverflowNumberSizeDark : mOverflowNumberSize);
- int paddingEnd = dark ? mOverflowNumberPaddingDark : mOverflowNumberPadding;
- view.setPaddingRelative(view.getPaddingStart(), view.getPaddingTop(), paddingEnd,
- view.getPaddingBottom());
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index cbec37e..1b5013d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -75,7 +75,6 @@
private int mIntrinsicPadding;
private int mExpandAnimationTopChange;
private ExpandableNotificationRow mExpandingNotification;
- private int mDarkTopPadding;
private float mDarkAmount;
private boolean mAppearing;
@@ -351,7 +350,8 @@
}
public boolean hasPulsingNotifications() {
- return mPulsing;
+ return mPulsing && mAmbientPulseManager != null
+ && mAmbientPulseManager.hasNotifications();
}
public void setPulsing(boolean hasPulsing) {
@@ -458,14 +458,6 @@
return mDarkAmount != 0;
}
- public void setDarkTopPadding(int darkTopPadding) {
- mDarkTopPadding = darkTopPadding;
- }
-
- public int getDarkTopPadding() {
- return mDarkTopPadding;
- }
-
public void setAppearing(boolean appearing) {
mAppearing = appearing;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index 5118036..8ffada4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -316,7 +316,7 @@
StatusBarNotification notification = mContainingNotification.getStatusBarNotification();
final Notification.Builder builder = Notification.Builder.recoverBuilder(getContext(),
notification.getNotification());
- RemoteViews header = builder.makeNotificationHeader(false /* ambient */);
+ RemoteViews header = builder.makeNotificationHeader();
if (mNotificationHeader == null) {
mNotificationHeader = (NotificationHeaderView) header.apply(getContext(), this);
final View expandButton = mNotificationHeader.findViewById(
@@ -344,7 +344,7 @@
builder = Notification.Builder.recoverBuilder(getContext(),
notification.getNotification());
}
- header = builder.makeNotificationHeader(true /* ambient */);
+ header = builder.makeNotificationHeader();
if (mNotificationHeaderAmbient == null) {
mNotificationHeaderAmbient = (ViewGroup) header.apply(getContext(), this);
mNotificationHeaderWrapperAmbient = NotificationViewWrapper.wrap(getContext(),
@@ -1171,12 +1171,6 @@
return mIsLowPriority && !mContainingNotification.isExpanded();
}
- public void setDark(boolean dark, boolean fade, long delay) {
- if (mOverflowNumber != null) {
- mHybridGroupManager.setOverflowNumberDark(mOverflowNumber, dark, fade, delay);
- }
- }
-
public void reInflateViews(OnClickListener listener, StatusBarNotification notification) {
if (mNotificationHeader != null) {
removeView(mNotificationHeader);
@@ -1227,8 +1221,7 @@
public void onNotificationUpdated() {
mHybridGroupManager.setOverflowNumberColor(mOverflowNumber,
- mContainingNotification.getNotificationColor(),
- mContainingNotification.getNotificationColorAmbient());
+ mContainingNotification.getNotificationColor());
}
public int getPositionInLinearLayout(View childInGroup) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
index 9418601..c5ab9f6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
@@ -18,6 +18,7 @@
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.NUM_SECTIONS;
+import com.android.systemui.statusbar.AmbientPulseManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -26,26 +27,34 @@
import java.util.HashSet;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
/**
* A class that manages the roundness for notification views
*/
-class NotificationRoundnessManager implements OnHeadsUpChangedListener {
+@Singleton
+class NotificationRoundnessManager implements OnHeadsUpChangedListener,
+ AmbientPulseManager.OnAmbientChangedListener {
+ private final ActivatableNotificationView[] mFirstInSectionViews;
+ private final ActivatableNotificationView[] mLastInSectionViews;
+ private final ActivatableNotificationView[] mTmpFirstInSectionViews;
+ private final ActivatableNotificationView[] mTmpLastInSectionViews;
private boolean mExpanded;
- private ActivatableNotificationView[] mFirstInSectionViews;
- private ActivatableNotificationView[] mLastInSectionViews;
- private ActivatableNotificationView[] mTmpFirstInSectionViews;
- private ActivatableNotificationView[] mTmpLastInSectionViews;
private HashSet<ExpandableView> mAnimatedChildren;
private Runnable mRoundingChangedCallback;
private ExpandableNotificationRow mTrackedHeadsUp;
+ private ActivatableNotificationView mTrackedAmbient;
private float mAppearFraction;
- NotificationRoundnessManager() {
+ @Inject
+ NotificationRoundnessManager(AmbientPulseManager ambientPulseManager) {
mFirstInSectionViews = new ActivatableNotificationView[NUM_SECTIONS];
mLastInSectionViews = new ActivatableNotificationView[NUM_SECTIONS];
mTmpFirstInSectionViews = new ActivatableNotificationView[NUM_SECTIONS];
mTmpLastInSectionViews = new ActivatableNotificationView[NUM_SECTIONS];
+ ambientPulseManager.addListener(this);
}
@Override
@@ -63,6 +72,17 @@
updateView(row, false /* animate */);
}
+ @Override
+ public void onAmbientStateChanged(NotificationEntry entry, boolean isPulsing) {
+ ActivatableNotificationView row = entry.getRow();
+ if (isPulsing) {
+ mTrackedAmbient = row;
+ } else if (mTrackedAmbient == row) {
+ mTrackedAmbient = null;
+ }
+ updateView(row, false /* animate */);
+ }
+
private void updateView(ActivatableNotificationView view, boolean animate) {
boolean changed = updateViewWithoutCallback(view, animate);
if (changed) {
@@ -125,6 +145,9 @@
// rounded.
return 1.0f;
}
+ if (view == mTrackedAmbient) {
+ return 1.0f;
+ }
return 0.0f;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index df8ec91..d066567 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -201,12 +201,7 @@
private int mPaddingBetweenElements;
private int mIncreasedPaddingBetweenElements;
private int mMaxTopPadding;
- private int mRegularTopPadding;
- private int mDarkTopPadding;
- // Current padding, will be either mRegularTopPadding or mDarkTopPadding
private int mTopPadding;
- // Distance between AOD separator and shelf
- private int mDarkShelfPadding;
private int mBottomMargin;
private int mBottomInset = 0;
private float mQsExpansionFraction;
@@ -318,7 +313,7 @@
private HashSet<Pair<ExpandableNotificationRow, Boolean>> mHeadsUpChangeAnimations
= new HashSet<>();
private HeadsUpManagerPhone mHeadsUpManager;
- private NotificationRoundnessManager mRoundnessManager = new NotificationRoundnessManager();
+ private final NotificationRoundnessManager mRoundnessManager;
private boolean mTrackingHeadsUp;
private ScrimController mScrimController;
private boolean mForceNoOverlappingRendering;
@@ -469,7 +464,8 @@
public NotificationStackScrollLayout(
@Named(VIEW_CONTEXT) Context context,
AttributeSet attrs,
- @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress) {
+ @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress,
+ NotificationRoundnessManager notificationRoundnessManager) {
super(context, attrs, 0, 0);
Resources res = getResources();
@@ -480,6 +476,7 @@
}
mAmbientState = new AmbientState(context);
+ mRoundnessManager = notificationRoundnessManager;
mBgColor = context.getColor(R.color.notification_shade_background_color);
int minHeight = res.getDimensionPixelSize(R.dimen.notification_min_height);
int maxHeight = res.getDimensionPixelSize(R.dimen.notification_max_height);
@@ -496,7 +493,6 @@
res.getBoolean(R.bool.config_drawNotificationBackground);
mFadeNotificationsOnDismiss =
res.getBoolean(R.bool.config_fadeNotificationsOnDismiss);
- mDarkShelfPadding = res.getDimensionPixelSize(R.dimen.widget_bottom_separator_padding);
mRoundnessManager.setAnimatedChildren(mChildrenToAddAnimated);
mRoundnessManager.setOnRoundingChangedCallback(this::invalidate);
addOnExpandedHeightListener(mRoundnessManager::setExpanded);
@@ -685,7 +681,7 @@
int lockScreenTop = mSections[0].getCurrentBounds().top;
int lockScreenBottom = mSections[NUM_SECTIONS - 1].getCurrentBounds().bottom;
int darkLeft = getWidth() / 2;
- int darkTop = mRegularTopPadding;
+ int darkTop = mTopPadding;
float yProgress = 1 - mInterpolatedDarkAmount;
float xProgress = mDarkXInterpolator.getInterpolation(
@@ -953,8 +949,6 @@
@ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM)
private void updateAlgorithmHeightAndPadding() {
- mTopPadding = (int) MathUtils.lerp(mRegularTopPadding, mDarkTopPadding,
- mInterpolatedDarkAmount);
mAmbientState.setLayoutHeight(getLayoutHeight());
updateAlgorithmLayoutMinHeight();
mAmbientState.setTopPadding(mTopPadding);
@@ -1092,10 +1086,8 @@
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void setTopPadding(int topPadding, boolean animate) {
- if (mRegularTopPadding != topPadding) {
- mRegularTopPadding = topPadding;
- mDarkTopPadding = topPadding + mDarkShelfPadding;
- mAmbientState.setDarkTopPadding(mDarkTopPadding);
+ if (mTopPadding != topPadding) {
+ mTopPadding = topPadding;
updateAlgorithmHeightAndPadding();
updateContentHeight();
if (animate && mAnimationsEnabled && mIsExpanded) {
@@ -2060,10 +2052,7 @@
}
mIntrinsicContentHeight = height;
- // We don't want to use the toppadding since that might be interpolated and we want
- // to take the final value of the animation.
- int topPadding = mAmbientState.isFullyDark() ? mDarkTopPadding : mRegularTopPadding;
- mContentHeight = height + topPadding + mBottomMargin;
+ mContentHeight = height + mTopPadding + mBottomMargin;
updateScrollability();
clampScrollPosition();
mAmbientState.setLayoutMaxHeight(mContentHeight);
@@ -5222,9 +5211,6 @@
// another "changeViewPosition" call is ever added.
changeViewPosition(mShelf,
getChildCount() - offsetFromEnd);
-
- // Scrim opacity varies based on notification count
- mScrimController.setNotificationCount(getNotGoneChildCount());
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
index 19fce48..b4c205a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
@@ -426,6 +426,9 @@
mTmpState.yTranslation += mPulsingAppearingTranslation;
mTmpState.alpha = 0;
mTmpState.applyToView(changingView);
+
+ mTmpState.copyFrom(mShelf.getViewState());
+ mTmpState.applyToView(mShelf);
}
} else if (event.animationType == NotificationStackScrollLayout
.AnimationEvent.ANIMATION_TYPE_PULSE_DISAPPEAR) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 6f2b63d..1049773 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -158,8 +158,7 @@
* @return duration in millis.
*/
public long getWallpaperAodDuration() {
- if (mAmbientDisplayConfiguration.wakeLockScreenGestureEnabled(UserHandle.USER_CURRENT)
- || shouldControlScreenOff()) {
+ if (shouldControlScreenOff()) {
return DozeScreenState.ENTER_DOZE_HIDE_WALLPAPER_DELAY;
}
return mAlwaysOnPolicy.wallpaperVisibilityDuration;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index 577e8d6..280dda0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -84,14 +84,6 @@
public void onCancelled() {
pulseFinished();
}
-
- /**
- * Whether to fade out wallpaper.
- */
- @Override
- public boolean isFadeOutWallpaper() {
- return mPulseReason == DozeLog.PULSE_REASON_DOCKING;
- }
};
public DozeScrimController(DozeParameters dozeParameters) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index a81b7e5..c68fdd4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -91,11 +91,6 @@
private int mBurnInPreventionOffsetY;
/**
- * Clock vertical padding when pulsing.
- */
- private int mPulsingPadding;
-
- /**
* Doze/AOD transition amount.
*/
private float mDarkAmount;
@@ -105,10 +100,6 @@
*/
private boolean mCurrentlySecure;
- /**
- * Dozing and receiving a notification (AOD notification.)
- */
- private boolean mPulsing;
private float mEmptyDragAmount;
/**
@@ -123,13 +114,11 @@
R.dimen.burn_in_prevention_offset_x);
mBurnInPreventionOffsetY = res.getDimensionPixelSize(
R.dimen.burn_in_prevention_offset_y);
- mPulsingPadding = res.getDimensionPixelSize(
- R.dimen.widget_pulsing_bottom_padding);
}
public void setup(int minTopMargin, int maxShadeBottom, int notificationStackHeight,
float panelExpansion, int parentHeight, int keyguardStatusHeight, float dark,
- boolean secure, boolean pulsing, float emptyDragAmount) {
+ boolean secure, float emptyDragAmount) {
mMinTopMargin = minTopMargin + mContainerTopPadding;
mMaxShadeBottom = maxShadeBottom;
mNotificationStackHeight = notificationStackHeight;
@@ -138,7 +127,6 @@
mKeyguardStatusHeight = keyguardStatusHeight;
mDarkAmount = dark;
mCurrentlySecure = secure;
- mPulsing = pulsing;
mEmptyDragAmount = emptyDragAmount;
}
@@ -146,7 +134,7 @@
final int y = getClockY();
result.clockY = y;
result.clockAlpha = getClockAlpha(y);
- result.stackScrollerPadding = y + (mPulsing ? mPulsingPadding : mKeyguardStatusHeight);
+ result.stackScrollerPadding = y + mKeyguardStatusHeight;
result.clockX = (int) interpolate(0, burnInPreventionOffsetX(), mDarkAmount);
}
@@ -185,9 +173,6 @@
private int getClockY() {
// Dark: Align the bottom edge of the clock at about half of the screen:
float clockYDark = getMaxClockY() + burnInPreventionOffsetY();
- if (mPulsing) {
- clockYDark -= mPulsingPadding;
- }
clockYDark = MathUtils.max(0, clockYDark);
float clockYRegular = getExpandedClockPosition();
@@ -230,11 +215,6 @@
- mBurnInPreventionOffsetX;
}
- @VisibleForTesting
- void setPulsingPadding(int padding) {
- mPulsingPadding = padding;
- }
-
public static class Result {
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 32cc0e6..0d5ebb9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -579,7 +579,6 @@
mKeyguardStatusView.getHeight(),
mInterpolatedDarkAmount,
mStatusBar.isKeyguardCurrentlySecure(),
- mPulsing,
mEmptyDragAmount);
mClockPositionAlgorithm.run(mClockPositionResult);
PropertyAnimator.setProperty(mKeyguardStatusView, AnimatableProperty.X,
@@ -595,7 +594,8 @@
stackScrollerPadding = mClockPositionResult.stackScrollerPadding;
}
mNotificationStackScroller.setIntrinsicPadding(stackScrollerPadding);
- mNotificationStackScroller.setAntiBurnInOffsetX(mClockPositionResult.clockX);
+ int burnInXOffset = mPulsing ? 0 : mClockPositionResult.clockX;
+ mNotificationStackScroller.setAntiBurnInOffsetX(burnInXOffset);
mStackScrollerMeasuringPass++;
requestScrollerTopPaddingUpdate(animate);
@@ -2830,7 +2830,7 @@
mAnimateNextPositionUpdate = false;
}
mNotificationStackScroller.setPulsing(pulsing, animatePulse);
- mKeyguardStatusView.setPulsing(pulsing, animatePulse);
+ mKeyguardStatusView.setPulsing(pulsing);
mKeyguardBottomArea.setPulsing(pulsing, animatePulse);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 3568f28..bf143c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -88,16 +88,12 @@
/**
* Default alpha value for most scrims.
*/
- public static final float GRADIENT_SCRIM_ALPHA = 0.45f;
+ public static final float GRADIENT_SCRIM_ALPHA = 0.2f;
/**
* A scrim varies its opacity based on a busyness factor, for example
* how many notifications are currently visible.
*/
public static final float GRADIENT_SCRIM_ALPHA_BUSY = 0.7f;
- /**
- * Scrim opacity when a wallpaper doesn't support ambient mode.
- */
- public static final float PULSING_WALLPAPER_SCRIM_ALPHA = 0.6f;
/**
* The most common scrim, the one under the keyguard.
@@ -154,7 +150,6 @@
private Callback mCallback;
private boolean mWallpaperSupportsAmbientMode;
private boolean mScreenOn;
- private float mNotificationDensity;
// Scrim blanking callbacks
private Runnable mPendingFrameCallback;
@@ -245,7 +240,7 @@
mCurrentInFrontTint = state.getFrontTint();
mCurrentBehindTint = state.getBehindTint();
mCurrentInFrontAlpha = state.getFrontAlpha();
- mCurrentBehindAlpha = state.getBehindAlpha(mNotificationDensity);
+ mCurrentBehindAlpha = state.getBehindAlpha();
applyExpansionToAlpha();
// Scrim might acquire focus when user is navigating with a D-pad or a keyboard.
@@ -279,8 +274,7 @@
// Docking pulses may take a long time, wallpapers should also fade away after a while.
if (mWallpaperSupportsAmbientMode && (
mDozeParameters.getAlwaysOn() && mState == ScrimState.AOD
- || mState == ScrimState.PULSING && mCallback != null
- && mCallback.isFadeOutWallpaper())) {
+ || mState == ScrimState.PULSING && mCallback != null)) {
if (!mWallpaperVisibilityTimedOut) {
mTimeTicker.schedule(mDozeParameters.getWallpaperAodDuration(),
AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
@@ -416,7 +410,7 @@
// Either darken of make the scrim transparent when you
// pull down the shade
float interpolatedFract = getInterpolatedFraction();
- float alphaBehind = mState.getBehindAlpha(mNotificationDensity);
+ float alphaBehind = mState.getBehindAlpha();
if (mDarkenWhileDragging) {
mCurrentBehindAlpha = MathUtils.lerp(GRADIENT_SCRIM_ALPHA_BUSY, alphaBehind,
interpolatedFract);
@@ -430,24 +424,6 @@
}
/**
- * Keyguard and shade scrim opacity varies according to how many notifications are visible.
- * @param notificationCount Number of visible notifications.
- */
- public void setNotificationCount(int notificationCount) {
- final float maxNotificationDensity = 3;
- float notificationDensity = Math.min(notificationCount / maxNotificationDensity, 1f);
- if (mNotificationDensity == notificationDensity) {
- return;
- }
- mNotificationDensity = notificationDensity;
-
- if (mState == ScrimState.KEYGUARD) {
- applyExpansionToAlpha();
- scheduleUpdate();
- }
- }
-
- /**
* Sets the given drawable as the background of the scrim that shows up behind the
* notifications.
*/
@@ -909,7 +885,7 @@
// Backdrop event may arrive after state was already applied,
// in this case, back-scrim needs to be re-evaluated
if (mState == ScrimState.AOD || mState == ScrimState.PULSING) {
- float newBehindAlpha = mState.getBehindAlpha(mNotificationDensity);
+ float newBehindAlpha = mState.getBehindAlpha();
if (mCurrentBehindAlpha != newBehindAlpha) {
mCurrentBehindAlpha = newBehindAlpha;
updateScrims();
@@ -923,6 +899,10 @@
}
}
+ public void setPulseReason(int pulseReason) {
+ ScrimState.PULSING.setPulseReason(pulseReason);
+ }
+
public interface Callback {
default void onStart() {
}
@@ -932,9 +912,6 @@
}
default void onCancelled() {
}
- default boolean isFadeOutWallpaper() {
- return false;
- }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 72519ba3..11a2d32 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -18,8 +18,8 @@
import android.graphics.Color;
import android.os.Trace;
-import android.util.MathUtils;
+import com.android.systemui.doze.DozeLog;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
@@ -57,13 +57,6 @@
mCurrentBehindAlpha = mScrimBehindAlphaKeyguard;
mCurrentInFrontAlpha = 0;
}
-
- @Override
- public float getBehindAlpha(float busynessFactor) {
- return MathUtils.map(0 /* start */, 1 /* stop */,
- mScrimBehindAlphaKeyguard, ScrimController.GRADIENT_SCRIM_ALPHA_BUSY,
- busynessFactor);
- }
},
/**
@@ -117,7 +110,7 @@
}
@Override
- public float getBehindAlpha(float busyness) {
+ public float getBehindAlpha() {
return mWallpaperSupportsAmbientMode && !mHasBackdrop ? 0f : 1f;
}
@@ -133,17 +126,17 @@
PULSING(5) {
@Override
public void prepare(ScrimState previousState) {
- mCurrentInFrontAlpha = 0;
- mCurrentInFrontTint = Color.BLACK;
- mCurrentBehindTint = Color.BLACK;
+ mCurrentInFrontAlpha = 0f;
+ if (mPulseReason == DozeLog.PULSE_REASON_NOTIFICATION
+ || mPulseReason == DozeLog.PULSE_REASON_DOCKING) {
+ mCurrentBehindAlpha = previousState.getBehindAlpha();
+ mCurrentBehindTint = Color.BLACK;
+ } else {
+ mCurrentBehindAlpha = mScrimBehindAlphaKeyguard;
+ mCurrentBehindTint = Color.TRANSPARENT;
+ }
mBlankScreen = mDisplayRequiresBlanking;
}
-
- @Override
- public float getBehindAlpha(float busyness) {
- return mWallpaperSupportsAmbientMode && !mHasBackdrop ? 0f
- : ScrimController.PULSING_WALLPAPER_SCRIM_ALPHA;
- }
},
/**
@@ -204,6 +197,7 @@
int mIndex;
boolean mHasBackdrop;
boolean mLaunchingAffordanceWithPreview;
+ int mPulseReason;
ScrimState(int index) {
mIndex = index;
@@ -235,7 +229,7 @@
return mCurrentInFrontAlpha;
}
- public float getBehindAlpha(float busyness) {
+ public float getBehindAlpha() {
return mCurrentBehindAlpha;
}
@@ -276,6 +270,10 @@
mAodFrontScrimAlpha = aodFrontScrimAlpha;
}
+ public void setPulseReason(int pulseReason) {
+ mPulseReason = pulseReason;
+ }
+
public void setScrimBehindAlphaKeyguard(float scrimBehindAlphaKeyguard) {
mScrimBehindAlphaKeyguard = scrimBehindAlphaKeyguard;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index ed71598..1470d0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -3883,6 +3883,7 @@
@Override
public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) {
+ mScrimController.setPulseReason(reason);
if (reason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS) {
mPowerManager.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:NODOZE");
startAssist(new Bundle());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java
index 8ae7d52..ff30a4d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java
@@ -29,7 +29,10 @@
import android.testing.TestableLooper.RunWithLooper;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.AmbientPulseManager;
import com.android.systemui.statusbar.NotificationTestHelper;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -37,6 +40,8 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.util.HashSet;
@@ -45,14 +50,18 @@
@RunWithLooper
public class NotificationRoundnessManagerTest extends SysuiTestCase {
- private NotificationRoundnessManager mRoundnessManager = new NotificationRoundnessManager();
+ private NotificationRoundnessManager mRoundnessManager;
private HashSet<ExpandableView> mAnimatedChildren = new HashSet<>();
private Runnable mRoundnessCallback = mock(Runnable.class);
private ExpandableNotificationRow mFirst;
private ExpandableNotificationRow mSecond;
+ @Mock
+ private AmbientPulseManager mAmbientPulseManager;
@Before
public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mRoundnessManager = new NotificationRoundnessManager(mAmbientPulseManager);
com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper();
NotificationTestHelper testHelper = new NotificationTestHelper(getContext());
mFirst = testHelper.createRow();
@@ -127,6 +136,27 @@
}
@Test
+ public void testRoundnessPulsing() throws Exception {
+ // Let's create a notification that's neither the first or last item of the stack,
+ // this way we'll ensure that it won't have any rounded corners by default.
+ mRoundnessManager.updateRoundedChildren(new NotificationSection[]{
+ createSection(mFirst, mSecond),
+ createSection(null, null)
+ });
+ ExpandableNotificationRow row = new NotificationTestHelper(getContext()).createRow();
+ NotificationEntry entry = mock(NotificationEntry.class);
+ when(entry.getRow()).thenReturn(row);
+
+ mRoundnessManager.onAmbientStateChanged(entry, true);
+ Assert.assertEquals(1f, row.getCurrentBottomRoundness(), 0.0f);
+ Assert.assertEquals(1f, row.getCurrentTopRoundness(), 0.0f);
+
+ mRoundnessManager.onAmbientStateChanged(entry, false);
+ Assert.assertEquals(0f, row.getCurrentBottomRoundness(), 0.0f);
+ Assert.assertEquals(0f, row.getCurrentTopRoundness(), 0.0f);
+ }
+
+ @Test
public void testRoundnessSetOnSecondSectionLast() {
mRoundnessManager.updateRoundedChildren(new NotificationSection[]{
createSection(mFirst, mFirst),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 37814f0..736f384 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -107,6 +107,7 @@
@Mock private NotificationRemoteInputManager mRemoteInputManager;
@Mock private RemoteInputController mRemoteInputController;
@Mock private MetricsLogger mMetricsLogger;
+ @Mock private NotificationRoundnessManager mNotificationRoundnessManager;
private TestableNotificationEntryManager mEntryManager;
private int mOriginalInterruptionModelSetting;
@@ -140,7 +141,7 @@
// holds a copy of the CUT's instances of these classes, so they still refer to the CUT's
// member variables, not the spy's member variables.
mStackScrollerInternal = new NotificationStackScrollLayout(getContext(), null,
- true /* allowLongPress */);
+ true /* allowLongPress */, mNotificationRoundnessManager);
mStackScroller = spy(mStackScrollerInternal);
mStackScroller.setShelf(notificationShelf);
mStackScroller.setStatusBar(mBar);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
index 27ed9c5..cd52e87 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
@@ -47,7 +47,6 @@
private float mPanelExpansion;
private int mKeyguardStatusHeight;
private float mDark;
- private boolean mPulsing;
@Before
public void setUp() {
@@ -208,20 +207,6 @@
}
@Test
- public void notifPositionWhilePulsingOnAOD() {
- // GIVEN on AOD and pulsing
- givenAOD();
- mNotificationStackHeight = EMPTY_HEIGHT;
- mKeyguardStatusHeight = EMPTY_HEIGHT;
- mPulsing = true;
- mClockPositionAlgorithm.setPulsingPadding(200);
- // WHEN the clock position algorithm is run
- positionClock();
- // THEN the notif padding doesn't adjust for pulsing.
- assertThat(mClockPosition.stackScrollerPadding).isEqualTo(1000);
- }
-
- @Test
public void notifPositionMiddleOfScreenOnLockScreen() {
// GIVEN on lock screen and both stack scroll and clock have 0 height
givenLockScreen();
@@ -307,20 +292,6 @@
assertThat(mClockPosition.stackScrollerPadding).isEqualTo(0);
}
- @Test
- public void notifPositionWhilePulsingOnLockScreen() {
- // GIVEN on lock screen and pulsing
- givenLockScreen();
- mNotificationStackHeight = EMPTY_HEIGHT;
- mKeyguardStatusHeight = EMPTY_HEIGHT;
- mPulsing = true;
- mClockPositionAlgorithm.setPulsingPadding(200);
- // WHEN the clock position algorithm is run
- positionClock();
- // THEN the notif padding adjusts for pulsing.
- assertThat(mClockPosition.stackScrollerPadding).isEqualTo(1200);
- }
-
private void givenAOD() {
mPanelExpansion = 1.f;
mDark = 1.f;
@@ -334,7 +305,7 @@
private void positionClock() {
mClockPositionAlgorithm.setup(EMPTY_MARGIN, SCREEN_HEIGHT, mNotificationStackHeight,
mPanelExpansion, SCREEN_HEIGHT, mKeyguardStatusHeight, mDark, SECURE_LOCKED,
- mPulsing, ZERO_DRAG);
+ ZERO_DRAG);
mClockPositionAlgorithm.run(mClockPosition);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 8eb42c4..c20d37f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -45,6 +45,7 @@
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.internal.util.function.TriConsumer;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.doze.DozeLog;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.util.wakelock.WakeLock;
import com.android.systemui.utils.os.FakeHandler;
@@ -133,7 +134,8 @@
// Back scrim should be transparent
assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_TRANSPARENT);
- // Move on to PULSING and check if the back scrim is still transparent
+ // Pulsing notification should conserve AOD wallpaper.
+ mScrimController.setPulseReason(DozeLog.PULSE_REASON_NOTIFICATION);
mScrimController.transitionTo(ScrimState.PULSING);
mScrimController.finishAnimationsImmediately();
assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_TRANSPARENT);
@@ -218,13 +220,14 @@
mScrimController.finishAnimationsImmediately();
assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE);
+ mScrimController.setPulseReason(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN);
mScrimController.transitionTo(ScrimState.PULSING);
mScrimController.finishAnimationsImmediately();
// Front scrim should be transparent
// Back scrim should be semi-transparent so the user can see the wallpaper
// Pulse callback should have been invoked
assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_SEMI_TRANSPARENT);
- assertScrimTint(mScrimBehind, true /* tinted */);
+ assertScrimTint(mScrimBehind, false /* tinted */);
}
@Test
@@ -477,12 +480,8 @@
@Test
public void testHoldsPulsingWallpaperAnimationLock() {
// Pre-conditions
- mScrimController.transitionTo(ScrimState.PULSING, new ScrimController.Callback() {
- @Override
- public boolean isFadeOutWallpaper() {
- return true;
- }
- });
+ mScrimController.setPulseReason(DozeLog.PULSE_REASON_NOTIFICATION);
+ mScrimController.transitionTo(ScrimState.PULSING);
mScrimController.finishAnimationsImmediately();
reset(mWakeLock);
@@ -491,7 +490,6 @@
verify(mWakeLock, never()).release();
mScrimController.finishAnimationsImmediately();
verify(mWakeLock).release();
- assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE);
}
@Test
@@ -504,31 +502,27 @@
}
@Test
- public void testWillHidePulsingWallpaper_withRequestFadeOut() {
- mScrimController.setWallpaperSupportsAmbientMode(true);
- mScrimController.transitionTo(ScrimState.PULSING, new ScrimController.Callback() {
- @Override
- public boolean isFadeOutWallpaper() {
- return true;
- }
- });
- verify(mAlarmManager).setExact(anyInt(), anyLong(), any(), any(), any());
- mScrimController.transitionTo(ScrimState.KEYGUARD);
- verify(mAlarmManager).cancel(any(AlarmManager.OnAlarmListener.class));
- }
-
- @Test
- public void testDoesNotHidePulsingWallpaper_withoutRequestFadeOut() {
- mScrimController.setWallpaperSupportsAmbientMode(true);
- mScrimController.transitionTo(ScrimState.PULSING, new ScrimController.Callback() {});
- verify(mAlarmManager, never()).setExact(anyInt(), anyLong(), any(), any(), any());
- }
-
- @Test
- public void testDoesNotHidePulsingWallpaper_withoutCallback() {
- mScrimController.setWallpaperSupportsAmbientMode(true);
+ public void testWillHidePulsingWallpaper_whenNotification() {
+ mScrimController.setWallpaperSupportsAmbientMode(false);
+ mScrimController.transitionTo(ScrimState.AOD);
+ mScrimController.finishAnimationsImmediately();
+ mScrimController.setPulseReason(DozeLog.PULSE_REASON_NOTIFICATION);
mScrimController.transitionTo(ScrimState.PULSING);
- verify(mAlarmManager, never()).setExact(anyInt(), anyLong(), any(), any(), any());
+ mScrimController.finishAnimationsImmediately();
+ assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE);
+ assertScrimTint(mScrimBehind, true);
+ }
+
+ @Test
+ public void testWillHidePulsingWallpaper_whenDocking() {
+ mScrimController.setWallpaperSupportsAmbientMode(false);
+ mScrimController.transitionTo(ScrimState.AOD);
+ mScrimController.finishAnimationsImmediately();
+ mScrimController.setPulseReason(DozeLog.PULSE_REASON_DOCKING);
+ mScrimController.transitionTo(ScrimState.PULSING);
+ mScrimController.finishAnimationsImmediately();
+ assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE);
+ assertScrimTint(mScrimBehind, true);
}
@Test
@@ -560,34 +554,6 @@
Assert.assertTrue(mScrimController.wasAnimationJustCancelled());
}
- /**
- * Number of visible notifications affects scrim opacity.
- */
- @Test
- public void testNotificationDensity() {
- mScrimController.transitionTo(ScrimState.KEYGUARD);
- mScrimController.finishAnimationsImmediately();
-
- mScrimController.setNotificationCount(0);
- mScrimController.finishAnimationsImmediately();
- Assert.assertEquals("lower density when no notifications",
- ScrimController.GRADIENT_SCRIM_ALPHA, mScrimBehind.getViewAlpha(), 0.01f);
-
- mScrimController.setNotificationCount(3);
- mScrimController.finishAnimationsImmediately();
- Assert.assertEquals("stronger density when notifications are visible",
- ScrimController.GRADIENT_SCRIM_ALPHA_BUSY, mScrimBehind.getViewAlpha(), 0.01f);
- }
-
- /**
- * Moving from/to states conserves old notification density.
- */
- @Test
- public void testConservesNotificationDensity() {
- testConservesNotificationDensity(0 /* count */, ScrimController.GRADIENT_SCRIM_ALPHA);
- testConservesNotificationDensity(3 /* count */, ScrimController.GRADIENT_SCRIM_ALPHA_BUSY);
- }
-
@Test
public void testScrimFocus() {
mScrimController.transitionTo(ScrimState.AOD);
@@ -662,24 +628,6 @@
mScrimBehind.getDefaultFocusHighlightEnabled());
}
- /**
- * Conserves old notification density after leaving state and coming back.
- *
- * @param count How many notification.
- * @param expectedAlpha Expected alpha.
- */
- private void testConservesNotificationDensity(int count, float expectedAlpha) {
- mScrimController.setNotificationCount(count);
- mScrimController.transitionTo(ScrimState.UNLOCKED);
- mScrimController.finishAnimationsImmediately();
-
- mScrimController.transitionTo(ScrimState.KEYGUARD);
- mScrimController.finishAnimationsImmediately();
-
- Assert.assertEquals("Doesn't respect notification busyness after transition",
- expectedAlpha, mScrimBehind.getViewAlpha(), 0.01f);
- }
-
private void assertScrimTint(ScrimView scrimView, boolean tinted) {
final boolean viewIsTinted = scrimView.getTint() != Color.TRANSPARENT;
final String name = scrimView == mScrimInFront ? "front" : "back";
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 36ca52a..763c16f 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -16,6 +16,11 @@
package com.android.server.accessibility;
+import static android.accessibilityservice.AccessibilityService.SHOW_MODE_AUTO;
+import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE;
+import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN;
+import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HIDDEN;
+import static android.accessibilityservice.AccessibilityService.SHOW_MODE_IGNORE_HARD_KEYBOARD;
import static android.accessibilityservice.AccessibilityService.SHOW_MODE_MASK;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
import static android.view.accessibility.AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED;
@@ -23,13 +28,9 @@
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
+
import static com.android.internal.util.FunctionalUtils.ignoreRemoteException;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
-import static android.accessibilityservice.AccessibilityService.SHOW_MODE_AUTO;
-import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HIDDEN;
-import static android.accessibilityservice.AccessibilityService.SHOW_MODE_IGNORE_HARD_KEYBOARD;
-import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE;
-import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN;
import android.Manifest;
import android.accessibilityservice.AccessibilityService;
@@ -121,6 +122,8 @@
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
+import libcore.util.EmptyArray;
+
import org.xmlpull.v1.XmlPullParserException;
import java.io.FileDescriptor;
@@ -139,8 +142,6 @@
import java.util.function.Consumer;
import java.util.function.IntSupplier;
-import libcore.util.EmptyArray;
-
/**
* This class is instantiated by the system as a system level service and can be
* accessed only by the system. The task of this service is to be a centralized
@@ -1827,8 +1828,6 @@
updateFilterKeyEventsLocked(userState);
updateTouchExplorationLocked(userState);
updatePerformGesturesLocked(userState);
- updateDisplayDaltonizerLocked(userState);
- updateDisplayInversionLocked(userState);
updateMagnificationLocked(userState);
scheduleUpdateFingerprintGestureHandling(userState);
scheduleUpdateInputFilter(userState);
@@ -2187,14 +2186,6 @@
return false;
}
- private void updateDisplayDaltonizerLocked(UserState userState) {
- DisplayAdjustmentUtils.applyDaltonizerSetting(mContext, userState.mUserId);
- }
-
- private void updateDisplayInversionLocked(UserState userState) {
- DisplayAdjustmentUtils.applyInversionSetting(mContext, userState.mUserId);
- }
-
private void updateMagnificationLocked(UserState userState) {
if (userState.mUserId != mCurrentUserId) {
return;
@@ -4104,15 +4095,6 @@
private final Uri mTouchExplorationGrantedAccessibilityServicesUri = Settings.Secure
.getUriFor(Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES);
- private final Uri mDisplayInversionEnabledUri = Settings.Secure.getUriFor(
- Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
-
- private final Uri mDisplayDaltonizerEnabledUri = Settings.Secure.getUriFor(
- Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED);
-
- private final Uri mDisplayDaltonizerUri = Settings.Secure.getUriFor(
- Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER);
-
private final Uri mHighTextContrastUri = Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED);
@@ -4153,12 +4135,6 @@
mTouchExplorationGrantedAccessibilityServicesUri,
false, this, UserHandle.USER_ALL);
contentResolver.registerContentObserver(
- mDisplayInversionEnabledUri, false, this, UserHandle.USER_ALL);
- contentResolver.registerContentObserver(
- mDisplayDaltonizerEnabledUri, false, this, UserHandle.USER_ALL);
- contentResolver.registerContentObserver(
- mDisplayDaltonizerUri, false, this, UserHandle.USER_ALL);
- contentResolver.registerContentObserver(
mHighTextContrastUri, false, this, UserHandle.USER_ALL);
contentResolver.registerContentObserver(
mAccessibilitySoftKeyboardModeUri, false, this, UserHandle.USER_ALL);
@@ -4202,11 +4178,6 @@
if (readTouchExplorationGrantedAccessibilityServicesLocked(userState)) {
onUserStateChangedLocked(userState);
}
- } else if (mDisplayDaltonizerEnabledUri.equals(uri)
- || mDisplayDaltonizerUri.equals(uri)) {
- updateDisplayDaltonizerLocked(userState);
- } else if (mDisplayInversionEnabledUri.equals(uri)) {
- updateDisplayInversionLocked(userState);
} else if (mHighTextContrastUri.equals(uri)) {
if (readHighTextContrastEnabledSettingLocked(userState)) {
onUserStateChangedLocked(userState);
diff --git a/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java b/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
deleted file mode 100644
index c81a876..0000000
--- a/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2013 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 com.android.server.accessibility;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.os.Binder;
-import android.provider.Settings.Secure;
-import android.view.accessibility.AccessibilityManager;
-
-import com.android.server.LocalServices;
-import com.android.server.display.DisplayTransformManager;
-
-/**
- * Utility methods for performing accessibility display adjustments.
- */
-class DisplayAdjustmentUtils {
-
- /** Default inversion mode for display color correction. */
- private static final int DEFAULT_DISPLAY_DALTONIZER =
- AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY;
-
- /** Matrix and offset used for converting color to gray-scale. */
- private static final float[] MATRIX_GRAYSCALE = new float[] {
- .2126f, .2126f, .2126f, 0,
- .7152f, .7152f, .7152f, 0,
- .0722f, .0722f, .0722f, 0,
- 0, 0, 0, 1
- };
-
- /**
- * Matrix and offset used for luminance inversion. Represents a transform
- * from RGB to YIQ color space, rotation around the Y axis by 180 degrees,
- * transform back to RGB color space, and subtraction from 1. The last row
- * represents a non-multiplied addition, see surfaceflinger's ProgramCache
- * for full implementation details.
- */
- private static final float[] MATRIX_INVERT_COLOR = new float[] {
- 0.402f, -0.598f, -0.599f, 0,
- -1.174f, -0.174f, -1.175f, 0,
- -0.228f, -0.228f, 0.772f, 0,
- 1, 1, 1, 1
- };
-
- public static void applyDaltonizerSetting(Context context, int userId) {
- final ContentResolver cr = context.getContentResolver();
- final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
-
- int daltonizerMode = AccessibilityManager.DALTONIZER_DISABLED;
- long identity = Binder.clearCallingIdentity();
- try {
- if (Secure.getIntForUser(cr,
- Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) != 0) {
- daltonizerMode = Secure.getIntForUser(cr,
- Secure.ACCESSIBILITY_DISPLAY_DALTONIZER, DEFAULT_DISPLAY_DALTONIZER, userId);
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
-
- float[] grayscaleMatrix = null;
- if (daltonizerMode == AccessibilityManager.DALTONIZER_SIMULATE_MONOCHROMACY) {
- // Monochromacy isn't supported by the native Daltonizer.
- grayscaleMatrix = MATRIX_GRAYSCALE;
- daltonizerMode = AccessibilityManager.DALTONIZER_DISABLED;
- }
- dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_GRAYSCALE, grayscaleMatrix);
- dtm.setDaltonizerMode(daltonizerMode);
- }
-
- /**
- * Applies the specified user's display color adjustments.
- */
- public static void applyInversionSetting(Context context, int userId) {
- final ContentResolver cr = context.getContentResolver();
- final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
-
- long identity = Binder.clearCallingIdentity();
- try {
- final boolean invertColors = Secure.getIntForUser(cr,
- Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) != 0;
- dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_INVERT_COLOR,
- invertColors ? MATRIX_INVERT_COLOR : null);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 2a80644..db2a733 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -780,6 +780,13 @@
});
refreshZramSettings();
+ // Schedule zram writeback unless zram is disabled by persist.sys.zram_enabled
+ String zramPropValue = SystemProperties.get(ZRAM_ENABLED_PROPERTY);
+ if (!zramPropValue.equals("0")
+ && mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_zramWriteback)) {
+ ZramWriteback.scheduleZramWriteback(mContext);
+ }
// Toggle isolated-enable system property in response to settings
mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(Settings.Global.ISOLATED_STORAGE_REMOTE),
@@ -813,6 +820,12 @@
// changing the property value. There's no race: we're the
// sole writer.
SystemProperties.set(ZRAM_ENABLED_PROPERTY, desiredPropertyValue);
+ // Schedule writeback only if zram is being enabled.
+ if (desiredPropertyValue.equals("1")
+ && mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_zramWriteback)) {
+ ZramWriteback.scheduleZramWriteback(mContext);
+ }
}
}
diff --git a/services/core/java/com/android/server/ZramWriteback.java b/services/core/java/com/android/server/ZramWriteback.java
new file mode 100644
index 0000000..3a4aff2
--- /dev/null
+++ b/services/core/java/com/android/server/ZramWriteback.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2019 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 com.android.server;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.FileUtils;
+import android.os.SystemProperties;
+import android.util.Slog;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Schedules jobs for triggering zram writeback.
+ */
+public final class ZramWriteback extends JobService {
+ private static final String TAG = "ZramWriteback";
+ private static final boolean DEBUG = false;
+
+ private static final ComponentName sZramWriteback =
+ new ComponentName("android", ZramWriteback.class.getName());
+
+ private static final int MARK_IDLE_JOB_ID = 811;
+ private static final int WRITEBACK_IDLE_JOB_ID = 812;
+
+ private static final int MAX_ZRAM_DEVICES = 256;
+ private static int sZramDeviceId = 0;
+
+ private static final String IDLE_SYS = "/sys/block/zram%d/idle";
+ private static final String IDLE_SYS_ALL_PAGES = "all";
+
+ private static final String WB_SYS = "/sys/block/zram%d/writeback";
+ private static final String WB_SYS_IDLE_PAGES = "idle";
+
+ private static final String WB_STATS_SYS = "/sys/block/zram%d/bd_stat";
+ private static final int WB_STATS_MAX_FILE_SIZE = 128;
+
+ private static final String BDEV_SYS = "/sys/block/zram%d/backing_dev";
+
+ private static final String MARK_IDLE_DELAY_PROP = "ro.zram.mark_idle_delay_mins";
+ private static final String FIRST_WB_DELAY_PROP = "ro.zram.first_wb_delay_mins";
+ private static final String PERIODIC_WB_DELAY_PROP = "ro.zram.periodic_wb_delay_hours";
+
+ private void markPagesAsIdle() {
+ String idlePath = String.format(IDLE_SYS, sZramDeviceId);
+ try {
+ FileUtils.stringToFile(new File(idlePath), IDLE_SYS_ALL_PAGES);
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to write to " + idlePath);
+ }
+ }
+
+ private void flushIdlePages() {
+ if (DEBUG) Slog.d(TAG, "Start writing back idle pages to disk");
+ String wbPath = String.format(WB_SYS, sZramDeviceId);
+ try {
+ FileUtils.stringToFile(new File(wbPath), WB_SYS_IDLE_PAGES);
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to write to " + wbPath);
+ }
+ if (DEBUG) Slog.d(TAG, "Finished writeback back idle pages");
+ }
+
+ private int getWrittenPageCount() {
+ String wbStatsPath = String.format(WB_STATS_SYS, sZramDeviceId);
+ try {
+ String wbStats = FileUtils
+ .readTextFile(new File(wbStatsPath), WB_STATS_MAX_FILE_SIZE, "");
+ return Integer.parseInt(wbStats.trim().split("\\s+")[2], 10);
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to read writeback stats from " + wbStatsPath);
+ }
+
+ return -1;
+ }
+
+ private void markAndFlushPages() {
+ int pageCount = getWrittenPageCount();
+
+ flushIdlePages();
+ markPagesAsIdle();
+
+ if (pageCount != -1) {
+ Slog.i(TAG, "Total pages written to disk is " + (getWrittenPageCount() - pageCount));
+ }
+ }
+
+ private static boolean isWritebackEnabled() {
+ try {
+ String backingDev = FileUtils
+ .readTextFile(new File(String.format(BDEV_SYS, sZramDeviceId)), 128, "");
+ if (!"none".equals(backingDev.trim())) {
+ return true;
+ } else {
+ Slog.w(TAG, "Writeback device is not set");
+ }
+ } catch (IOException e) {
+ Slog.w(TAG, "Writeback is not enabled on zram");
+ }
+ return false;
+ }
+
+ private static void schedNextWriteback(Context context) {
+ int nextWbDelay = SystemProperties.getInt(PERIODIC_WB_DELAY_PROP, 24);
+ JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
+
+ js.schedule(new JobInfo.Builder(WRITEBACK_IDLE_JOB_ID, sZramWriteback)
+ .setMinimumLatency(TimeUnit.HOURS.toMillis(nextWbDelay))
+ .setRequiresDeviceIdle(true)
+ .build());
+ }
+
+ @Override
+ public boolean onStartJob(JobParameters params) {
+
+ if (!isWritebackEnabled()) {
+ jobFinished(params, false);
+ return false;
+ }
+
+ if (params.getJobId() == MARK_IDLE_JOB_ID) {
+ markPagesAsIdle();
+ jobFinished(params, false);
+ return false;
+ } else {
+ new Thread("ZramWriteback_WritebackIdlePages") {
+ @Override
+ public void run() {
+ markAndFlushPages();
+ schedNextWriteback(ZramWriteback.this);
+ jobFinished(params, false);
+ }
+ }.start();
+ }
+ return true;
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters params) {
+ // The thread that triggers the writeback is non-interruptible
+ return false;
+ }
+
+ /**
+ * Schedule the zram writeback job to trigger a writeback when idle
+ */
+ public static void scheduleZramWriteback(Context context) {
+ int markIdleDelay = SystemProperties.getInt(MARK_IDLE_DELAY_PROP, 20);
+ int firstWbDelay = SystemProperties.getInt(FIRST_WB_DELAY_PROP, 180);
+
+ JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
+
+ // Schedule a one time job to mark pages as idle. These pages will be written
+ // back at later point if they remain untouched.
+ js.schedule(new JobInfo.Builder(MARK_IDLE_JOB_ID, sZramWriteback)
+ .setMinimumLatency(TimeUnit.MINUTES.toMillis(markIdleDelay))
+ .build());
+
+ // Schedule a one time job to flush idle pages to disk.
+ // After the initial writeback, subsequent writebacks are done at interval set
+ // by ro.zram.periodic_wb_delay_hours.
+ js.schedule(new JobInfo.Builder(WRITEBACK_IDLE_JOB_ID, sZramWriteback)
+ .setMinimumLatency(TimeUnit.MINUTES.toMillis(firstWbDelay))
+ .setRequiresDeviceIdle(true)
+ .build());
+ }
+}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 9a4ca1f..d9fcf9e 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1614,7 +1614,9 @@
// For notifications/ring, show the ui before making any adjustments
// Don't suppress mute/unmute requests
- if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)) {
+ // Don't suppress adjustments for single volume device
+ if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)
+ && !mIsSingleVolume) {
direction = 0;
flags &= ~AudioManager.FLAG_PLAY_SOUND;
flags &= ~AudioManager.FLAG_VIBRATE;
diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java
index f06cf0b..9223739 100644
--- a/services/core/java/com/android/server/display/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/ColorDisplayService.java
@@ -51,6 +51,7 @@
import android.provider.Settings.System;
import android.util.MathUtils;
import android.util.Slog;
+import android.view.accessibility.AccessibilityManager;
import android.view.animation.AnimationUtils;
import com.android.internal.R;
@@ -402,6 +403,29 @@
}
};
+ /**
+ * Matrix and offset used for converting color to grayscale.
+ */
+ private static final float[] MATRIX_GRAYSCALE = new float[]{
+ .2126f, .2126f, .2126f, 0f,
+ .7152f, .7152f, .7152f, 0f,
+ .0722f, .0722f, .0722f, 0f,
+ 0f, 0f, 0f, 1f
+ };
+
+ /**
+ * Matrix and offset used for luminance inversion. Represents a transform from RGB to YIQ color
+ * space, rotation around the Y axis by 180 degrees, transform back to RGB color space, and
+ * subtraction from 1. The last row represents a non-multiplied addition, see surfaceflinger's
+ * ProgramCache for full implementation details.
+ */
+ private static final float[] MATRIX_INVERT_COLOR = new float[] {
+ 0.402f, -0.598f, -0.599f, 0f,
+ -1.174f, -0.174f, -1.175f, 0f,
+ -0.228f, -0.228f, 0.772f, 0f,
+ 1f, 1f, 1f, 1f
+ };
+
private final Handler mHandler;
private final AppSaturationController mAppSaturationController = new AppSaturationController();
@@ -543,9 +567,16 @@
case System.DISPLAY_COLOR_MODE:
onDisplayColorModeChanged(mNightDisplayController.getColorMode());
break;
- case Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED:
case Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED:
- onAccessibilityTransformChanged();
+ onAccessibilityInversionChanged();
+ onAccessibilityActivated();
+ break;
+ case Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED:
+ onAccessibilityDaltonizerChanged();
+ onAccessibilityActivated();
+ break;
+ case Secure.ACCESSIBILITY_DISPLAY_DALTONIZER:
+ onAccessibilityDaltonizerChanged();
break;
case Secure.DISPLAY_WHITE_BALANCE_ENABLED:
updateDisplayWhiteBalanceStatus();
@@ -574,6 +605,9 @@
cr.registerContentObserver(
Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED),
false /* notifyForDescendants */, mContentObserver, mCurrentUser);
+ cr.registerContentObserver(
+ Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER),
+ false /* notifyForDescendants */, mContentObserver, mCurrentUser);
cr.registerContentObserver(Secure.getUriFor(Secure.DISPLAY_WHITE_BALANCE_ENABLED),
false /* notifyForDescendants */, mContentObserver, mCurrentUser);
@@ -704,10 +738,43 @@
dtm.setColorMode(mode, mNightDisplayTintController.getMatrix());
}
- private void onAccessibilityTransformChanged() {
+ private void onAccessibilityActivated() {
onDisplayColorModeChanged(mNightDisplayController.getColorMode());
}
+ /**
+ * Apply the accessibility daltonizer transform based on the settings value.
+ */
+ private void onAccessibilityDaltonizerChanged() {
+ final boolean enabled = Secure.getIntForUser(getContext().getContentResolver(),
+ Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, mCurrentUser) != 0;
+ final int daltonizerMode = enabled ? Secure.getIntForUser(getContext().getContentResolver(),
+ Secure.ACCESSIBILITY_DISPLAY_DALTONIZER,
+ AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY, mCurrentUser)
+ : AccessibilityManager.DALTONIZER_DISABLED;
+
+ final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
+ if (daltonizerMode == AccessibilityManager.DALTONIZER_SIMULATE_MONOCHROMACY) {
+ // Monochromacy isn't supported by the native Daltonizer implementation; use grayscale.
+ dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_GRAYSCALE,
+ MATRIX_GRAYSCALE);
+ dtm.setDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED);
+ } else {
+ dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_GRAYSCALE, null);
+ dtm.setDaltonizerMode(daltonizerMode);
+ }
+ }
+
+ /**
+ * Apply the accessibility inversion transform based on the settings value.
+ */
+ private void onAccessibilityInversionChanged() {
+ final boolean enabled = Secure.getIntForUser(getContext().getContentResolver(),
+ Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, mCurrentUser) != 0;
+ final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
+ dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_INVERT_COLOR,
+ enabled ? MATRIX_INVERT_COLOR : null);
+ }
/**
* Applies current color temperature matrix, or removes it if deactivated.
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
index f1951b1..1f9b027 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
@@ -26,6 +26,7 @@
import android.security.keystore.recovery.KeyDerivationParams;
import android.security.keystore.recovery.WrappedApplicationKey;
import android.util.Log;
+import android.util.Pair;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
@@ -258,9 +259,9 @@
localLskfHash = hashCredentialsBySaltedSha256(salt, mCredential);
}
- Map<String, SecretKey> rawKeys;
+ Map<String, Pair<SecretKey, byte[]>> rawKeysWithMetadata;
try {
- rawKeys = getKeysToSync(recoveryAgentUid);
+ rawKeysWithMetadata = getKeysToSync(recoveryAgentUid);
} catch (GeneralSecurityException e) {
Log.e(TAG, "Failed to load recoverable keys for sync", e);
return;
@@ -278,7 +279,9 @@
}
// Only include insecure key material for test
if (mTestOnlyInsecureCertificateHelper.isTestOnlyCertificateAlias(rootCertAlias)) {
- rawKeys = mTestOnlyInsecureCertificateHelper.keepOnlyWhitelistedInsecureKeys(rawKeys);
+ rawKeysWithMetadata =
+ mTestOnlyInsecureCertificateHelper.keepOnlyWhitelistedInsecureKeys(
+ rawKeysWithMetadata);
}
SecretKey recoveryKey;
@@ -292,7 +295,7 @@
Map<String, byte[]> encryptedApplicationKeys;
try {
encryptedApplicationKeys = KeySyncUtils.encryptKeysWithRecoveryKey(
- recoveryKey, rawKeys);
+ recoveryKey, rawKeysWithMetadata);
} catch (InvalidKeyException | NoSuchAlgorithmException e) {
Log.wtf(TAG,
"Should be impossible: could not encrypt application keys with random key",
@@ -356,7 +359,8 @@
.setCounterId(counterId)
.setServerParams(vaultHandle)
.setKeyChainProtectionParams(metadataList)
- .setWrappedApplicationKeys(createApplicationKeyEntries(encryptedApplicationKeys))
+ .setWrappedApplicationKeys(
+ createApplicationKeyEntries(encryptedApplicationKeys, rawKeysWithMetadata))
.setEncryptedRecoveryKeyBlob(encryptedRecoveryKey);
try {
keyChainSnapshotBuilder.setTrustedHardwareCertPath(certPath);
@@ -405,7 +409,7 @@
/**
* Returns all of the recoverable keys for the user.
*/
- private Map<String, SecretKey> getKeysToSync(int recoveryAgentUid)
+ private Map<String, Pair<SecretKey, byte[]>> getKeysToSync(int recoveryAgentUid)
throws InsecureUserException, KeyStoreException, UnrecoverableKeyException,
NoSuchAlgorithmException, NoSuchPaddingException, BadPlatformKeyException,
InvalidKeyException, InvalidAlgorithmParameterException, IOException {
@@ -521,12 +525,14 @@
}
private static List<WrappedApplicationKey> createApplicationKeyEntries(
- Map<String, byte[]> encryptedApplicationKeys) {
+ Map<String, byte[]> encryptedApplicationKeys,
+ Map<String, Pair<SecretKey, byte[]>> originalKeysWithMetadata) {
ArrayList<WrappedApplicationKey> keyEntries = new ArrayList<>();
for (String alias : encryptedApplicationKeys.keySet()) {
keyEntries.add(new WrappedApplicationKey.Builder()
.setAlias(alias)
.setEncryptedKeyMaterial(encryptedApplicationKeys.get(alias))
+ .setMetadata(originalKeysWithMetadata.get(alias).second)
.build());
}
return keyEntries;
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java
index 8e6f9cb..24d575e 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java
@@ -16,6 +16,9 @@
package com.android.server.locksettings.recoverablekeystore;
+import android.annotation.Nullable;
+import android.util.Pair;
+
import com.android.internal.annotations.VisibleForTesting;
import java.nio.ByteBuffer;
@@ -152,15 +155,28 @@
* @hide
*/
public static Map<String, byte[]> encryptKeysWithRecoveryKey(
- SecretKey recoveryKey, Map<String, SecretKey> keys)
+ SecretKey recoveryKey, Map<String, Pair<SecretKey, byte[]>> keys)
throws NoSuchAlgorithmException, InvalidKeyException {
HashMap<String, byte[]> encryptedKeys = new HashMap<>();
for (String alias : keys.keySet()) {
- SecretKey key = keys.get(alias);
+ SecretKey key = keys.get(alias).first;
+ byte[] metadata = keys.get(alias).second;
+ byte[] header;
+ if (metadata == null) {
+ header = ENCRYPTED_APPLICATION_KEY_HEADER;
+ } else {
+ // The provided metadata, if non-empty, will be bound to the authenticated
+ // encryption process of the key material. As a result, the ciphertext cannot be
+ // decrypted if a wrong metadata is provided during the recovery/decryption process.
+ // Note that Android P devices do not have the API to provide the optional metadata,
+ // so all the keys with non-empty metadata stored on Android Q+ devices cannot be
+ // recovered on Android P devices.
+ header = concat(ENCRYPTED_APPLICATION_KEY_HEADER, metadata);
+ }
byte[] encryptedKey = SecureBox.encrypt(
/*theirPublicKey=*/ null,
/*sharedSecret=*/ recoveryKey.getEncoded(),
- /*header=*/ ENCRYPTED_APPLICATION_KEY_HEADER,
+ /*header=*/ header,
/*payload=*/ key.getEncoded());
encryptedKeys.put(alias, encryptedKey);
}
@@ -257,12 +273,19 @@
* @throws AEADBadTagException if the message has been tampered with or was encrypted with a
* different key.
*/
- public static byte[] decryptApplicationKey(byte[] recoveryKey, byte[] encryptedApplicationKey)
+ public static byte[] decryptApplicationKey(byte[] recoveryKey, byte[] encryptedApplicationKey,
+ @Nullable byte[] applicationKeyMetadata)
throws NoSuchAlgorithmException, InvalidKeyException, AEADBadTagException {
+ byte[] header;
+ if (applicationKeyMetadata == null) {
+ header = ENCRYPTED_APPLICATION_KEY_HEADER;
+ } else {
+ header = concat(ENCRYPTED_APPLICATION_KEY_HEADER, applicationKeyMetadata);
+ }
return SecureBox.decrypt(
/*ourPrivateKey=*/ null,
/*sharedSecret=*/ recoveryKey,
- /*header=*/ ENCRYPTED_APPLICATION_KEY_HEADER,
+ /*header=*/ header,
/*encryptedPayload=*/ encryptedApplicationKey);
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGenerator.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGenerator.java
index c249468..1692e5c 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGenerator.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGenerator.java
@@ -17,6 +17,8 @@
package com.android.server.locksettings.recoverablekeystore;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Log;
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDb;
@@ -24,7 +26,6 @@
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.Locale;
-import android.util.Log;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
@@ -84,6 +85,8 @@
* @param userId The user ID of the profile to which the calling app belongs.
* @param uid The uid of the application that will own the key.
* @param alias The alias by which the key will be known in the recoverable key store.
+ * @param metadata The optional metadata that will be authenticated (but unencrypted) together
+ * with the key material when the key is uploaded to cloud.
* @throws RecoverableKeyStorageException if there is some error persisting the key either to
* the database.
* @throws KeyStoreException if there is a KeyStore error wrapping the generated key.
@@ -92,12 +95,13 @@
* @hide
*/
public byte[] generateAndStoreKey(
- PlatformEncryptionKey platformKey, int userId, int uid, String alias)
+ PlatformEncryptionKey platformKey, int userId, int uid, String alias,
+ @Nullable byte[] metadata)
throws RecoverableKeyStorageException, KeyStoreException, InvalidKeyException {
mKeyGenerator.init(KEY_SIZE_BITS);
SecretKey key = mKeyGenerator.generateKey();
- WrappedKey wrappedKey = WrappedKey.fromSecretKey(platformKey, key);
+ WrappedKey wrappedKey = WrappedKey.fromSecretKey(platformKey, key, metadata);
long result = mDatabase.insertKey(userId, uid, alias, wrappedKey);
if (result == RESULT_CANNOT_INSERT_ROW) {
@@ -126,6 +130,8 @@
* @param uid The uid of the application that will own the key.
* @param alias The alias by which the key will be known in the recoverable key store.
* @param keyBytes The raw bytes of the AES key to be imported.
+ * @param metadata The optional metadata that will be authenticated (but unencrypted) together
+ * with the key material when the key is uploaded to cloud.
* @throws RecoverableKeyStorageException if there is some error persisting the key either to
* the database.
* @throws KeyStoreException if there is a KeyStore error wrapping the generated key.
@@ -135,11 +141,11 @@
*/
public void importKey(
@NonNull PlatformEncryptionKey platformKey, int userId, int uid, @NonNull String alias,
- @NonNull byte[] keyBytes)
+ @NonNull byte[] keyBytes, @Nullable byte[] metadata)
throws RecoverableKeyStorageException, KeyStoreException, InvalidKeyException {
SecretKey key = new SecretKeySpec(keyBytes, SECRET_KEY_ALGORITHM);
- WrappedKey wrappedKey = WrappedKey.fromSecretKey(platformKey, key);
+ WrappedKey wrappedKey = WrappedKey.fromSecretKey(platformKey, key, metadata);
long result = mDatabase.insertKey(userId, uid, alias, wrappedKey);
if (result == RESULT_CANNOT_INSERT_ROW) {
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index 81d219c..ed864c0 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -604,7 +604,8 @@
try {
byte[] recoveryKey = decryptRecoveryKey(sessionEntry, encryptedRecoveryKey);
- Map<String, byte[]> keysByAlias = recoverApplicationKeys(recoveryKey, applicationKeys);
+ Map<String, byte[]> keysByAlias = recoverApplicationKeys(recoveryKey,
+ applicationKeys);
return importKeyMaterials(userId, uid, keysByAlias);
} catch (KeyStoreException e) {
throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
@@ -623,7 +624,8 @@
* @throws KeyStoreException if an error occurs importing the key or getting the grant.
*/
private @NonNull Map<String, String> importKeyMaterials(
- int userId, int uid, Map<String, byte[]> keysByAlias) throws KeyStoreException {
+ int userId, int uid, Map<String, byte[]> keysByAlias)
+ throws KeyStoreException {
ArrayMap<String, String> grantAliasesByAlias = new ArrayMap<>(keysByAlias.size());
for (String alias : keysByAlias.keySet()) {
mApplicationKeyStorage.setSymmetricKeyEntry(userId, uid, alias, keysByAlias.get(alias));
@@ -700,8 +702,6 @@
int uid = Binder.getCallingUid();
int userId = UserHandle.getCallingUserId();
- // TODO: Include metadata in the processes of authentication and storage
-
PlatformEncryptionKey encryptionKey;
try {
encryptionKey = mPlatformKeyManager.getEncryptKey(userId);
@@ -715,8 +715,8 @@
}
try {
- byte[] secretKey =
- mRecoverableKeyGenerator.generateAndStoreKey(encryptionKey, userId, uid, alias);
+ byte[] secretKey = mRecoverableKeyGenerator.generateAndStoreKey(encryptionKey, userId,
+ uid, alias, metadata);
mApplicationKeyStorage.setSymmetricKeyEntry(userId, uid, alias, secretKey);
return getAlias(userId, uid, alias);
} catch (KeyStoreException | InvalidKeyException | RecoverableKeyStorageException e) {
@@ -768,8 +768,6 @@
+ " bits.");
}
- // TODO: Include metadata in the processes of authentication and storage
-
int uid = Binder.getCallingUid();
int userId = UserHandle.getCallingUserId();
@@ -787,7 +785,8 @@
try {
// Wrap the key by the platform key and store the wrapped key locally
- mRecoverableKeyGenerator.importKey(encryptionKey, userId, uid, alias, keyBytes);
+ mRecoverableKeyGenerator.importKey(encryptionKey, userId, uid, alias, keyBytes,
+ metadata);
// Import the key to Android KeyStore and get grant
mApplicationKeyStorage.setSymmetricKeyEntry(userId, uid, alias, keyBytes);
@@ -854,17 +853,17 @@
* @return Map from alias to raw key material.
* @throws RemoteException if an error occurred decrypting the keys.
*/
- private @NonNull Map<String, byte[]> recoverApplicationKeys(
- @NonNull byte[] recoveryKey,
+ private @NonNull Map<String, byte[]> recoverApplicationKeys(@NonNull byte[] recoveryKey,
@NonNull List<WrappedApplicationKey> applicationKeys) throws RemoteException {
HashMap<String, byte[]> keyMaterialByAlias = new HashMap<>();
for (WrappedApplicationKey applicationKey : applicationKeys) {
String alias = applicationKey.getAlias();
byte[] encryptedKeyMaterial = applicationKey.getEncryptedKeyMaterial();
+ byte[] keyMetadata = applicationKey.getMetadata();
try {
- byte[] keyMaterial =
- KeySyncUtils.decryptApplicationKey(recoveryKey, encryptedKeyMaterial);
+ byte[] keyMaterial = KeySyncUtils.decryptApplicationKey(recoveryKey,
+ encryptedKeyMaterial, keyMetadata);
keyMaterialByAlias.put(alias, keyMaterial);
} catch (NoSuchAlgorithmException e) {
Log.wtf(TAG, "Missing SecureBox algorithm. AOSP required to support this.", e);
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java
index 5ba3cce..ffea488 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java
@@ -18,17 +18,20 @@
import static android.security.keystore.recovery.RecoveryController.ERROR_INVALID_CERTIFICATE;
-import com.android.internal.widget.LockPatternUtils;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.security.keystore.recovery.TrustedRootCertificates;
import android.util.Log;
+import android.util.Pair;
-import java.util.HashMap;
+import com.android.internal.widget.LockPatternUtils;
+
import java.security.cert.X509Certificate;
+import java.util.HashMap;
import java.util.Map;
+
import javax.crypto.SecretKey;
/**
@@ -84,22 +87,24 @@
|| isTestOnlyCertificateAlias(rootCertificateAlias);
}
- public boolean doesCredentialSupportInsecureMode(int credentialType, String credential) {
+ boolean doesCredentialSupportInsecureMode(int credentialType, String credential) {
return (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD)
&& (credential != null)
&& credential.startsWith(TrustedRootCertificates.INSECURE_PASSWORD_PREFIX);
}
- public Map<String, SecretKey> keepOnlyWhitelistedInsecureKeys(Map<String, SecretKey> rawKeys) {
+ Map<String, Pair<SecretKey, byte[]>> keepOnlyWhitelistedInsecureKeys(
+ Map<String, Pair<SecretKey, byte[]>> rawKeys) {
if (rawKeys == null) {
return null;
}
- Map<String, SecretKey> filteredKeys = new HashMap<>();
- for (Map.Entry<String, SecretKey> entry : rawKeys.entrySet()) {
+ Map<String, Pair<SecretKey, byte[]>> filteredKeys = new HashMap<>();
+ for (Map.Entry<String, Pair<SecretKey, byte[]>> entry : rawKeys.entrySet()) {
String alias = entry.getKey();
if (alias != null
&& alias.startsWith(TrustedRootCertificates.INSECURE_KEY_ALIAS_PREFIX)) {
- filteredKeys.put(entry.getKey(), entry.getValue());
+ filteredKeys.put(entry.getKey(),
+ Pair.create(entry.getValue().first, entry.getValue().second));
Log.d(TAG, "adding key with insecure alias " + alias + " to the recovery snapshot");
}
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/WrappedKey.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/WrappedKey.java
index 0077242..09d7541 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/WrappedKey.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/WrappedKey.java
@@ -16,8 +16,10 @@
package com.android.server.locksettings.recoverablekeystore;
+import android.annotation.Nullable;
import android.security.keystore.recovery.RecoveryController;
import android.util.Log;
+import android.util.Pair;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
@@ -49,6 +51,7 @@
private final int mRecoveryStatus;
private final byte[] mNonce;
private final byte[] mKeyMaterial;
+ private final byte[] mKeyMetadata;
/**
* Returns a wrapped form of {@code key}, using {@code wrappingKey} to encrypt the key material.
@@ -58,7 +61,8 @@
* {@link android.security.keystore.AndroidKeyStoreKey} for an example of a key that does
* not expose its key material.
*/
- public static WrappedKey fromSecretKey(PlatformEncryptionKey wrappingKey, SecretKey key)
+ public static WrappedKey fromSecretKey(PlatformEncryptionKey wrappingKey, SecretKey key,
+ @Nullable byte[] metadata)
throws InvalidKeyException, KeyStoreException {
if (key.getEncoded() == null) {
throw new InvalidKeyException(
@@ -96,6 +100,7 @@
return new WrappedKey(
/*nonce=*/ cipher.getIV(),
/*keyMaterial=*/ encryptedKeyMaterial,
+ /*keyMetadata=*/ metadata,
/*platformKeyGenerationId=*/ wrappingKey.getGenerationId(),
RecoveryController.RECOVERY_STATUS_SYNC_IN_PROGRESS);
}
@@ -110,11 +115,10 @@
* @see RecoveryController#RECOVERY_STATUS_SYNC_IN_PROGRESS
* @hide
*/
- public WrappedKey(byte[] nonce, byte[] keyMaterial, int platformKeyGenerationId) {
- mNonce = nonce;
- mKeyMaterial = keyMaterial;
- mPlatformKeyGenerationId = platformKeyGenerationId;
- mRecoveryStatus = RecoveryController.RECOVERY_STATUS_SYNC_IN_PROGRESS;
+ public WrappedKey(byte[] nonce, byte[] keyMaterial, @Nullable byte[] keyMetadata,
+ int platformKeyGenerationId) {
+ this(nonce, keyMaterial, keyMetadata, platformKeyGenerationId,
+ RecoveryController.RECOVERY_STATUS_SYNC_IN_PROGRESS);
}
/**
@@ -122,15 +126,18 @@
*
* @param nonce The nonce with which the key material was encrypted.
* @param keyMaterial The encrypted bytes of the key material.
+ * @param keyMetadata The metadata that will be authenticated (but unencrypted) together with
+ * the key material when the key is uploaded to cloud.
* @param platformKeyGenerationId The generation ID of the key used to wrap this key.
* @param recoveryStatus recovery status of the key.
*
* @hide
*/
- public WrappedKey(byte[] nonce, byte[] keyMaterial, int platformKeyGenerationId,
- int recoveryStatus) {
+ public WrappedKey(byte[] nonce, byte[] keyMaterial, @Nullable byte[] keyMetadata,
+ int platformKeyGenerationId, int recoveryStatus) {
mNonce = nonce;
mKeyMaterial = keyMaterial;
+ mKeyMetadata = keyMetadata;
mPlatformKeyGenerationId = platformKeyGenerationId;
mRecoveryStatus = recoveryStatus;
}
@@ -154,6 +161,15 @@
}
/**
+ * Returns the key metadata.
+ *
+ * @hide
+ */
+ public @Nullable byte[] getKeyMetadata() {
+ return mKeyMetadata;
+ }
+
+ /**
* Returns the generation ID of the platform key, with which this key was wrapped.
*
* @hide
@@ -181,12 +197,12 @@
*
* @hide
*/
- public static Map<String, SecretKey> unwrapKeys(
+ public static Map<String, Pair<SecretKey, byte[]>> unwrapKeys(
PlatformDecryptionKey platformKey,
Map<String, WrappedKey> wrappedKeys)
throws NoSuchAlgorithmException, NoSuchPaddingException, BadPlatformKeyException,
InvalidKeyException, InvalidAlgorithmParameterException {
- HashMap<String, SecretKey> unwrappedKeys = new HashMap<>();
+ HashMap<String, Pair<SecretKey, byte[]>> unwrappedKeys = new HashMap<>();
Cipher cipher = Cipher.getInstance(KEY_WRAP_CIPHER_ALGORITHM);
int platformKeyGenerationId = platformKey.getGenerationId();
@@ -219,7 +235,7 @@
e);
continue;
}
- unwrappedKeys.put(alias, key);
+ unwrappedKeys.put(alias, Pair.create(key, wrappedKey.getKeyMetadata()));
}
return unwrappedKeys;
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
index e69f73d..dffaffe 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
@@ -104,6 +104,12 @@
values.put(KeysEntry.COLUMN_NAME_LAST_SYNCED_AT, LAST_SYNCED_AT_UNSYNCED);
values.put(KeysEntry.COLUMN_NAME_GENERATION_ID, wrappedKey.getPlatformKeyGenerationId());
values.put(KeysEntry.COLUMN_NAME_RECOVERY_STATUS, wrappedKey.getRecoveryStatus());
+ byte[] keyMetadata = wrappedKey.getKeyMetadata();
+ if (keyMetadata == null) {
+ values.putNull(KeysEntry.COLUMN_NAME_KEY_METADATA);
+ } else {
+ values.put(KeysEntry.COLUMN_NAME_KEY_METADATA, keyMetadata);
+ }
return db.replace(KeysEntry.TABLE_NAME, /*nullColumnHack=*/ null, values);
}
@@ -119,7 +125,8 @@
KeysEntry.COLUMN_NAME_NONCE,
KeysEntry.COLUMN_NAME_WRAPPED_KEY,
KeysEntry.COLUMN_NAME_GENERATION_ID,
- KeysEntry.COLUMN_NAME_RECOVERY_STATUS};
+ KeysEntry.COLUMN_NAME_RECOVERY_STATUS,
+ KeysEntry.COLUMN_NAME_KEY_METADATA};
String selection =
KeysEntry.COLUMN_NAME_UID + " = ? AND "
+ KeysEntry.COLUMN_NAME_ALIAS + " = ?";
@@ -155,7 +162,17 @@
cursor.getColumnIndexOrThrow(KeysEntry.COLUMN_NAME_GENERATION_ID));
int recoveryStatus = cursor.getInt(
cursor.getColumnIndexOrThrow(KeysEntry.COLUMN_NAME_RECOVERY_STATUS));
- return new WrappedKey(nonce, keyMaterial, generationId, recoveryStatus);
+
+ // Retrieve the metadata associated with the key
+ byte[] keyMetadata;
+ int metadataIdx = cursor.getColumnIndexOrThrow(KeysEntry.COLUMN_NAME_KEY_METADATA);
+ if (cursor.isNull(metadataIdx)) {
+ keyMetadata = null;
+ } else {
+ keyMetadata = cursor.getBlob(metadataIdx);
+ }
+
+ return new WrappedKey(nonce, keyMaterial, keyMetadata, generationId, recoveryStatus);
}
}
@@ -252,7 +269,8 @@
KeysEntry.COLUMN_NAME_NONCE,
KeysEntry.COLUMN_NAME_WRAPPED_KEY,
KeysEntry.COLUMN_NAME_ALIAS,
- KeysEntry.COLUMN_NAME_RECOVERY_STATUS};
+ KeysEntry.COLUMN_NAME_RECOVERY_STATUS,
+ KeysEntry.COLUMN_NAME_KEY_METADATA};
String selection =
KeysEntry.COLUMN_NAME_USER_ID + " = ? AND "
+ KeysEntry.COLUMN_NAME_UID + " = ? AND "
@@ -283,8 +301,18 @@
cursor.getColumnIndexOrThrow(KeysEntry.COLUMN_NAME_ALIAS));
int recoveryStatus = cursor.getInt(
cursor.getColumnIndexOrThrow(KeysEntry.COLUMN_NAME_RECOVERY_STATUS));
- keys.put(alias, new WrappedKey(nonce, keyMaterial, platformKeyGenerationId,
- recoveryStatus));
+
+ // Retrieve the metadata associated with the key
+ byte[] keyMetadata;
+ int metadataIdx = cursor.getColumnIndexOrThrow(KeysEntry.COLUMN_NAME_KEY_METADATA);
+ if (cursor.isNull(metadataIdx)) {
+ keyMetadata = null;
+ } else {
+ keyMetadata = cursor.getBlob(metadataIdx);
+ }
+
+ keys.put(alias, new WrappedKey(nonce, keyMaterial, keyMetadata,
+ platformKeyGenerationId, recoveryStatus));
}
return keys;
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
index 22e77cc..b58ee4b 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
@@ -67,6 +67,12 @@
* Status of the key sync {@code RecoveryController#setRecoveryStatus}
*/
static final String COLUMN_NAME_RECOVERY_STATUS = "recovery_status";
+
+ /**
+ * Data blob that will be authenticated (but encrypted) together with the key when the key
+ * is uploaded to cloud.
+ */
+ static final String COLUMN_NAME_KEY_METADATA = "key_metadata";
}
/**
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java
index 43efe9c..b0613da 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java
@@ -32,7 +32,7 @@
class RecoverableKeyStoreDbHelper extends SQLiteOpenHelper {
private static final String TAG = "RecoverableKeyStoreDbHp";
- static final int DATABASE_VERSION = 4;
+ static final int DATABASE_VERSION = 5;
private static final String DATABASE_NAME = "recoverablekeystore.db";
private static final String SQL_CREATE_KEYS_ENTRY =
@@ -46,6 +46,7 @@
+ KeysEntry.COLUMN_NAME_GENERATION_ID + " INTEGER,"
+ KeysEntry.COLUMN_NAME_LAST_SYNCED_AT + " INTEGER,"
+ KeysEntry.COLUMN_NAME_RECOVERY_STATUS + " INTEGER,"
+ + KeysEntry.COLUMN_NAME_KEY_METADATA + " BLOB,"
+ "UNIQUE(" + KeysEntry.COLUMN_NAME_UID + ","
+ KeysEntry.COLUMN_NAME_ALIAS + "))";
@@ -135,6 +136,11 @@
oldVersion = 4;
}
+ if (oldVersion < 5 && newVersion >= 5) {
+ upgradeDbForVersion5(db);
+ oldVersion = 5;
+ }
+
if (oldVersion != newVersion) {
Log.e(TAG, "Failed to update recoverablekeystore database to the most recent version");
}
@@ -166,6 +172,13 @@
/*defaultStr=*/ null);
}
+ private void upgradeDbForVersion5(SQLiteDatabase db) {
+ Log.d(TAG, "Updating recoverable keystore database to version 5");
+ // adds a column to store the metadata for application keys
+ addColumnToTable(db, KeysEntry.TABLE_NAME,
+ KeysEntry.COLUMN_NAME_KEY_METADATA, "BLOB", /*defaultStr=*/ null);
+ }
+
private static void addColumnToTable(
SQLiteDatabase db, String tableName, String column, String columnType,
String defaultStr) {
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index fd365a7..b6dae19 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -33,7 +33,6 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.ILauncherApps;
import android.content.pm.IOnAppsChangedListener;
-import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.ShortcutQuery;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -43,8 +42,6 @@
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutServiceInternal;
import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener;
-import android.content.pm.Signature;
-import android.content.pm.SigningInfo;
import android.content.pm.UserInfo;
import android.graphics.Rect;
import android.net.Uri;
@@ -59,31 +56,21 @@
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.provider.Settings;
-import android.util.ByteStringUtils;
import android.util.Log;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
-import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
-import com.android.internal.util.StatLogger;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.wm.ActivityTaskManagerInternal;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
/**
* Service that manages requests and callbacks for launchers that support
@@ -121,17 +108,6 @@
static class LauncherAppsImpl extends ILauncherApps.Stub {
private static final boolean DEBUG = false;
private static final String TAG = "LauncherAppsService";
-
- // Stats
- @VisibleForTesting
- interface Stats {
- int INIT_VOUCHED_SIGNATURES = 0;
- int COUNT = INIT_VOUCHED_SIGNATURES + 1;
- }
- private final StatLogger mStatLogger = new StatLogger(new String[] {
- "initVouchedSignatures"
- });
-
private final Context mContext;
private final UserManager mUm;
private final UserManagerInternal mUserManagerInternal;
@@ -141,16 +117,11 @@
private final PackageCallbackList<IOnAppsChangedListener> mListeners
= new PackageCallbackList<IOnAppsChangedListener>();
private final DevicePolicyManager mDpm;
- private final ConcurrentHashMap<UserHandle, Set<String>> mVouchedSignaturesByUser;
- private final Set<String> mVouchProviders;
private final MyPackageMonitor mPackageMonitor = new MyPackageMonitor();
- private final VouchesChangedMonitor mVouchesChangedMonitor = new VouchesChangedMonitor();
private final Handler mCallbackHandler;
- private final Object mVouchedSignaturesLocked = new Object();
-
public LauncherAppsImpl(Context context) {
mContext = context;
mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
@@ -165,9 +136,6 @@
mShortcutServiceInternal.addListener(mPackageMonitor);
mCallbackHandler = BackgroundThread.getHandler();
mDpm = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
- mVouchedSignaturesByUser = new ConcurrentHashMap<>();
- mVouchProviders = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
- mVouchesChangedMonitor.register(mContext, UserHandle.ALL, true, mCallbackHandler);
}
@VisibleForTesting
@@ -387,7 +355,7 @@
}
ApplicationInfo appInfo = pmInt.getApplicationInfo(packageName, /*flags*/ 0,
callingUid, user.getIdentifier());
- if (shouldShowHiddenApp(user, appInfo)) {
+ if (shouldShowHiddenApp(appInfo)) {
ResolveInfo info = getHiddenAppActivityInfo(packageName, callingUid, user);
if (info != null) {
result.add(info);
@@ -403,7 +371,7 @@
user.getIdentifier(), callingUid);
for (ApplicationInfo applicationInfo : installedPackages) {
if (!visiblePackages.contains(applicationInfo.packageName)) {
- if (!shouldShowHiddenApp(user, applicationInfo)) {
+ if (!shouldShowHiddenApp(applicationInfo)) {
continue;
}
ResolveInfo info = getHiddenAppActivityInfo(applicationInfo.packageName,
@@ -419,126 +387,13 @@
}
}
- private boolean shouldShowHiddenApp(UserHandle user, ApplicationInfo appInfo) {
+ private static boolean shouldShowHiddenApp(ApplicationInfo appInfo) {
if (appInfo == null || appInfo.isSystemApp() || appInfo.isUpdatedSystemApp()) {
return false;
}
- if (!mVouchedSignaturesByUser.containsKey(user)) {
- initVouchedSignatures(user);
- }
- if (mVouchProviders.contains(appInfo.packageName)) {
- // If it's a vouching packages then we must show hidden app
- return true;
- }
- // If app's signature is in vouch list, do not show hidden app
- final Set<String> vouches = mVouchedSignaturesByUser.get(user);
- try {
- final PackageInfo pkgInfo = mContext.getPackageManager().getPackageInfo(
- appInfo.packageName, PackageManager.GET_SIGNING_CERTIFICATES);
- final Signature[] signatures = getLatestSignatures(pkgInfo.signingInfo);
- // If any of the signatures appears in vouches, then we don't show hidden app
- for (Signature signature : signatures) {
- final String certDigest = computePackageCertDigest(signature);
- if (vouches.contains(certDigest)) {
- return false;
- }
- }
- } catch (PackageManager.NameNotFoundException e) {
- // Should not happen
- }
return true;
}
- @VisibleForTesting
- static String computePackageCertDigest(Signature signature) {
- MessageDigest messageDigest;
- try {
- messageDigest = MessageDigest.getInstance("SHA1");
- } catch (NoSuchAlgorithmException e) {
- // Should not happen
- return null;
- }
- messageDigest.update(signature.toByteArray());
- final byte[] digest = messageDigest.digest();
- return ByteStringUtils.toHexString(digest);
- }
-
- @VisibleForTesting
- static Signature[] getLatestSignatures(SigningInfo signingInfo) {
- if (signingInfo.hasMultipleSigners()) {
- return signingInfo.getApkContentsSigners();
- } else {
- final Signature[] signatures = signingInfo.getSigningCertificateHistory();
- return new Signature[]{signatures[0]};
- }
- }
-
- private void updateVouches(String packageName, UserHandle user) {
- final PackageManagerInternal pmInt =
- LocalServices.getService(PackageManagerInternal.class);
- ApplicationInfo appInfo = pmInt.getApplicationInfo(packageName,
- PackageManager.GET_META_DATA, Binder.getCallingUid(), user.getIdentifier());
- updateVouches(appInfo, user);
- }
-
- private void updateVouches(ApplicationInfo appInfo, UserHandle user) {
- if (appInfo.metaData == null) {
- // No meta-data
- return;
- }
- int tokenResourceId = appInfo.metaData.getInt(LauncherApps.VOUCHED_CERTS_KEY);
- if (tokenResourceId == 0) {
- // No xml file
- return;
- }
- mVouchProviders.add(appInfo.packageName);
- Set<String> vouches = mVouchedSignaturesByUser.get(user);
- try {
- List<String> signatures = Arrays.asList(
- mContext.getPackageManager().getResourcesForApplication(
- appInfo.packageName).getStringArray(tokenResourceId));
- for (String signature : signatures) {
- vouches.add(signature.toUpperCase());
- }
- } catch (PackageManager.NameNotFoundException e) {
- // Should not happen
- }
- }
-
- private void initVouchedSignatures(UserHandle user) {
- synchronized (mVouchedSignaturesLocked) {
- if (mVouchedSignaturesByUser.contains(user)) {
- return;
- }
- final long startTime = mStatLogger.getTime();
-
- Set<String> vouches = Collections.newSetFromMap(
- new ConcurrentHashMap<String, Boolean>());
-
- final int callingUid = injectBinderCallingUid();
- long ident = Binder.clearCallingIdentity();
- try {
- final PackageManagerInternal pmInt =
- LocalServices.getService(PackageManagerInternal.class);
- List<ApplicationInfo> installedPackages = pmInt.getInstalledApplications(
- PackageManager.GET_META_DATA, user.getIdentifier(), callingUid);
- for (ApplicationInfo appInfo : installedPackages) {
- updateVouches(appInfo, user);
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- mVouchedSignaturesByUser.putIfAbsent(user, vouches);
- mStatLogger.logDurationStat(Stats.INIT_VOUCHED_SIGNATURES, startTime);
- }
- }
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
- mStatLogger.dump(pw, " ");
- }
-
@Override
public ActivityInfo resolveActivity(
String callingPackage, ComponentName component, UserHandle user)
@@ -905,18 +760,6 @@
mCallbackHandler.post(r);
}
- private class VouchesChangedMonitor extends PackageMonitor {
- @Override
- public void onPackageAdded(String packageName, int uid) {
- updateVouches(packageName, new UserHandle(getChangingUserId()));
- }
-
- @Override
- public void onPackageModified(String packageName) {
- updateVouches(packageName, new UserHandle(getChangingUserId()));
- }
- }
-
private class MyPackageMonitor extends PackageMonitor implements ShortcutChangeListener {
// TODO Simplify with lambdas.
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6fe32c5..3300900 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1460,8 +1460,9 @@
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, args.traceMethod,
args.traceCookie);
}
- } else {
- Slog.e(TAG, "Bogus post-install token " + msg.arg1);
+ } else if (DEBUG_INSTALL) {
+ // No post-install when we run restore from installExistingPackageForUser
+ Slog.i(TAG, "Nothing to do for post-install token " + msg.arg1);
}
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "postInstall", msg.arg1);
@@ -12737,6 +12738,11 @@
@Override
public int installExistingPackageAsUser(String packageName, int userId, int installFlags,
int installReason) {
+ if (DEBUG_INSTALL) {
+ Log.v(TAG, "installExistingPackageAsUser package=" + packageName + " userId=" + userId
+ + " installFlags=" + installFlags + " installReason=" + installReason);
+ }
+
final int callingUid = Binder.getCallingUid();
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES)
!= PackageManager.PERMISSION_GRANTED
@@ -12807,6 +12813,11 @@
synchronized (mPackages) {
updateSequenceNumberLP(pkgSetting, new int[]{ userId });
}
+ // start async restore with no post-install since we finish install here
+ PackageInstalledInfo res =
+ createPackageInstalledInfo(PackageManager.INSTALL_SUCCEEDED);
+ res.pkg = pkgSetting.pkg;
+ restoreAndPostInstall(userId, res, null);
}
} finally {
Binder.restoreCallingIdentity(callingId);
@@ -13746,8 +13757,8 @@
}
}
for (InstallRequest request : installRequests) {
- resolvePackageInstalledInfo(request.args,
- request.installResult);
+ restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
+ new PostInstallData(request.args, request.installResult));
}
});
}
@@ -13762,7 +13773,14 @@
return res;
}
- private void resolvePackageInstalledInfo(InstallArgs args, PackageInstalledInfo res) {
+ /** @param data Post-install is performed only if this is non-null. */
+ private void restoreAndPostInstall(
+ int userId, PackageInstalledInfo res, @Nullable PostInstallData data) {
+ if (DEBUG_INSTALL) {
+ Log.v(TAG, "restoreAndPostInstall userId=" + userId + " package="
+ + res.pkg.packageName);
+ }
+
// A restore should be performed at this point if (a) the install
// succeeded, (b) the operation is not an update, and (c) the new
// package has not opted out of backup participation.
@@ -13778,9 +13796,12 @@
int token;
if (mNextInstallToken < 0) mNextInstallToken = 1;
token = mNextInstallToken++;
+ if (data != null) {
+ mRunningInstalls.put(token, data);
+ } else if (DEBUG_INSTALL) {
+ Log.v(TAG, "No post-install required for " + token);
+ }
- PostInstallData data = new PostInstallData(args, res);
- mRunningInstalls.put(token, data);
if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
@@ -13791,7 +13812,6 @@
IBackupManager bm = IBackupManager.Stub.asInterface(
ServiceManager.getService(Context.BACKUP_SERVICE));
if (bm != null) {
- int userId = args.user.getIdentifier();
// For backwards compatibility as USER_ALL previously routed directly to USER_SYSTEM
// in the BackupManager. USER_ALL is used in compatibility tests.
if (userId == UserHandle.USER_ALL) {
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index dcb2ff5..f3c19d0 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -81,7 +81,7 @@
static jmethodID method_correctionSatConstType;
static jmethodID method_correctionSatId;
static jmethodID method_correctionSatCarrierFreq;
-static jmethodID method_correctionSatIsLos;
+static jmethodID method_correctionSatIsLosProb;
static jmethodID method_correctionSatEpl;
static jmethodID method_correctionSatEplUnc;
static jmethodID method_correctionSatRefPlane;
@@ -2277,8 +2277,8 @@
singleSatCorrClass, "getSatId", "()I");
method_correctionSatCarrierFreq = env->GetMethodID(
singleSatCorrClass, "getCarrierFrequencyHz", "()F");
- method_correctionSatIsLos = env->GetMethodID(
- singleSatCorrClass,"getSatIsLos", "()Z");
+ method_correctionSatIsLosProb = env->GetMethodID(
+ singleSatCorrClass,"getProbSatIsLos", "()F");
method_correctionSatEpl = env->GetMethodID(
singleSatCorrClass, "getExcessPathLengthMeters", "()F");
method_correctionSatEplUnc = env->GetMethodID(
@@ -2296,8 +2296,8 @@
env->CallIntMethod(singleSatCorrectionObj, method_correctionSatId);
jfloat carrierFreqHz = env->CallFloatMethod(
singleSatCorrectionObj, method_correctionSatCarrierFreq);
- jboolean satIsLos = env->CallBooleanMethod(singleSatCorrectionObj,
- method_correctionSatIsLos);
+ jfloat probSatIsLos = env->CallFloatMethod(singleSatCorrectionObj,
+ method_correctionSatIsLosProb);
jfloat eplMeters =
env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEpl);
jfloat eplUncMeters = env->CallFloatMethod(singleSatCorrectionObj,
@@ -2337,7 +2337,7 @@
.constellation = static_cast<GnssConstellationType>(constType),
.svid = static_cast<uint16_t>(satId),
.carrierFrequencyHz = carrierFreqHz,
- .satIsLos = static_cast<bool>(satIsLos),
+ .probSatIsLos = probSatIsLos,
.excessPathLengthMeters = eplMeters,
.excessPathLengthUncertaintyMeters = eplUncMeters,
.reflectingPlane = reflectingPlane,
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
index 8a9e5d1..c2d4846 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
@@ -23,6 +23,7 @@
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
+
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertArrayEquals;
@@ -91,6 +92,9 @@
private static final byte[] TEST_VAULT_HANDLE =
new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
private static final String TEST_APP_KEY_ALIAS = "rcleaver";
+ private static final byte[] TEST_APP_KEY_METADATA_NULL = null;
+ private static final byte[] TEST_APP_KEY_METADATA_NON_NULL =
+ "mdata".getBytes(StandardCharsets.UTF_8);
private static final int TEST_GENERATION_ID = 2;
private static final int TEST_CREDENTIAL_TYPE = CREDENTIAL_TYPE_PATTERN;
private static final String TEST_CREDENTIAL = "pas123";
@@ -251,7 +255,7 @@
TEST_USER_ID,
TEST_RECOVERY_AGENT_UID,
TEST_APP_KEY_ALIAS,
- WrappedKey.fromSecretKey(mEncryptKey, applicationKey));
+ WrappedKey.fromSecretKey(mEncryptKey, applicationKey, TEST_APP_KEY_METADATA_NULL));
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
mKeySyncTask.run();
@@ -267,7 +271,7 @@
TEST_USER_ID,
TEST_RECOVERY_AGENT_UID,
TEST_APP_KEY_ALIAS,
- WrappedKey.fromSecretKey(mEncryptKey, applicationKey));
+ WrappedKey.fromSecretKey(mEncryptKey, applicationKey, TEST_APP_KEY_METADATA_NULL));
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
@@ -545,18 +549,20 @@
assertEquals(TEST_APP_KEY_ALIAS, keyData.getAlias());
assertThat(keyData.getAlias()).isEqualTo(keyData.getAlias());
byte[] appKey = KeySyncUtils.decryptApplicationKey(
- recoveryKey, keyData.getEncryptedKeyMaterial());
+ recoveryKey, keyData.getEncryptedKeyMaterial(), TEST_APP_KEY_METADATA_NULL);
assertThat(appKey).isEqualTo(applicationKey.getEncoded());
}
@Test
- public void run_sendsEncryptedKeysIfAvailableToSync_withCertPath() throws Exception {
+ public void run_sendsEncryptedKeysIfAvailableToSync_withCertPath_withNullKeyMetadata()
+ throws Exception {
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
mRecoverableKeyStoreDb.setServerParams(
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE);
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
- addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
+ addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS,
+ TEST_APP_KEY_METADATA_NULL);
mKeySyncTask.run();
@@ -564,6 +570,33 @@
verify(mSnapshotListenersStorage).recoverySnapshotAvailable(TEST_RECOVERY_AGENT_UID);
List<WrappedApplicationKey> applicationKeys = keyChainSnapshot.getWrappedApplicationKeys();
assertThat(applicationKeys).hasSize(1);
+ WrappedApplicationKey keyData = applicationKeys.get(0);
+ assertThat(keyData.getAlias()).isEqualTo(TEST_APP_KEY_ALIAS);
+ assertThat(keyData.getMetadata()).isEqualTo(TEST_APP_KEY_METADATA_NULL);
+ assertThat(keyChainSnapshot.getTrustedHardwareCertPath())
+ .isEqualTo(TestData.CERT_PATH_1);
+ }
+
+ @Test
+ public void run_sendsEncryptedKeysIfAvailableToSync_withCertPath_withNonNullKeyMetadata()
+ throws Exception {
+ mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
+ TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
+ mRecoverableKeyStoreDb.setServerParams(
+ TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE);
+ when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
+ addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS,
+ TEST_APP_KEY_METADATA_NON_NULL);
+
+ mKeySyncTask.run();
+
+ KeyChainSnapshot keyChainSnapshot = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
+ verify(mSnapshotListenersStorage).recoverySnapshotAvailable(TEST_RECOVERY_AGENT_UID);
+ List<WrappedApplicationKey> applicationKeys = keyChainSnapshot.getWrappedApplicationKeys();
+ assertThat(applicationKeys).hasSize(1);
+ WrappedApplicationKey keyData = applicationKeys.get(0);
+ assertThat(keyData.getAlias()).isEqualTo(TEST_APP_KEY_ALIAS);
+ assertThat(keyData.getMetadata()).isEqualTo(TEST_APP_KEY_METADATA_NON_NULL);
assertThat(keyChainSnapshot.getTrustedHardwareCertPath())
.isEqualTo(TestData.CERT_PATH_1);
}
@@ -788,6 +821,11 @@
private SecretKey addApplicationKey(int userId, int recoveryAgentUid, String alias)
throws Exception{
+ return addApplicationKey(userId, recoveryAgentUid, alias, TEST_APP_KEY_METADATA_NULL);
+ }
+
+ private SecretKey addApplicationKey(int userId, int recoveryAgentUid, String alias,
+ byte[] metadata) throws Exception {
SecretKey applicationKey = generateKey();
mRecoverableKeyStoreDb.setServerParams(
userId, recoveryAgentUid, TEST_VAULT_HANDLE);
@@ -800,7 +838,7 @@
userId,
recoveryAgentUid,
alias,
- WrappedKey.fromSecretKey(mEncryptKey, applicationKey));
+ WrappedKey.fromSecretKey(mEncryptKey, applicationKey, metadata));
return applicationKey;
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncUtilsTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncUtilsTest.java
index f832d3c..178fd10 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncUtilsTest.java
@@ -22,6 +22,8 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import android.util.Pair;
+
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -65,7 +67,8 @@
private static final byte[] RECOVERY_RESPONSE_HEADER =
"V1 reencrypted_recovery_key".getBytes(StandardCharsets.UTF_8);
private static final int PUBLIC_KEY_LENGTH_BYTES = 65;
-
+ private static final byte[] NULL_METADATA = null;
+ private static final byte[] NON_NULL_METADATA = "somemetadata".getBytes(StandardCharsets.UTF_8);
@Test
public void calculateThmKfHash_isShaOfLockScreenHashWithPrefix() throws Exception {
@@ -125,18 +128,35 @@
}
@Test
- public void decryptApplicationKey_decryptsAnApplicationKeyEncryptedWithSecureBox()
- throws Exception {
+ public void decryptApplicationKey_decryptsAnApplicationKey_nullMetadata() throws Exception {
String alias = "phoebe";
SecretKey recoveryKey = KeySyncUtils.generateRecoveryKey();
SecretKey applicationKey = generateApplicationKey();
Map<String, byte[]> encryptedKeys =
KeySyncUtils.encryptKeysWithRecoveryKey(
- recoveryKey, ImmutableMap.of(alias, applicationKey));
+ recoveryKey,
+ ImmutableMap.of(alias, Pair.create(applicationKey, NULL_METADATA)));
byte[] encryptedKey = encryptedKeys.get(alias);
- byte[] keyMaterial =
- KeySyncUtils.decryptApplicationKey(recoveryKey.getEncoded(), encryptedKey);
+ byte[] keyMaterial = KeySyncUtils.decryptApplicationKey(recoveryKey.getEncoded(),
+ encryptedKey, NULL_METADATA);
+
+ assertArrayEquals(applicationKey.getEncoded(), keyMaterial);
+ }
+
+ @Test
+ public void decryptApplicationKey_decryptsAnApplicationKey_nonNullMetadata() throws Exception {
+ String alias = "phoebe";
+ SecretKey recoveryKey = KeySyncUtils.generateRecoveryKey();
+ SecretKey applicationKey = generateApplicationKey();
+ Map<String, byte[]> encryptedKeys =
+ KeySyncUtils.encryptKeysWithRecoveryKey(
+ recoveryKey,
+ ImmutableMap.of(alias, Pair.create(applicationKey, NON_NULL_METADATA)));
+ byte[] encryptedKey = encryptedKeys.get(alias);
+
+ byte[] keyMaterial = KeySyncUtils.decryptApplicationKey(recoveryKey.getEncoded(),
+ encryptedKey, NON_NULL_METADATA);
assertArrayEquals(applicationKey.getEncoded(), keyMaterial);
}
@@ -147,12 +167,13 @@
Map<String, byte[]> encryptedKeys =
KeySyncUtils.encryptKeysWithRecoveryKey(
KeySyncUtils.generateRecoveryKey(),
- ImmutableMap.of("casper", generateApplicationKey()));
+ ImmutableMap.of("casper",
+ Pair.create(generateApplicationKey(), NULL_METADATA)));
byte[] encryptedKey = encryptedKeys.get(alias);
try {
- KeySyncUtils.decryptApplicationKey(
- KeySyncUtils.generateRecoveryKey().getEncoded(), encryptedKey);
+ KeySyncUtils.decryptApplicationKey(KeySyncUtils.generateRecoveryKey().getEncoded(),
+ encryptedKey, NULL_METADATA);
fail("Did not throw decrypting with bad key.");
} catch (AEADBadTagException error) {
// expected
@@ -160,6 +181,47 @@
}
@Test
+ public void decryptApplicationKey_throwsIfWrongMetadata() throws Exception {
+ String alias1 = "casper1";
+ String alias2 = "casper2";
+ String alias3 = "casper3";
+ SecretKey recoveryKey = KeySyncUtils.generateRecoveryKey();
+
+ Map<String, byte[]> encryptedKeys =
+ KeySyncUtils.encryptKeysWithRecoveryKey(
+ recoveryKey,
+ ImmutableMap.of(
+ alias1,
+ Pair.create(generateApplicationKey(), NULL_METADATA),
+ alias2,
+ Pair.create(generateApplicationKey(), NON_NULL_METADATA),
+ alias3,
+ Pair.create(generateApplicationKey(), NON_NULL_METADATA)));
+
+ try {
+ KeySyncUtils.decryptApplicationKey(recoveryKey.getEncoded(),
+ encryptedKeys.get(alias1), NON_NULL_METADATA);
+ fail("Did not throw decrypting with wrong metadata.");
+ } catch (AEADBadTagException error) {
+ // expected
+ }
+ try {
+ KeySyncUtils.decryptApplicationKey(recoveryKey.getEncoded(),
+ encryptedKeys.get(alias2), NULL_METADATA);
+ fail("Did not throw decrypting with wrong metadata.");
+ } catch (AEADBadTagException error) {
+ // expected
+ }
+ try {
+ KeySyncUtils.decryptApplicationKey(recoveryKey.getEncoded(),
+ encryptedKeys.get(alias3), "different".getBytes(StandardCharsets.UTF_8));
+ fail("Did not throw decrypting with wrong metadata.");
+ } catch (AEADBadTagException error) {
+ // expected
+ }
+ }
+
+ @Test
public void decryptRecoveryKey_decryptsALocallyEncryptedKey() throws Exception {
SecretKey recoveryKey = KeySyncUtils.generateRecoveryKey();
byte[] encrypted = KeySyncUtils.locallyEncryptRecoveryKey(
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java
index 48afb8b..c295177 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java
@@ -20,6 +20,7 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import android.content.Context;
import android.security.keystore.AndroidKeyStoreSecretKey;
@@ -60,6 +61,9 @@
private static final int TEST_USER_ID = 1000;
private static final int KEYSTORE_UID_SELF = -1;
private static final int GCM_TAG_LENGTH_BITS = 128;
+ private static final byte[] NULL_METADATA = null;
+ private static final byte[] NON_NULL_METADATA = "test-metadata".getBytes(
+ StandardCharsets.UTF_8);
private PlatformEncryptionKey mPlatformKey;
private PlatformDecryptionKey mDecryptKey;
@@ -90,18 +94,29 @@
}
@Test
- public void generateAndStoreKey_storesWrappedKey() throws Exception {
+ public void generateAndStoreKey_storesWrappedKey_nullMetadata() throws Exception {
mRecoverableKeyGenerator.generateAndStoreKey(
- mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS);
+ mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS, NULL_METADATA);
WrappedKey wrappedKey = mRecoverableKeyStoreDb.getKey(KEYSTORE_UID_SELF, TEST_ALIAS);
assertNotNull(wrappedKey);
+ assertNull(wrappedKey.getKeyMetadata());
+ }
+
+ @Test
+ public void generateAndStoreKey_storesWrappedKey_nonNullMetadata() throws Exception {
+ mRecoverableKeyGenerator.generateAndStoreKey(
+ mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS, NON_NULL_METADATA);
+
+ WrappedKey wrappedKey = mRecoverableKeyStoreDb.getKey(KEYSTORE_UID_SELF, TEST_ALIAS);
+ assertNotNull(wrappedKey);
+ assertArrayEquals(NON_NULL_METADATA, wrappedKey.getKeyMetadata());
}
@Test
public void generateAndStoreKey_returnsRawMaterialOfCorrectLength() throws Exception {
byte[] rawKey = mRecoverableKeyGenerator.generateAndStoreKey(
- mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS);
+ mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS, NON_NULL_METADATA);
assertEquals(KEY_SIZE_BYTES, rawKey.length);
}
@@ -109,7 +124,7 @@
@Test
public void generateAndStoreKey_storesTheWrappedVersionOfTheRawMaterial() throws Exception {
byte[] rawMaterial = mRecoverableKeyGenerator.generateAndStoreKey(
- mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS);
+ mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS, NULL_METADATA);
WrappedKey wrappedKey = mRecoverableKeyStoreDb.getKey(KEYSTORE_UID_SELF, TEST_ALIAS);
Cipher cipher = Cipher.getInstance(KEY_WRAP_ALGORITHM);
@@ -120,10 +135,30 @@
}
@Test
+ public void importKey_storesNullMetadata() throws Exception {
+ mRecoverableKeyGenerator.importKey(
+ mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS,
+ randomBytes(KEY_SIZE_BYTES),
+ NULL_METADATA);
+ assertNull(mRecoverableKeyStoreDb.getKey(KEYSTORE_UID_SELF, TEST_ALIAS).getKeyMetadata());
+ }
+
+ @Test
+ public void importKey_storesNonNullMetadata() throws Exception {
+ mRecoverableKeyGenerator.importKey(
+ mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS,
+ randomBytes(KEY_SIZE_BYTES),
+ NON_NULL_METADATA);
+ assertArrayEquals(NON_NULL_METADATA,
+ mRecoverableKeyStoreDb.getKey(KEYSTORE_UID_SELF, TEST_ALIAS).getKeyMetadata());
+ }
+
+ @Test
public void importKey_storesTheWrappedVersionOfTheRawMaterial() throws Exception {
byte[] rawMaterial = randomBytes(KEY_SIZE_BYTES);
mRecoverableKeyGenerator.importKey(
- mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS, rawMaterial);
+ mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS, rawMaterial,
+ NULL_METADATA);
WrappedKey wrappedKey = mRecoverableKeyStoreDb.getKey(KEYSTORE_UID_SELF, TEST_ALIAS);
Cipher cipher = Cipher.getInstance(KEY_WRAP_ALGORITHM);
@@ -145,10 +180,6 @@
return (AndroidKeyStoreSecretKey) keyGenerator.generateKey();
}
- private static byte[] getUtf8Bytes(String s) {
- return s.getBytes(StandardCharsets.UTF_8);
- }
-
private static byte[] randomBytes(int n) {
byte[] bytes = new byte[n];
new Random().nextBytes(bytes);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index b15863d..c78b96d 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -52,6 +52,7 @@
import android.security.keystore.recovery.RecoveryCertPath;
import android.security.keystore.recovery.TrustedRootCertificates;
import android.security.keystore.recovery.WrappedApplicationKey;
+import android.util.Pair;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -134,6 +135,8 @@
private static final int GENERATION_ID = 1;
private static final byte[] NONCE = getUtf8Bytes("nonce");
private static final byte[] KEY_MATERIAL = getUtf8Bytes("keymaterial");
+ private static final byte[] KEY_METADATA_NULL = null;
+ private static final byte[] KEY_METADATA_NON_NULL = getUtf8Bytes("keymetametadata");
private static final String KEY_ALGORITHM = "AES";
private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
private static final String WRAPPING_KEY_ALIAS = "RecoverableKeyStoreManagerTest/WrappingKey";
@@ -231,6 +234,77 @@
}
@Test
+ public void importKeyWithMetadata_nullMetadata_storesTheKey() throws Exception {
+ int uid = Binder.getCallingUid();
+ int userId = UserHandle.getCallingUserId();
+ byte[] keyMaterial = randomBytes(APPLICATION_KEY_SIZE_BYTES);
+
+ mRecoverableKeyStoreManager.importKeyWithMetadata(
+ TEST_ALIAS, keyMaterial, KEY_METADATA_NULL);
+
+ assertThat(mRecoverableKeyStoreDb.getKey(uid, TEST_ALIAS)).isNotNull();
+ assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isTrue();
+ }
+
+ @Test
+ public void importKeyWithMetadata_nonNullMetadata_storesTheKey() throws Exception {
+ int uid = Binder.getCallingUid();
+ int userId = UserHandle.getCallingUserId();
+ byte[] keyMaterial = randomBytes(APPLICATION_KEY_SIZE_BYTES);
+
+ mRecoverableKeyStoreManager.importKeyWithMetadata(
+ TEST_ALIAS, keyMaterial, KEY_METADATA_NON_NULL);
+
+ assertThat(mRecoverableKeyStoreDb.getKey(uid, TEST_ALIAS)).isNotNull();
+ assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isTrue();
+ }
+
+ @Test
+ public void importKeyWithMetadata_throwsIfInvalidLength() throws Exception {
+ byte[] keyMaterial = randomBytes(APPLICATION_KEY_SIZE_BYTES - 1);
+ try {
+ mRecoverableKeyStoreManager.importKeyWithMetadata(
+ TEST_ALIAS, keyMaterial, KEY_METADATA_NON_NULL);
+ fail("should have thrown");
+ } catch (ServiceSpecificException e) {
+ assertThat(e.getMessage()).contains("not contain 256 bits");
+ }
+ }
+
+ @Test
+ public void importKeyWithMetadata_throwsIfNullKey() throws Exception {
+ try {
+ mRecoverableKeyStoreManager.importKeyWithMetadata(
+ TEST_ALIAS, /*keyBytes=*/ null, KEY_METADATA_NON_NULL);
+ fail("should have thrown");
+ } catch (NullPointerException e) {
+ assertThat(e.getMessage()).contains("is null");
+ }
+ }
+
+ @Test
+ public void generateKeyWithMetadata_nullMetadata_storesTheKey() throws Exception {
+ int uid = Binder.getCallingUid();
+ int userId = UserHandle.getCallingUserId();
+
+ mRecoverableKeyStoreManager.generateKeyWithMetadata(TEST_ALIAS, KEY_METADATA_NULL);
+
+ assertThat(mRecoverableKeyStoreDb.getKey(uid, TEST_ALIAS)).isNotNull();
+ assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isTrue();
+ }
+
+ @Test
+ public void generateKeyWithMetadata_nonNullMetadata_storesTheKey() throws Exception {
+ int uid = Binder.getCallingUid();
+ int userId = UserHandle.getCallingUserId();
+
+ mRecoverableKeyStoreManager.generateKeyWithMetadata(TEST_ALIAS, KEY_METADATA_NON_NULL);
+
+ assertThat(mRecoverableKeyStoreDb.getKey(uid, TEST_ALIAS)).isNotNull();
+ assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isTrue();
+ }
+
+ @Test
public void removeKey_removesAKey() throws Exception {
int uid = Binder.getCallingUid();
mRecoverableKeyStoreManager.generateKey(TEST_ALIAS);
@@ -1143,7 +1217,10 @@
int status = 100;
int status2 = 200;
String alias = "key1";
- WrappedKey wrappedKey = new WrappedKey(NONCE, KEY_MATERIAL, GENERATION_ID, status);
+ byte[] keyMetadata = null;
+
+ WrappedKey wrappedKey = new WrappedKey(NONCE, KEY_MATERIAL, keyMetadata, GENERATION_ID,
+ status);
mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey);
Map<String, Integer> statuses =
mRecoverableKeyStoreManager.getRecoveryStatus();
@@ -1169,7 +1246,8 @@
private static byte[] encryptedApplicationKey(
SecretKey recoveryKey, byte[] applicationKey) throws Exception {
return KeySyncUtils.encryptKeysWithRecoveryKey(recoveryKey, ImmutableMap.of(
- TEST_ALIAS, new SecretKeySpec(applicationKey, "AES")
+ TEST_ALIAS,
+ Pair.create(new SecretKeySpec(applicationKey, "AES"), /*metadata=*/ null)
)).get(TEST_ALIAS);
}
@@ -1203,7 +1281,7 @@
private void generateKeyAndSimulateSync(int userId, int uid, int snapshotVersion)
throws Exception{
- mRecoverableKeyStoreManager.generateKey(TEST_ALIAS);
+ mRecoverableKeyStoreManager.generateKeyWithMetadata(TEST_ALIAS, KEY_METADATA_NULL);
// Simulate key sync.
mRecoverableKeyStoreDb.setSnapshotVersion(userId, uid, snapshotVersion);
mRecoverableKeyStoreDb.setShouldCreateSnapshot(userId, uid, false);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java
index 944d6e0..9b4c3be 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java
@@ -3,6 +3,7 @@
import static com.google.common.truth.Truth.assertThat;
import android.security.keystore.recovery.TrustedRootCertificates;
+import android.util.Pair;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -64,10 +65,10 @@
@Test
public void testKeepOnlyWhitelistedInsecureKeys_emptyKeysList() throws Exception {
- Map<String, SecretKey> rawKeys = new HashMap<>();
- Map<String, SecretKey> expectedResult = new HashMap<>();
+ Map<String, Pair<SecretKey, byte[]>> rawKeys = new HashMap<>();
+ Map<String, Pair<SecretKey, byte[]>> expectedResult = new HashMap<>();
- Map<String, SecretKey> filteredKeys =
+ Map<String, Pair<SecretKey, byte[]>> filteredKeys =
mHelper.keepOnlyWhitelistedInsecureKeys(rawKeys);
assertThat(filteredKeys.entrySet()).containsExactlyElementsIn(expectedResult.entrySet());
assertThat(filteredKeys.entrySet()).containsAllIn(rawKeys.entrySet());
@@ -75,13 +76,13 @@
@Test
public void testKeepOnlyWhitelistedInsecureKeys_singleNonWhitelistedKey() throws Exception {
- Map<String, SecretKey> rawKeys = new HashMap<>();
- Map<String, SecretKey> expectedResult = new HashMap<>();
+ Map<String, Pair<SecretKey, byte[]>> rawKeys = new HashMap<>();
+ Map<String, Pair<SecretKey, byte[]>> expectedResult = new HashMap<>();
String alias = "secureAlias";
- rawKeys.put(alias, TestData.generateKey());
+ rawKeys.put(alias, Pair.create(TestData.generateKey(), /*metadata=*/ null));
- Map<String, SecretKey> filteredKeys =
+ Map<String, Pair<SecretKey, byte[]>> filteredKeys =
mHelper.keepOnlyWhitelistedInsecureKeys(rawKeys);
assertThat(filteredKeys.entrySet()).containsExactlyElementsIn(expectedResult.entrySet());
assertThat(rawKeys.entrySet()).containsAllIn(filteredKeys.entrySet());
@@ -89,14 +90,14 @@
@Test
public void testKeepOnlyWhitelistedInsecureKeys_singleWhitelistedKey() throws Exception {
- Map<String, SecretKey> rawKeys = new HashMap<>();
- Map<String, SecretKey> expectedResult = new HashMap<>();
+ Map<String, Pair<SecretKey, byte[]>> rawKeys = new HashMap<>();
+ Map<String, Pair<SecretKey, byte[]>> expectedResult = new HashMap<>();
String alias = TrustedRootCertificates.INSECURE_KEY_ALIAS_PREFIX;
- rawKeys.put(alias, TestData.generateKey());
+ rawKeys.put(alias, Pair.create(TestData.generateKey(), /*metadata=*/ null));
expectedResult.put(alias, rawKeys.get(alias));
- Map<String, SecretKey> filteredKeys =
+ Map<String, Pair<SecretKey, byte[]>> filteredKeys =
mHelper.keepOnlyWhitelistedInsecureKeys(rawKeys);
assertThat(filteredKeys.entrySet()).containsExactlyElementsIn(expectedResult.entrySet());
assertThat(rawKeys.entrySet()).containsAllIn(filteredKeys.entrySet());
@@ -104,21 +105,21 @@
@Test
public void testKeepOnlyWhitelistedInsecureKeys() throws Exception {
- Map<String, SecretKey> rawKeys = new HashMap<>();
- Map<String, SecretKey> expectedResult = new HashMap<>();
+ Map<String, Pair<SecretKey, byte[]>> rawKeys = new HashMap<>();
+ Map<String, Pair<SecretKey, byte[]>> expectedResult = new HashMap<>();
String alias = "SECURE_ALIAS" + TrustedRootCertificates.INSECURE_KEY_ALIAS_PREFIX;
- rawKeys.put(alias, TestData.generateKey());
+ rawKeys.put(alias, Pair.create(TestData.generateKey(), /*metadata=*/ null));
alias = TrustedRootCertificates.INSECURE_KEY_ALIAS_PREFIX + "1";
- rawKeys.put(alias, TestData.generateKey());
+ rawKeys.put(alias, Pair.create(TestData.generateKey(), /*metadata=*/ null));
expectedResult.put(alias, rawKeys.get(alias));
alias = TrustedRootCertificates.INSECURE_KEY_ALIAS_PREFIX + "2";
- rawKeys.put(alias, TestData.generateKey());
+ rawKeys.put(alias, Pair.create(TestData.generateKey(), /*metadata=*/ null));
expectedResult.put(alias, rawKeys.get(alias));
- Map<String, SecretKey> filteredKeys =
+ Map<String, Pair<SecretKey, byte[]>> filteredKeys =
mHelper.keepOnlyWhitelistedInsecureKeys(rawKeys);
assertThat(filteredKeys.entrySet()).containsExactlyElementsIn(expectedResult.entrySet());
assertThat(rawKeys.entrySet()).containsAllIn(filteredKeys.entrySet());
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/WrappedKeyTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/WrappedKeyTest.java
index b5ee60e..9813ab7 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/WrappedKeyTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/WrappedKeyTest.java
@@ -24,6 +24,7 @@
import android.security.keystore.AndroidKeyStoreSecretKey;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
+import android.util.Pair;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -32,6 +33,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.nio.charset.StandardCharsets;
import java.security.KeyStore;
import java.util.HashMap;
import java.util.Map;
@@ -47,26 +49,49 @@
private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
private static final String KEY_ALGORITHM = "AES";
private static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding";
- private static final String WRAPPING_KEY_ALIAS = "WrappedKeyTestWrappingKeyAlias";
+ private static final String WRAPPED_KEY_ALIAS = "WrappedKeyTestWrappingKeyAlias";
private static final int GENERATION_ID = 1;
private static final int GCM_TAG_LENGTH_BYTES = 16;
private static final int BITS_PER_BYTE = 8;
private static final int GCM_TAG_LENGTH_BITS = GCM_TAG_LENGTH_BYTES * BITS_PER_BYTE;
+ private static final byte[] NULL_METADATA = null;
+ private static final byte[] NON_NULL_METADATA = "keyMetadata".getBytes(StandardCharsets.UTF_8);
@After
public void tearDown() throws Exception {
KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER);
keyStore.load(/*param=*/ null);
- keyStore.deleteEntry(WRAPPING_KEY_ALIAS);
+ keyStore.deleteEntry(WRAPPED_KEY_ALIAS);
}
+ // TODO: Add tests for non-null metadata
+
@Test
- public void fromSecretKey_createsWrappedKeyThatCanBeUnwrapped() throws Exception {
+ public void fromSecretKey_createsWrappedKeyThatCanBeUnwrapped_nullMetadata() throws Exception {
PlatformEncryptionKey wrappingKey = new PlatformEncryptionKey(
GENERATION_ID, generateAndroidKeyStoreKey());
SecretKey rawKey = generateKey();
- WrappedKey wrappedKey = WrappedKey.fromSecretKey(wrappingKey, rawKey);
+ WrappedKey wrappedKey = WrappedKey.fromSecretKey(wrappingKey, rawKey, NULL_METADATA);
+
+ Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
+ cipher.init(
+ Cipher.UNWRAP_MODE,
+ wrappingKey.getKey(),
+ new GCMParameterSpec(GCM_TAG_LENGTH_BITS, wrappedKey.getNonce()));
+ SecretKey unwrappedKey = (SecretKey) cipher.unwrap(
+ wrappedKey.getKeyMaterial(), KEY_ALGORITHM, Cipher.SECRET_KEY);
+ assertEquals(rawKey, unwrappedKey);
+ }
+
+ @Test
+ public void fromSecretKey_createsWrappedKeyThatCanBeUnwrapped_nonNullMetadata()
+ throws Exception {
+ PlatformEncryptionKey wrappingKey = new PlatformEncryptionKey(
+ GENERATION_ID, generateAndroidKeyStoreKey());
+ SecretKey rawKey = generateKey();
+
+ WrappedKey wrappedKey = WrappedKey.fromSecretKey(wrappingKey, rawKey, NON_NULL_METADATA);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(
@@ -84,27 +109,47 @@
GENERATION_ID, generateAndroidKeyStoreKey());
SecretKey rawKey = generateKey();
- WrappedKey wrappedKey = WrappedKey.fromSecretKey(wrappingKey, rawKey);
+ WrappedKey wrappedKey = WrappedKey.fromSecretKey(wrappingKey, rawKey, NULL_METADATA);
assertEquals(GENERATION_ID, wrappedKey.getPlatformKeyGenerationId());
}
@Test
- public void decryptWrappedKeys_decryptsWrappedKeys() throws Exception {
+ public void decryptWrappedKeys_decryptsWrappedKeys_nullMetadata() throws Exception {
String alias = "karlin";
AndroidKeyStoreSecretKey platformKey = generateAndroidKeyStoreKey();
SecretKey appKey = generateKey();
WrappedKey wrappedKey = WrappedKey.fromSecretKey(
- new PlatformEncryptionKey(GENERATION_ID, platformKey), appKey);
+ new PlatformEncryptionKey(GENERATION_ID, platformKey), appKey, NULL_METADATA);
HashMap<String, WrappedKey> keysByAlias = new HashMap<>();
keysByAlias.put(alias, wrappedKey);
- Map<String, SecretKey> unwrappedKeys = WrappedKey.unwrapKeys(
+ Map<String, Pair<SecretKey, byte[]>> unwrappedKeys = WrappedKey.unwrapKeys(
new PlatformDecryptionKey(GENERATION_ID, platformKey), keysByAlias);
assertEquals(1, unwrappedKeys.size());
assertTrue(unwrappedKeys.containsKey(alias));
- assertArrayEquals(appKey.getEncoded(), unwrappedKeys.get(alias).getEncoded());
+ assertArrayEquals(appKey.getEncoded(), unwrappedKeys.get(alias).first.getEncoded());
+ assertArrayEquals(null, unwrappedKeys.get(alias).second);
+ }
+
+ @Test
+ public void decryptWrappedKeys_decryptsWrappedKeys_nonNullMetadata() throws Exception {
+ String alias = "karlin";
+ AndroidKeyStoreSecretKey platformKey = generateAndroidKeyStoreKey();
+ SecretKey appKey = generateKey();
+ WrappedKey wrappedKey = WrappedKey.fromSecretKey(
+ new PlatformEncryptionKey(GENERATION_ID, platformKey), appKey, NON_NULL_METADATA);
+ HashMap<String, WrappedKey> keysByAlias = new HashMap<>();
+ keysByAlias.put(alias, wrappedKey);
+
+ Map<String, Pair<SecretKey, byte[]>> unwrappedKeys = WrappedKey.unwrapKeys(
+ new PlatformDecryptionKey(GENERATION_ID, platformKey), keysByAlias);
+
+ assertEquals(1, unwrappedKeys.size());
+ assertTrue(unwrappedKeys.containsKey(alias));
+ assertArrayEquals(appKey.getEncoded(), unwrappedKeys.get(alias).first.getEncoded());
+ assertArrayEquals(NON_NULL_METADATA, unwrappedKeys.get(alias).second);
}
@Test
@@ -113,11 +158,11 @@
AndroidKeyStoreSecretKey platformKey = generateAndroidKeyStoreKey();
SecretKey appKey = generateKey();
WrappedKey wrappedKey = WrappedKey.fromSecretKey(
- new PlatformEncryptionKey(GENERATION_ID, platformKey), appKey);
+ new PlatformEncryptionKey(GENERATION_ID, platformKey), appKey, NULL_METADATA);
HashMap<String, WrappedKey> keysByAlias = new HashMap<>();
keysByAlias.put(alias, wrappedKey);
- Map<String, SecretKey> unwrappedKeys = WrappedKey.unwrapKeys(
+ Map<String, Pair<SecretKey, byte[]>> unwrappedKeys = WrappedKey.unwrapKeys(
new PlatformDecryptionKey(GENERATION_ID, generateAndroidKeyStoreKey()),
keysByAlias);
@@ -128,7 +173,8 @@
public void decryptWrappedKeys_throwsIfPlatformKeyGenerationIdDoesNotMatch() throws Exception {
AndroidKeyStoreSecretKey platformKey = generateAndroidKeyStoreKey();
WrappedKey wrappedKey = WrappedKey.fromSecretKey(
- new PlatformEncryptionKey(GENERATION_ID, platformKey), generateKey());
+ new PlatformEncryptionKey(GENERATION_ID, platformKey), generateKey(),
+ /*metadata=*/ null);
HashMap<String, WrappedKey> keysByAlias = new HashMap<>();
keysByAlias.put("benji", wrappedKey);
@@ -156,19 +202,11 @@
KEY_ALGORITHM,
ANDROID_KEY_STORE_PROVIDER);
keyGenerator.init(new KeyGenParameterSpec.Builder(
- WRAPPING_KEY_ALIAS,
+ WRAPPED_KEY_ALIAS,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build());
return (AndroidKeyStoreSecretKey) keyGenerator.generateKey();
}
-
- private PlatformDecryptionKey generatePlatformDecryptionKey() throws Exception {
- return generatePlatformDecryptionKey(GENERATION_ID);
- }
-
- private PlatformDecryptionKey generatePlatformDecryptionKey(int generationId) throws Exception {
- return new PlatformDecryptionKey(generationId, generateAndroidKeyStoreKey());
- }
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java
index 7130b42..35215c3 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java
@@ -60,6 +60,7 @@
private static final String TEST_ROOT_ALIAS = "root_cert_alias";
private static final byte[] TEST_CERT_PATH = "test-cert-path".getBytes(UTF_8);
private static final long TEST_CERT_SERIAL = 1000L;
+ private static final byte[] TEST_KEY_METADATA = "test-key-metadata".getBytes(UTF_8);
private static final String SQL_CREATE_V2_TABLE_KEYS =
"CREATE TABLE " + KeysEntry.TABLE_NAME + "( "
@@ -120,14 +121,14 @@
@Test
public void onCreate() throws Exception {
mDatabaseHelper.onCreate(mDatabase);
- checkAllColumns();
+ checkAllColumns_latest();
}
@Test
public void onUpgrade_beforeV2() throws Exception {
mDatabaseHelper.onUpgrade(mDatabase, /*oldVersion=*/ 1,
RecoverableKeyStoreDbHelper.DATABASE_VERSION);
- checkAllColumns();
+ checkAllColumns_latest();
}
@Test
@@ -135,11 +136,11 @@
createV2Tables();
mDatabaseHelper.onUpgrade(mDatabase, /*oldVersion=*/ 2,
RecoverableKeyStoreDbHelper.DATABASE_VERSION);
- checkAllColumns();
+ checkAllColumns_latest();
}
@Test
- public void onUpgrade_v2_to_v3_to_v4() throws Exception {
+ public void onUpgrade_v2_to_v3_to_v4_to_latest() throws Exception {
createV2Tables();
assertThat(isRootOfTrustTableAvailable()).isFalse(); // V2 doesn't have the table;
@@ -148,9 +149,12 @@
assertThat(isRootOfTrustTableAvailable()).isFalse(); // V3 doesn't have the table;
- mDatabaseHelper.onUpgrade(mDatabase, /*oldVersion=*/ 3,
+ mDatabaseHelper.onUpgrade(mDatabase, /*oldVersion=*/ 3, /*newVersion=*/ 4);
+ checkAllColumns_v4();
+
+ mDatabaseHelper.onUpgrade(mDatabase, /*oldVersion=*/ 4,
RecoverableKeyStoreDbHelper.DATABASE_VERSION);
- checkAllColumns();
+ checkAllColumns_latest();
}
private boolean isRootOfTrustTableAvailable() {
@@ -160,11 +164,11 @@
values.put(RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS, TEST_ROOT_ALIAS);
values.put(RootOfTrustEntry.COLUMN_NAME_CERT_PATH, TEST_CERT_PATH);
values.put(RootOfTrustEntry.COLUMN_NAME_CERT_SERIAL, TEST_CERT_SERIAL);
- return mDatabase.insert(RootOfTrustEntry.TABLE_NAME, /*nullColumnHack=*/ null, values)
+ return mDatabase.replace(RootOfTrustEntry.TABLE_NAME, /*nullColumnHack=*/ null, values)
> -1;
}
- private void checkAllColumns() throws Exception {
+ private void checkAllColumns_v4() throws Exception {
// Check the table containing encrypted application keys
ContentValues values = new ContentValues();
values.put(KeysEntry.COLUMN_NAME_USER_ID, TEST_USER_ID);
@@ -175,7 +179,7 @@
values.put(KeysEntry.COLUMN_NAME_GENERATION_ID, TEST_GENERATION_ID);
values.put(KeysEntry.COLUMN_NAME_LAST_SYNCED_AT, TEST_LAST_SYNCED_AT);
values.put(KeysEntry.COLUMN_NAME_RECOVERY_STATUS, TEST_RECOVERY_STATUS);
- assertThat(mDatabase.insert(KeysEntry.TABLE_NAME, /*nullColumnHack=*/ null, values))
+ assertThat(mDatabase.replace(KeysEntry.TABLE_NAME, /*nullColumnHack=*/ null, values))
.isGreaterThan(-1L);
// Check the table about user metadata
@@ -183,7 +187,8 @@
values.put(UserMetadataEntry.COLUMN_NAME_USER_ID, TEST_USER_ID);
values.put(UserMetadataEntry.COLUMN_NAME_PLATFORM_KEY_GENERATION_ID,
TEST_PLATFORM_KEY_GENERATION_ID);
- assertThat(mDatabase.insert(UserMetadataEntry.TABLE_NAME, /*nullColumnHack=*/ null, values))
+ assertThat(
+ mDatabase.replace(UserMetadataEntry.TABLE_NAME, /*nullColumnHack=*/ null, values))
.isGreaterThan(-1L);
// Check the table about recovery service metadata
@@ -202,11 +207,32 @@
values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_PATH, TEST_CERT_PATH);
values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_SERIAL, TEST_CERT_SERIAL);
assertThat(
- mDatabase.insert(RecoveryServiceMetadataEntry.TABLE_NAME, /*nullColumnHack=*/ null,
+ mDatabase.replace(RecoveryServiceMetadataEntry.TABLE_NAME, /*nullColumnHack=*/ null,
values))
.isGreaterThan(-1L);
// Check the table about recovery service and root of trust data introduced in V4
assertThat(isRootOfTrustTableAvailable()).isTrue();
}
+
+ private void checkAllColumns_latest() throws Exception {
+ // Check all columns of the previous version first.
+ checkAllColumns_v4();
+
+ ContentValues values = new ContentValues();
+ values.put(KeysEntry.COLUMN_NAME_USER_ID, TEST_USER_ID);
+ values.put(KeysEntry.COLUMN_NAME_UID, TEST_UID);
+ values.put(KeysEntry.COLUMN_NAME_ALIAS, TEST_ALIAS);
+ values.put(KeysEntry.COLUMN_NAME_NONCE, TEST_NONCE);
+ values.put(KeysEntry.COLUMN_NAME_WRAPPED_KEY, TEST_WRAPPED_KEY);
+ values.put(KeysEntry.COLUMN_NAME_GENERATION_ID, TEST_GENERATION_ID);
+ values.put(KeysEntry.COLUMN_NAME_LAST_SYNCED_AT, TEST_LAST_SYNCED_AT);
+ values.put(KeysEntry.COLUMN_NAME_RECOVERY_STATUS, TEST_RECOVERY_STATUS);
+
+ // This column is added when upgrading from v4 to v5
+ values.put(KeysEntry.COLUMN_NAME_KEY_METADATA, TEST_KEY_METADATA);
+
+ assertThat(mDatabase.replace(KeysEntry.TABLE_NAME, /*nullColumnHack=*/ null, values))
+ .isGreaterThan(-1L);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
index 6a26f8c..7de9ffc 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
@@ -80,25 +80,33 @@
public void insertKey_replacesOldKey() {
int userId = 12;
int uid = 10009;
- String alias = "test";
- WrappedKey oldWrappedKey = new WrappedKey(
- getUtf8Bytes("nonce1"),
- getUtf8Bytes("keymaterial1"),
- /*platformKeyGenerationId=*/ 1);
- mRecoverableKeyStoreDb.insertKey(
- userId, uid, alias, oldWrappedKey);
- byte[] nonce = getUtf8Bytes("nonce2");
- byte[] keyMaterial = getUtf8Bytes("keymaterial2");
- WrappedKey newWrappedKey = new WrappedKey(
- nonce, keyMaterial, /*platformKeyGenerationId=*/2);
+ String alias = "test-alias";
- mRecoverableKeyStoreDb.insertKey(
- userId, uid, alias, newWrappedKey);
+ byte[] nonce = getUtf8Bytes("nonce1");
+ byte[] keyMaterial = getUtf8Bytes("keymaterial1");
+ byte[] keyMetadata = null;
+ int generationId = 1;
+ WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, keyMetadata, generationId);
+ mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey);
WrappedKey retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
assertArrayEquals(nonce, retrievedKey.getNonce());
assertArrayEquals(keyMaterial, retrievedKey.getKeyMaterial());
- assertEquals(2, retrievedKey.getPlatformKeyGenerationId());
+ assertArrayEquals(keyMetadata, retrievedKey.getKeyMetadata());
+ assertEquals(generationId, retrievedKey.getPlatformKeyGenerationId());
+
+ nonce = getUtf8Bytes("nonce2");
+ keyMaterial = getUtf8Bytes("keymaterial2");
+ keyMetadata = getUtf8Bytes("keymetadata2");
+ generationId = 2;
+ wrappedKey = new WrappedKey(nonce, keyMaterial, keyMetadata, generationId);
+ mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey);
+
+ retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
+ assertArrayEquals(nonce, retrievedKey.getNonce());
+ assertArrayEquals(keyMaterial, retrievedKey.getKeyMaterial());
+ assertArrayEquals(keyMetadata, retrievedKey.getKeyMetadata());
+ assertEquals(generationId, retrievedKey.getPlatformKeyGenerationId());
}
@Test
@@ -108,10 +116,12 @@
WrappedKey key1 = new WrappedKey(
getUtf8Bytes("nonce1"),
getUtf8Bytes("key1"),
+ /*metadata=*/ null,
/*platformKeyGenerationId=*/ 1);
WrappedKey key2 = new WrappedKey(
getUtf8Bytes("nonce2"),
getUtf8Bytes("key2"),
+ /*metadata=*/ null,
/*platformKeyGenerationId=*/ 1);
mRecoverableKeyStoreDb.insertKey(userId, /*uid=*/ 1, alias, key1);
@@ -133,6 +143,7 @@
WrappedKey key = new WrappedKey(
getUtf8Bytes("nonce1"),
getUtf8Bytes("key1"),
+ /*metadata=*/ null,
/*platformKeyGenerationId=*/ 1);
mRecoverableKeyStoreDb.insertKey(userId, uid, alias, key);
@@ -158,13 +169,16 @@
String alias = "test";
byte[] nonce = getUtf8Bytes("nonce");
byte[] keyMaterial = getUtf8Bytes("keymaterial");
- WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, generationId, 120);
+ byte[] keyMetadata = getUtf8Bytes("keymetametametadata");
+
+ WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, keyMetadata, generationId, 120);
mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey);
WrappedKey retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
assertArrayEquals(nonce, retrievedKey.getNonce());
assertArrayEquals(keyMaterial, retrievedKey.getKeyMaterial());
+ assertArrayEquals(keyMetadata, retrievedKey.getKeyMetadata());
assertEquals(generationId, retrievedKey.getPlatformKeyGenerationId());
assertEquals(status,retrievedKey.getRecoveryStatus());
}
@@ -174,20 +188,37 @@
int userId = 12;
int uid = 1009;
int generationId = 6;
- String alias = "test";
- byte[] nonce = getUtf8Bytes("nonce");
- byte[] keyMaterial = getUtf8Bytes("keymaterial");
- WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, generationId);
- mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey);
+
+ String alias1 = "alias1";
+ byte[] nonce1 = getUtf8Bytes("nonce1");
+ byte[] keyMaterial1 = getUtf8Bytes("keymaterial1");
+ byte[] keyMetadata1 = getUtf8Bytes("keyallmetadata1");
+ WrappedKey wrappedKey1 = new WrappedKey(nonce1, keyMaterial1, keyMetadata1, generationId);
+ mRecoverableKeyStoreDb.insertKey(userId, uid, alias1, wrappedKey1);
+
+ String alias2 = "alias2";
+ byte[] nonce2 = getUtf8Bytes("nonce2");
+ byte[] keyMaterial2 = getUtf8Bytes("keymaterial2");
+ byte[] keyMetadata2 = null;
+ WrappedKey wrappedKey2 = new WrappedKey(nonce2, keyMaterial2, keyMetadata2, generationId);
+ mRecoverableKeyStoreDb.insertKey(userId, uid, alias2, wrappedKey2);
Map<String, WrappedKey> keys = mRecoverableKeyStoreDb.getAllKeys(userId, uid, generationId);
+ assertEquals(2, keys.size());
- assertEquals(1, keys.size());
- assertTrue(keys.containsKey(alias));
- WrappedKey retrievedKey = keys.get(alias);
- assertArrayEquals(nonce, retrievedKey.getNonce());
- assertArrayEquals(keyMaterial, retrievedKey.getKeyMaterial());
- assertEquals(generationId, retrievedKey.getPlatformKeyGenerationId());
+ assertTrue(keys.containsKey(alias1));
+ WrappedKey retrievedKey1 = keys.get(alias1);
+ assertArrayEquals(nonce1, retrievedKey1.getNonce());
+ assertArrayEquals(keyMaterial1, retrievedKey1.getKeyMaterial());
+ assertArrayEquals(keyMetadata1, retrievedKey1.getKeyMetadata());
+ assertEquals(generationId, retrievedKey1.getPlatformKeyGenerationId());
+
+ assertTrue(keys.containsKey(alias2));
+ WrappedKey retrievedKey2 = keys.get(alias2);
+ assertArrayEquals(nonce2, retrievedKey2.getNonce());
+ assertArrayEquals(keyMaterial2, retrievedKey2.getKeyMaterial());
+ assertArrayEquals(keyMetadata2, retrievedKey2.getKeyMetadata());
+ assertEquals(generationId, retrievedKey2.getPlatformKeyGenerationId());
}
@Test
@@ -197,6 +228,7 @@
WrappedKey wrappedKey = new WrappedKey(
getUtf8Bytes("nonce"),
getUtf8Bytes("keymaterial"),
+ /*metadata=*/ null,
/*platformKeyGenerationId=*/ 5);
mRecoverableKeyStoreDb.insertKey(
userId, uid, /*alias=*/ "test", wrappedKey);
@@ -212,7 +244,8 @@
int generationId = 12;
int uid = 10009;
WrappedKey wrappedKey = new WrappedKey(
- getUtf8Bytes("nonce"), getUtf8Bytes("keymaterial"), generationId);
+ getUtf8Bytes("nonce"), getUtf8Bytes("keymaterial"), /*metadata=*/ null,
+ generationId);
mRecoverableKeyStoreDb.insertKey(
/*userId=*/ 1, uid, /*alias=*/ "test", wrappedKey);
@@ -255,7 +288,10 @@
String alias = "test";
byte[] nonce = getUtf8Bytes("nonce");
byte[] keyMaterial = getUtf8Bytes("keymaterial");
- WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, generationId, status);
+ byte[] keyMetadata = null;
+
+ WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, keyMetadata, generationId,
+ status);
mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey);
WrappedKey retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
@@ -279,12 +315,16 @@
String alias3 = "test3";
byte[] nonce = getUtf8Bytes("nonce");
byte[] keyMaterial = getUtf8Bytes("keymaterial");
+ byte[] keyMetadata = null;
- WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, generationId, status);
+ WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, keyMetadata, generationId,
+ status);
mRecoverableKeyStoreDb.insertKey(userId, uid, alias2, wrappedKey);
- WrappedKey wrappedKey2 = new WrappedKey(nonce, keyMaterial, generationId, status);
- mRecoverableKeyStoreDb.insertKey(userId, uid, alias3, wrappedKey);
- WrappedKey wrappedKeyWithDefaultStatus = new WrappedKey(nonce, keyMaterial, generationId);
+ WrappedKey wrappedKey2 = new WrappedKey(nonce, keyMaterial, keyMetadata, generationId,
+ status);
+ mRecoverableKeyStoreDb.insertKey(userId, uid, alias3, wrappedKey2);
+ WrappedKey wrappedKeyWithDefaultStatus = new WrappedKey(nonce, keyMaterial, keyMetadata,
+ generationId);
mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKeyWithDefaultStatus);
Map<String, Integer> statuses = mRecoverableKeyStoreDb.getStatusForAllKeys(uid);
@@ -333,7 +373,10 @@
String alias = "test";
byte[] nonce = getUtf8Bytes("nonce");
byte[] keyMaterial = getUtf8Bytes("keymaterial");
- WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, generationId, status);
+ byte[] keyMetadata = null;
+
+ WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, keyMetadata, generationId,
+ status);
mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey);
WrappedKey retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
@@ -357,7 +400,10 @@
String alias = "test";
byte[] nonce = getUtf8Bytes("nonce");
byte[] keyMaterial = getUtf8Bytes("keymaterial");
- WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, generationId, status);
+ byte[] keyMetadata = null;
+
+ WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, keyMetadata, generationId,
+ status);
mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey);
WrappedKey retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
diff --git a/services/tests/servicestests/src/com/android/server/pm/LauncherAppsServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/LauncherAppsServiceTest.java
deleted file mode 100644
index d7dc58d..0000000
--- a/services/tests/servicestests/src/com/android/server/pm/LauncherAppsServiceTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2019 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 com.android.server.pm;
-
-import static org.junit.Assert.assertEquals;
-
-import android.content.pm.PackageParser;
-import android.content.pm.Signature;
-import android.content.pm.SigningInfo;
-import android.platform.test.annotations.Presubmit;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.junit.MockitoJUnitRunner;
-
-@Presubmit
-@RunWith(MockitoJUnitRunner.class)
-public class LauncherAppsServiceTest {
-
- private static final Signature SIGNATURE_1 = new Signature(new byte[]{0x00, 0x01, 0x02, 0x03});
- private static final Signature SIGNATURE_2 = new Signature(new byte[]{0x04, 0x05, 0x06, 0x07});
- private static final Signature SIGNATURE_3 = new Signature(new byte[]{0x08, 0x09, 0x10, 0x11});
-
- @Test
- public void testComputePackageCertDigest() {
- String digest = LauncherAppsService.LauncherAppsImpl.computePackageCertDigest(SIGNATURE_1);
- assertEquals("A02A05B025B928C039CF1AE7E8EE04E7C190C0DB", digest);
- }
-
- @Test
- public void testGetLatestSignaturesWithSingleCert() {
- SigningInfo signingInfo = new SigningInfo(
- new PackageParser.SigningDetails(
- new Signature[]{SIGNATURE_1},
- PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
- null,
- null));
- Signature[] signatures = LauncherAppsService.LauncherAppsImpl.getLatestSignatures(
- signingInfo);
- assertEquals(1, signatures.length);
- assertEquals(SIGNATURE_1, signatures[0]);
- }
-
- @Test
- public void testGetLatestSignaturesWithMultiCert() {
- SigningInfo signingInfo = new SigningInfo(
- new PackageParser.SigningDetails(
- new Signature[]{SIGNATURE_1, SIGNATURE_2},
- PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
- null,
- null));
- Signature[] signatures = LauncherAppsService.LauncherAppsImpl.getLatestSignatures(
- signingInfo);
- assertEquals(2, signatures.length);
- assertEquals(SIGNATURE_1, signatures[0]);
- assertEquals(SIGNATURE_2, signatures[1]);
- }
-
- @Test
- public void testGetLatestSignaturesWithCertHistory() {
- SigningInfo signingInfo = new SigningInfo(
- new PackageParser.SigningDetails(
- new Signature[]{SIGNATURE_1},
- PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
- null,
- new Signature[]{SIGNATURE_2, SIGNATURE_3}));
- Signature[] signatures = LauncherAppsService.LauncherAppsImpl.getLatestSignatures(
- signingInfo);
- assertEquals(1, signatures.length);
- assertEquals(SIGNATURE_2, signatures[0]);
- }
-
-}
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index 17516bc2..6e8d038 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -87,7 +87,7 @@
public static final int CMD_NET_STAT_POLL = BASE + 40;
public static final int EVENT_DATA_RAT_CHANGED = BASE + 41;
public static final int CMD_CLEAR_PROVISIONING_SPINNER = BASE + 42;
- public static final int EVENT_REDIRECTION_DETECTED = BASE + 44;
+ public static final int EVENT_NETWORK_STATUS_CHANGED = BASE + 44;
public static final int EVENT_PCO_DATA_RECEIVED = BASE + 45;
public static final int EVENT_DATA_ENABLED_CHANGED = BASE + 46;
public static final int EVENT_DATA_RECONNECT = BASE + 47;
diff --git a/tests/net/Android.mk b/tests/net/Android.mk
index f6f35fd..6850673 100644
--- a/tests/net/Android.mk
+++ b/tests/net/Android.mk
@@ -54,6 +54,7 @@
libnativehelper \
libpackagelistparser \
libpcre2 \
+ libprocessgroup \
libselinux \
libui \
libutils \
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index d8f9618..a844cfee 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -535,7 +535,10 @@
IpSecTransformResponse createTransformResp =
mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
- ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
+
+ Socket socket = new Socket();
+ socket.bind(null);
+ ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
int resourceId = createTransformResp.resourceId;
mIpSecService.applyTransportModeTransform(pfd, IpSecManager.DIRECTION_OUT, resourceId);
@@ -552,7 +555,9 @@
@Test
public void testRemoveTransportModeTransform() throws Exception {
- ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
+ Socket socket = new Socket();
+ socket.bind(null);
+ ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
mIpSecService.removeTransportModeTransforms(pfd);
verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd);
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java
index 724446e..5be7c7b 100644
--- a/tests/net/java/com/android/server/IpSecServiceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceTest.java
@@ -422,7 +422,9 @@
@Test
public void testRemoveTransportModeTransform() throws Exception {
- ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
+ Socket socket = new Socket();
+ socket.bind(null);
+ ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
mIpSecService.removeTransportModeTransforms(pfd);
verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd);
diff --git a/tools/processors/view_inspector/Android.bp b/tools/processors/view_inspector/Android.bp
index ca6b3c4..9b5df56 100644
--- a/tools/processors/view_inspector/Android.bp
+++ b/tools/processors/view_inspector/Android.bp
@@ -5,7 +5,7 @@
java_resource_dirs: ["src/resources"],
static_libs: [
- "javapoet",
+ "javapoet",
],
use_tools_jar: true,
@@ -18,9 +18,9 @@
java_resource_dirs: ["test/resources"],
static_libs: [
- "guava",
"junit",
- "view-inspector-annotation-processor",
+ "guava",
+ "view-inspector-annotation-processor"
],
test_suites: ["general-tests"],
diff --git a/tools/processors/view_inspector/TEST_MAPPING b/tools/processors/view_inspector/TEST_MAPPING
index a91b5b4..b4c9cab 100644
--- a/tools/processors/view_inspector/TEST_MAPPING
+++ b/tools/processors/view_inspector/TEST_MAPPING
@@ -2,6 +2,8 @@
"presubmit": [
{
"name": "view-inspector-annotation-processor-test"
+ }, {
+ "name": "CtsViewInspectorAnnotationProcessorTestCases"
}
]
}
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java
index f157949..fc4cd01 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 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.
@@ -24,6 +24,7 @@
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
@@ -78,40 +79,126 @@
}
/**
- * Extract a string-valued property from an {@link AnnotationMirror}.
+ * Determine if an annotation with the supplied qualified name is present on the element.
*
- * @param propertyName The name of the requested property
- * @param annotationMirror The mirror to search for the property
- * @return The String value of the annotation or null
+ * @param element The element to check for the presence of an annotation
+ * @param annotationQualifiedName The name of the annotation to check for
+ * @return True if the annotation is present, false otherwise
*/
- Optional<String> stringProperty(String propertyName, AnnotationMirror annotationMirror) {
- final AnnotationValue value = valueByName(propertyName, annotationMirror);
- if (value != null) {
- return Optional.of((String) value.getValue());
- } else {
- return Optional.empty();
+ boolean hasAnnotation(Element element, String annotationQualifiedName) {
+ final TypeElement namedElement = mElementUtils.getTypeElement(annotationQualifiedName);
+
+ if (namedElement != null) {
+ final TypeMirror annotationType = namedElement.asType();
+
+ for (AnnotationMirror annotation : element.getAnnotationMirrors()) {
+ if (mTypeUtils.isSubtype(annotation.getAnnotationType(), annotationType)) {
+ return true;
+ }
+ }
}
+
+ return false;
}
+ /**
+ * Get the typed value of an annotation property by name.
+ *
+ * The returned optional will be empty if the value was left at the default, or if the value
+ * of the property is null.
+ *
+ * @param propertyName The name of the property to search for
+ * @param valueClass The expected class of the property value
+ * @param element The element the annotation is on, used for exceptions
+ * @param annotationMirror An annotation mirror to search for the property
+ * @param <T> The type of the value
+ * @return An optional containing the typed value of the named property
+ */
+ <T> Optional<T> typedValueByName(
+ String propertyName,
+ Class<T> valueClass,
+ Element element,
+ AnnotationMirror annotationMirror) {
+ return valueByName(propertyName, annotationMirror).map(annotationValue -> {
+ final Object value = annotationValue.getValue();
+
+ if (value == null) {
+ throw new ProcessingException(
+ String.format(
+ "Unexpected null value for annotation property \"%s\".",
+ propertyName),
+ element,
+ annotationMirror,
+ annotationValue);
+ }
+
+ if (valueClass.isAssignableFrom(value.getClass())) {
+ return valueClass.cast(value);
+ } else {
+ throw new ProcessingException(
+ String.format(
+ "Expected annotation property \"%s\" to have type %s, but got %s.",
+ propertyName,
+ valueClass.getCanonicalName(),
+ value.getClass().getCanonicalName()),
+ element,
+ annotationMirror,
+ annotationValue);
+ }
+ });
+ }
+
+ /**
+ * Get the untyped value of an annotation property by name.
+ *
+ * The returned optional will be empty if the value was left at the default, or if the value
+ * of the property is null.
+ *
+ * @param propertyName The name of the property to search for
+ * @param element The element the annotation is on, used for exceptions
+ * @param annotationMirror An annotation mirror to search for the property
+ * @return An optional containing the untyped value of the named property
+ * @see AnnotationValue#getValue()
+ */
+ Optional<Object> untypedValueByName(
+ String propertyName,
+ Element element,
+ AnnotationMirror annotationMirror) {
+ return valueByName(propertyName, annotationMirror).map(annotationValue -> {
+ final Object value = annotationValue.getValue();
+
+ if (value == null) {
+ throw new ProcessingException(
+ String.format(
+ "Unexpected null value for annotation property \"%s\".",
+ propertyName),
+ element,
+ annotationMirror,
+ annotationValue);
+ }
+
+ return value;
+ });
+ }
/**
* Extract a {@link AnnotationValue} from a mirror by string property name.
*
* @param propertyName The name of the property requested property
- * @param annotationMirror
- * @return
+ * @param annotationMirror The mirror to search for the property
+ * @return The value of the property
*/
- AnnotationValue valueByName(String propertyName, AnnotationMirror annotationMirror) {
+ Optional<AnnotationValue> valueByName(String propertyName, AnnotationMirror annotationMirror) {
final Map<? extends ExecutableElement, ? extends AnnotationValue> valueMap =
annotationMirror.getElementValues();
for (ExecutableElement method : valueMap.keySet()) {
if (method.getSimpleName().contentEquals(propertyName)) {
- return valueMap.get(method);
+ return Optional.ofNullable(valueMap.get(method));
}
}
- return null;
+ // Property not explicitly defined, use default value.
+ return Optional.empty();
}
-
}
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java
index 579745d..f1ebb87 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 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.
@@ -21,6 +21,7 @@
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
+import java.util.Objects;
import java.util.Optional;
/**
@@ -70,7 +71,7 @@
* @return The property or an empty optional
*/
public Optional<Property> getProperty(String name) {
- return Optional.of(mPropertyMap.get(name));
+ return Optional.ofNullable(mPropertyMap.get(name));
}
/**
@@ -87,13 +88,15 @@
*/
public static final class Property {
private final String mName;
- private String mGetter;
- private Type mType;
+ private final String mGetter;
+ private final Type mType;
private boolean mAttributeIdInferrableFromR = true;
private int mAttributeId = 0;
- public Property(String name) {
- mName = name;
+ public Property(String name, String getter, Type type) {
+ mName = Objects.requireNonNull(name, "Name must not be null");
+ mGetter = Objects.requireNonNull(getter, "Getter must not be null");
+ mType = Objects.requireNonNull(type, "Type must not be null");
}
public int getAttributeId() {
@@ -126,18 +129,10 @@
return mGetter;
}
- public void setGetter(String getter) {
- mGetter = getter;
- }
-
public Type getType() {
return mType;
}
- public void setType(Type type) {
- mType = type;
- }
-
public enum Type {
/** Primitive or boxed {@code boolean} */
BOOLEAN,
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableNodeNameProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableNodeNameProcessor.java
index a186a82..46819b2 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableNodeNameProcessor.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableNodeNameProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 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.
@@ -23,7 +23,7 @@
import javax.lang.model.element.Element;
/**
- * Process {InspectableNodeName} annotations
+ * Process {@code @InspectableNodeName} annotations.
*
* @see android.view.inspector.InspectableNodeName
*/
@@ -58,7 +58,8 @@
try {
final AnnotationMirror mirror =
mAnnotationUtils.exactlyOneMirror(mQualifiedName, element);
- final Optional<String> nodeName = mAnnotationUtils.stringProperty("value", mirror);
+ final Optional<String> nodeName = mAnnotationUtils
+ .typedValueByName("value", String.class, element, mirror);
if (!model.getNodeName().isPresent() || model.getNodeName().equals(nodeName)) {
model.setNodeName(nodeName);
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java
new file mode 100644
index 0000000..f666be7
--- /dev/null
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java
@@ -0,0 +1,408 @@
+/*
+ * Copyright 2019 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.processor.view.inspector;
+
+import android.processor.view.inspector.InspectableClassModel.Property;
+
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.NoType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * Process {@code @InspectableProperty} annotations.
+ *
+ * @see android.view.inspector.InspectableProperty
+ */
+public final class InspectablePropertyProcessor implements ModelProcessor {
+ private final String mQualifiedName;
+ private final ProcessingEnvironment mProcessingEnv;
+ private final AnnotationUtils mAnnotationUtils;
+
+ /**
+ * Regex that matches methods names of the form {@code #getValue()}.
+ */
+ private static final Pattern GETTER_GET_PREFIX = Pattern.compile("\\Aget[A-Z]");
+
+ /**
+ * Regex that matches method name of the form {@code #isPredicate()}.
+ */
+ private static final Pattern GETTER_IS_PREFIX = Pattern.compile("\\Ais[A-Z]");
+
+ /**
+ * Set of android and androidx annotation qualified names for colors packed into {@code int}.
+ *
+ * @see android.annotation.ColorInt
+ */
+ private static final String[] COLOR_INT_ANNOTATION_NAMES = {
+ "android.annotation.ColorInt",
+ "androidx.annotation.ColorInt"};
+
+ /**
+ * Set of android and androidx annotation qualified names for colors packed into {@code long}.
+ * @see android.annotation.ColorLong
+ */
+ private static final String[] COLOR_LONG_ANNOTATION_NAMES = {
+ "android.annotation.ColorLong",
+ "androidx.annotation.ColorLong"};
+
+ /**
+ * @param annotationQualifiedName The qualified name of the annotation to process
+ * @param processingEnv The processing environment from the parent processor
+ */
+ public InspectablePropertyProcessor(
+ String annotationQualifiedName,
+ ProcessingEnvironment processingEnv) {
+ mQualifiedName = annotationQualifiedName;
+ mProcessingEnv = processingEnv;
+ mAnnotationUtils = new AnnotationUtils(processingEnv);
+ }
+
+ @Override
+ public void process(Element element, InspectableClassModel model) {
+ try {
+ final AnnotationMirror annotation =
+ mAnnotationUtils.exactlyOneMirror(mQualifiedName, element);
+ final ExecutableElement getter = ensureGetter(element);
+ final Property property = buildProperty(getter, annotation);
+
+ model.getProperty(property.getName()).ifPresent(p -> {
+ throw new ProcessingException(
+ String.format(
+ "Property \"%s\" is already defined on #%s().",
+ p.getName(),
+ p.getGetter()),
+ getter,
+ annotation);
+ });
+
+ model.putProperty(property);
+ } catch (ProcessingException processingException) {
+ processingException.print(mProcessingEnv.getMessager());
+ }
+ }
+
+ /**
+ * Check that an element is shaped like a getter.
+ *
+ * @param element An element that hopefully represents a getter
+ * @throws ProcessingException if the element isn't a getter
+ * @return An {@link ExecutableElement} that represents a getter method.
+ */
+ private ExecutableElement ensureGetter(Element element) {
+ if (element.getKind() != ElementKind.METHOD) {
+ throw new ProcessingException(
+ String.format("Expected a method, got a %s", element.getKind()),
+ element);
+ }
+
+ final ExecutableElement method = (ExecutableElement) element;
+ final Set<Modifier> modifiers = method.getModifiers();
+
+ if (modifiers.contains(Modifier.PRIVATE)) {
+ throw new ProcessingException(
+ "Property getter methods must not be private.",
+ element);
+ }
+
+ if (modifiers.contains(Modifier.ABSTRACT)) {
+ throw new ProcessingException(
+ "Property getter methods must not be abstract.",
+ element);
+ }
+
+ if (modifiers.contains(Modifier.STATIC)) {
+ throw new ProcessingException(
+ "Property getter methods must not be static.",
+ element);
+ }
+
+ if (!method.getParameters().isEmpty()) {
+ throw new ProcessingException(
+ String.format(
+ "Expected a getter method to take no parameters, "
+ + "but got %d parameters.",
+ method.getParameters().size()),
+ element);
+ }
+
+ if (method.isVarArgs()) {
+ throw new ProcessingException(
+ "Expected a getter method to take no arguments, but got a var args method.",
+ element);
+ }
+
+ if (method.getReturnType() instanceof NoType) {
+ throw new ProcessingException(
+ "Expected a getter to have a return type, got void.",
+ element);
+ }
+
+ return method;
+ }
+
+ /**
+ * Build a {@link Property} from a getter and an inspectable property annotation.
+ *
+ * @param getter An element representing the getter to build from
+ * @param annotation A mirror of an inspectable property-shaped annotation
+ * @throws ProcessingException If the supplied data is invalid and a property cannot be modeled
+ * @return A property for the getter and annotation
+ */
+ private Property buildProperty(ExecutableElement getter, AnnotationMirror annotation) {
+ final String name = mAnnotationUtils
+ .typedValueByName("name", String.class, getter, annotation)
+ .orElseGet(() -> inferPropertyNameFromGetter(getter));
+
+ final Property property = new Property(
+ name,
+ getter.getSimpleName().toString(),
+ determinePropertyType(getter, annotation));
+
+ mAnnotationUtils
+ .typedValueByName("hasAttributeId", Boolean.class, getter, annotation)
+ .ifPresent(property::setAttributeIdInferrableFromR);
+
+ mAnnotationUtils
+ .typedValueByName("attributeId", Integer.class, getter, annotation)
+ .ifPresent(property::setAttributeId);
+
+ return property;
+ }
+
+ /**
+ * Determine the property type from the annotation, return type, or context clues.
+ *
+ * @param getter An element representing the getter to build from
+ * @param annotation A mirror of an inspectable property-shaped annotation
+ * @return The resolved property type
+ * @throws ProcessingException If the property type cannot be resolved
+ * @see android.view.inspector.InspectableProperty#valueType()
+ */
+ private Property.Type determinePropertyType(
+ ExecutableElement getter,
+ AnnotationMirror annotation) {
+
+ final String valueType = mAnnotationUtils
+ .untypedValueByName("valueType", getter, annotation)
+ .map(Object::toString)
+ .orElse("INFERRED");
+
+ final Property.Type returnType = convertReturnTypeToPropertyType(getter);
+
+ switch (valueType) {
+ case "INFERRED":
+ if (hasColorAnnotation(getter)) {
+ return Property.Type.COLOR;
+ } else {
+ return returnType;
+ }
+ case "NONE":
+ return returnType;
+ case "COLOR":
+ switch (returnType) {
+ case COLOR:
+ case INT:
+ case LONG:
+ return Property.Type.COLOR;
+ default:
+ throw new ProcessingException(
+ "Color must be a long, integer, or android.graphics.Color",
+ getter,
+ annotation);
+ }
+ case "GRAVITY":
+ if (returnType == Property.Type.INT) {
+ return Property.Type.GRAVITY;
+ } else {
+ throw new ProcessingException(
+ String.format("Gravity must be an integer, got %s", returnType),
+ getter,
+ annotation);
+ }
+ case "INT_ENUM":
+ case "INT_FLAG":
+ throw new ProcessingException("Not implemented", getter, annotation);
+ default:
+ throw new ProcessingException(
+ String.format("Unknown value type enumeration value: %s", valueType),
+ getter,
+ annotation);
+ }
+ }
+
+ /**
+ * Get a property type from the return type of a getter.
+ *
+ * @param getter The getter to extract the return type of
+ * @throws ProcessingException If the return type is not a primitive or an object
+ * @return The property type returned by the getter
+ */
+ private Property.Type convertReturnTypeToPropertyType(ExecutableElement getter) {
+ final TypeMirror returnType = getter.getReturnType();
+
+ switch (unboxType(returnType)) {
+ case BOOLEAN:
+ return Property.Type.BOOLEAN;
+ case BYTE:
+ return Property.Type.BYTE;
+ case CHAR:
+ return Property.Type.CHAR;
+ case DOUBLE:
+ return Property.Type.DOUBLE;
+ case FLOAT:
+ return Property.Type.FLOAT;
+ case INT:
+ return Property.Type.INT;
+ case LONG:
+ return Property.Type.LONG;
+ case SHORT:
+ return Property.Type.SHORT;
+ case DECLARED:
+ if (isColorType(returnType)) {
+ return Property.Type.COLOR;
+ } else {
+ return Property.Type.OBJECT;
+ }
+ default:
+ throw new ProcessingException(
+ String.format("Unsupported return type %s.", returnType),
+ getter);
+ }
+ }
+
+ /**
+ * Determine if a getter is annotated with color annotation matching its return type.
+ *
+ * Note that an {@code int} return value annotated with {@link android.annotation.ColorLong} is
+ * not considered to be annotated, nor is a {@code long} annotated with
+ * {@link android.annotation.ColorInt}.
+ *
+ * @param getter The getter to query
+ * @return True if the getter has a color annotation, false otherwise
+ *
+ */
+ private boolean hasColorAnnotation(ExecutableElement getter) {
+ switch (unboxType(getter.getReturnType())) {
+ case INT:
+ for (String name : COLOR_INT_ANNOTATION_NAMES) {
+ if (mAnnotationUtils.hasAnnotation(getter, name)) {
+ return true;
+ }
+ }
+ return false;
+ case LONG:
+ for (String name : COLOR_LONG_ANNOTATION_NAMES) {
+ if (mAnnotationUtils.hasAnnotation(getter, name)) {
+ return true;
+ }
+ }
+ return false;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Infer a property name from a getter method.
+ *
+ * If the method is prefixed with {@code get}, the prefix will be stripped, and the
+ * capitalization fixed. E.g.: {@code getSomeProperty} to {@code someProperty}.
+ *
+ * Additionally, if the method's return type is a boolean, an {@code is} prefix will also be
+ * stripped. E.g.: {@code isPropertyEnabled} to {@code propertyEnabled}.
+ *
+ * Failing that, this method will just return the full name of the getter.
+ *
+ * @param getter An element representing a getter
+ * @return A string property name
+ */
+ private String inferPropertyNameFromGetter(ExecutableElement getter) {
+ final String name = getter.getSimpleName().toString();
+
+ if (GETTER_GET_PREFIX.matcher(name).find()) {
+ return name.substring(3, 4).toLowerCase() + name.substring(4);
+ } else if (isBoolean(getter.getReturnType()) && GETTER_IS_PREFIX.matcher(name).find()) {
+ return name.substring(2, 3).toLowerCase() + name.substring(3);
+ } else {
+ return name;
+ }
+ }
+
+ /**
+ * Determine if a {@link TypeMirror} is a boxed or unboxed boolean.
+ *
+ * @param type The type mirror to check
+ * @return True if the type is a boolean
+ */
+ private boolean isBoolean(TypeMirror type) {
+ if (type.getKind() == TypeKind.DECLARED) {
+ return mProcessingEnv.getTypeUtils().unboxedType(type).getKind() == TypeKind.BOOLEAN;
+ } else {
+ return type.getKind() == TypeKind.BOOLEAN;
+ }
+ }
+
+ /**
+ * Unbox a type mirror if it represents a boxed type, otherwise pass it through.
+ *
+ * @param typeMirror The type mirror to unbox
+ * @return The same type mirror, or an unboxed primitive version
+ */
+ private TypeKind unboxType(TypeMirror typeMirror) {
+ final TypeKind typeKind = typeMirror.getKind();
+
+ if (typeKind.isPrimitive()) {
+ return typeKind;
+ } else if (typeKind == TypeKind.DECLARED) {
+ try {
+ return mProcessingEnv.getTypeUtils().unboxedType(typeMirror).getKind();
+ } catch (IllegalArgumentException e) {
+ return typeKind;
+ }
+ } else {
+ return typeKind;
+ }
+ }
+
+ /**
+ * Determine if a type mirror represents a subtype of {@link android.graphics.Color}.
+ *
+ * @param typeMirror The type mirror to test
+ * @return True if it represents a subclass of color, false otherwise
+ */
+ private boolean isColorType(TypeMirror typeMirror) {
+ final TypeElement colorType = mProcessingEnv
+ .getElementUtils()
+ .getTypeElement("android.graphics.Color");
+
+ if (colorType == null) {
+ return false;
+ } else {
+ return mProcessingEnv.getTypeUtils().isSubtype(typeMirror, colorType.asType());
+ }
+ }
+}
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java
index 8b2cc84..dd4d8f5 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 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.
@@ -51,12 +51,6 @@
private static final ClassName R_CLASS_NAME = ClassName.get("android", "R");
/**
- * The class name of {@link android.content.res.ResourceId}.
- */
- private static final ClassName RESOURCE_ID_CLASS_NAME = ClassName.get(
- "android.content.res", "ResourceId");
-
- /**
* The class name of {@link android.view.inspector.InspectionCompanion}.
*/
private static final ClassName INSPECTION_COMPANION = ClassName.get(
@@ -91,11 +85,11 @@
private static final String GENERATED_CLASS_SUFFIX = "$$InspectionCompanion";
/**
- * The null resource ID.
+ * The null resource ID, copied to avoid a host dependency on platform code.
*
* @see android.content.res.Resources#ID_NULL
*/
- private static final int NO_ID = 0;
+ private static final int ID_NULL = 0;
/**
* @param filer A filer to write the generated source to
@@ -289,8 +283,8 @@
if (property.isAttributeIdInferrableFromR()) {
builder.add("$T.attr.$L", R_CLASS_NAME, property.getName());
} else {
- if (property.getAttributeId() == NO_ID) {
- builder.add("$T.ID_NULL", RESOURCE_ID_CLASS_NAME);
+ if (property.getAttributeId() == ID_NULL) {
+ builder.add("$L", ID_NULL);
} else {
builder.add("$L", String.format("0x%08x", property.getAttributeId()));
}
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/ModelProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/ModelProcessor.java
index 3ffcff8..6f52260 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/ModelProcessor.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/ModelProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 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.
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java
index e531b67..455f5b0 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 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.
@@ -46,11 +46,14 @@
* @see android.view.inspector.InspectableProperty
*/
@SupportedAnnotationTypes({
- PlatformInspectableProcessor.NODE_NAME_QUALIFIED_NAME
+ PlatformInspectableProcessor.NODE_NAME_QUALIFIED_NAME,
+ PlatformInspectableProcessor.PROPERTY_QUALIFIED_NAME
})
public final class PlatformInspectableProcessor extends AbstractProcessor {
static final String NODE_NAME_QUALIFIED_NAME =
"android.view.inspector.InspectableNodeName";
+ static final String PROPERTY_QUALIFIED_NAME =
+ "android.view.inspector.InspectableProperty";
@Override
public SourceVersion getSupportedSourceVersion() {
@@ -68,6 +71,11 @@
new InspectableNodeNameProcessor(NODE_NAME_QUALIFIED_NAME, processingEnv),
modelMap);
+ } else if (annotation.getQualifiedName().contentEquals(PROPERTY_QUALIFIED_NAME)) {
+ runModelProcessor(
+ roundEnv.getElementsAnnotatedWith(annotation),
+ new InspectablePropertyProcessor(PROPERTY_QUALIFIED_NAME, processingEnv),
+ modelMap);
} else {
fail("Unexpected annotation type", annotation);
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/ProcessingException.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/ProcessingException.java
index 6360e0a..b4c6466 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/ProcessingException.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/ProcessingException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 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.
diff --git a/tools/processors/view_inspector/src/resources/META-INF/services/javax.annotation.processing.Processor b/tools/processors/view_inspector/src/resources/META-INF/services/javax.annotation.processing.Processor
index fa4f71f..79185cc 100644
--- a/tools/processors/view_inspector/src/resources/META-INF/services/javax.annotation.processing.Processor
+++ b/tools/processors/view_inspector/src/resources/META-INF/services/javax.annotation.processing.Processor
@@ -1 +1 @@
-android.processor.inspector.view.PlatformInspectableProcessor
+android.processor.view.inspector.PlatformInspectableProcessor
diff --git a/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java b/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java
index f639719..b0775dc 100644
--- a/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java
+++ b/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 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.
@@ -20,7 +20,7 @@
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
-import static junit.framework.TestCase.fail;
+import static junit.framework.Assert.fail;
import com.google.common.base.Charsets;
import com.google.common.io.Resources;
@@ -65,27 +65,28 @@
@Test
public void testSimpleProperties() {
- addProperty("boolean", Property.Type.BOOLEAN, "getBoolean");
- addProperty("byte", Property.Type.BYTE, "getByte");
- addProperty("char", Property.Type.CHAR, "getChar");
- addProperty("double", Property.Type.DOUBLE, "getDouble");
- addProperty("float", Property.Type.FLOAT, "getFloat");
- addProperty("int", Property.Type.INT, "getInt");
- addProperty("long", Property.Type.LONG, "getLong");
- addProperty("short", Property.Type.SHORT, "getShort");
+ addProperty("boolean", "getBoolean", Property.Type.BOOLEAN);
+ addProperty("byte", "getByte", Property.Type.BYTE);
+ addProperty("char", "getChar", Property.Type.CHAR);
+ addProperty("double", "getDouble", Property.Type.DOUBLE);
+ addProperty("float", "getFloat", Property.Type.FLOAT);
+ addProperty("int", "getInt", Property.Type.INT);
+ addProperty("long", "getLong", Property.Type.LONG);
+ addProperty("short", "getShort", Property.Type.SHORT);
- addProperty("object", Property.Type.OBJECT, "getObject");
- addProperty("color", Property.Type.COLOR, "getColor");
- addProperty("gravity", Property.Type.GRAVITY, "getGravity");
+ addProperty("object", "getObject", Property.Type.OBJECT);
+ addProperty("color", "getColor", Property.Type.COLOR);
+ addProperty("gravity", "getGravity", Property.Type.GRAVITY);
assertGeneratedFileEquals("SimpleProperties");
}
@Test
public void testNoAttributeId() {
- final Property property = new Property("noAttributeProperty");
- property.setType(Property.Type.INT);
- property.setGetter("getNoAttributeProperty");
+ final Property property = new Property(
+ "noAttributeProperty",
+ "getNoAttributeProperty",
+ Property.Type.INT);
property.setAttributeIdInferrableFromR(false);
mModel.putProperty(property);
@@ -94,19 +95,18 @@
@Test
public void testSuppliedAttributeId() {
- final Property property = new Property("suppliedAttributeProperty");
- property.setType(Property.Type.INT);
- property.setGetter("getSuppliedAttributeProperty");
+ final Property property = new Property(
+ "suppliedAttributeProperty",
+ "getSuppliedAttributeProperty",
+ Property.Type.INT);
property.setAttributeId(0xdecafbad);
mModel.putProperty(property);
assertGeneratedFileEquals("SuppliedAttributeId");
}
- private Property addProperty(String name, Property.Type type, String getter) {
- final Property property = new Property(name);
- property.setType(type);
- property.setGetter(getter);
+ private Property addProperty(String name, String getter, Property.Type type) {
+ final Property property = new Property(name, getter, type);
mModel.putProperty(property);
return property;
}
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt
index 277e840..23d0f78 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt
@@ -1,6 +1,5 @@
package com.android.inspectable;
-import android.content.res.ResourceId;
import android.view.inspector.InspectionCompanion;
import android.view.inspector.PropertyMapper;
import android.view.inspector.PropertyReader;
@@ -25,7 +24,7 @@
@Override
public void mapProperties(PropertyMapper propertyMapper) {
- mNoAttributePropertyId = propertyMapper.mapInt("noAttributeProperty", ResourceId.ID_NULL);
+ mNoAttributePropertyId = propertyMapper.mapInt("noAttributeProperty", 0);
mPropertiesMapped = true;
}
diff --git a/wifi/java/android/net/wifi/EasyConnectStatusCallback.java b/wifi/java/android/net/wifi/EasyConnectStatusCallback.java
index 3b4a6cd..b8c82fd 100644
--- a/wifi/java/android/net/wifi/EasyConnectStatusCallback.java
+++ b/wifi/java/android/net/wifi/EasyConnectStatusCallback.java
@@ -101,7 +101,7 @@
/**
* Easy Connect Failure event: General protocol failure.
*/
- public static final int EASY_CONNECT_EVENT_FAILURE = -7;
+ public static final int EASY_CONNECT_EVENT_FAILURE_GENERIC = -7;
/**
* Easy Connect Failure event: Feature or option is not supported.
@@ -123,7 +123,7 @@
EASY_CONNECT_EVENT_FAILURE_CONFIGURATION,
EASY_CONNECT_EVENT_FAILURE_BUSY,
EASY_CONNECT_EVENT_FAILURE_TIMEOUT,
- EASY_CONNECT_EVENT_FAILURE,
+ EASY_CONNECT_EVENT_FAILURE_GENERIC,
EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED,
EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK,
})
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 07f7cb3..46c4191 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -46,7 +46,7 @@
*/
interface IWifiManager
{
- int getSupportedFeatures();
+ long getSupportedFeatures();
WifiActivityEnergyInfo reportActivityInfo();
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 7cc89ac3..5742bd5 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -2083,7 +2083,7 @@
/** @hide */
public static final int WIFI_FEATURE_DPP = 0x80000000; // DPP (Easy-Connect)
- private int getSupportedFeatures() {
+ private long getSupportedFeatures() {
try {
return mService.getSupportedFeatures();
} catch (RemoteException e) {
@@ -2091,7 +2091,7 @@
}
}
- private boolean isFeatureSupported(int feature) {
+ private boolean isFeatureSupported(long feature) {
return (getSupportedFeatures() & feature) == feature;
}
/**
diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java
index 2c96c05..b3ac9f1 100644
--- a/wifi/java/com/android/server/wifi/BaseWifiService.java
+++ b/wifi/java/com/android/server/wifi/BaseWifiService.java
@@ -64,7 +64,7 @@
private static final String TAG = BaseWifiService.class.getSimpleName();
@Override
- public int getSupportedFeatures() {
+ public long getSupportedFeatures() {
throw new UnsupportedOperationException();
}