Merge "add API for getRegisteredPhoneAccounts" into main
diff --git a/core/api/current.txt b/core/api/current.txt
index 25765cf..84fbe1a 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -2167,11 +2167,6 @@
field public static final int notification_large_icon_width = 17104901; // 0x1050005
field public static final int system_app_widget_background_radius = 17104904; // 0x1050008
field public static final int system_app_widget_inner_radius = 17104905; // 0x1050009
- field public static final int system_corner_radius_large;
- field public static final int system_corner_radius_medium;
- field public static final int system_corner_radius_small;
- field public static final int system_corner_radius_xlarge;
- field public static final int system_corner_radius_xsmall;
field public static final int thumbnail_height = 17104897; // 0x1050001
field public static final int thumbnail_width = 17104898; // 0x1050002
}
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 24a5157..6255260 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -550,7 +550,7 @@
@UnsupportedAppUsage
protected @Nullable AssetManager createAssetManager(@NonNull final ResourcesKey key,
@Nullable ApkAssetsSupplier apkSupplier) {
- final AssetManager.Builder builder = new AssetManager.Builder();
+ final AssetManager.Builder builder = new AssetManager.Builder().setNoInit();
final ArrayList<ApkKey> apkKeys = extractApkKeys(key);
for (int i = 0, n = apkKeys.size(); i < n; i++) {
@@ -1555,7 +1555,7 @@
} else if(overlayPaths == null) {
return ArrayUtils.cloneOrNull(resourceDirs);
} else {
- final ArrayList<String> paths = new ArrayList<>();
+ final var paths = new ArrayList<String>(overlayPaths.length + resourceDirs.length);
for (final String path : overlayPaths) {
paths.add(path);
}
diff --git a/core/java/android/content/pm/ArchivedActivityInfo.java b/core/java/android/content/pm/ArchivedActivityInfo.java
index 166d265..9f65f589 100644
--- a/core/java/android/content/pm/ArchivedActivityInfo.java
+++ b/core/java/android/content/pm/ArchivedActivityInfo.java
@@ -24,6 +24,7 @@
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.util.Slog;
import com.android.internal.util.DataClass;
@@ -39,6 +40,7 @@
@DataClass(genBuilder = false, genConstructor = false, genSetters = true)
@FlaggedApi(Flags.FLAG_ARCHIVING)
public final class ArchivedActivityInfo {
+ private static final String TAG = "ArchivedActivityInfo";
/** The label for the activity. */
private @NonNull CharSequence mLabel;
/** The component name of this activity. */
@@ -138,7 +140,8 @@
bitmap.getByteCount())) {
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
return baos.toByteArray();
- } catch (IOException ignored) {
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to compress bitmap", e);
return null;
}
}
@@ -240,10 +243,10 @@
}
@DataClass.Generated(
- time = 1705615445673L,
+ time = 1708042076897L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/content/pm/ArchivedActivityInfo.java",
- inputSignatures = "private @android.annotation.NonNull java.lang.CharSequence mLabel\nprivate @android.annotation.NonNull android.content.ComponentName mComponentName\nprivate @android.annotation.Nullable android.graphics.drawable.Drawable mIcon\nprivate @android.annotation.Nullable android.graphics.drawable.Drawable mMonochromeIcon\n @android.annotation.NonNull android.content.pm.ArchivedActivityParcel getParcel()\npublic static android.graphics.Bitmap drawableToBitmap(android.graphics.drawable.Drawable)\npublic static android.graphics.Bitmap drawableToBitmap(android.graphics.drawable.Drawable,int)\npublic static byte[] bytesFromBitmap(android.graphics.Bitmap)\nprivate static android.graphics.drawable.Drawable drawableFromCompressedBitmap(byte[])\nclass ArchivedActivityInfo extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=false, genConstructor=false, genSetters=true)")
+ inputSignatures = "private static final java.lang.String TAG\nprivate @android.annotation.NonNull java.lang.CharSequence mLabel\nprivate @android.annotation.NonNull android.content.ComponentName mComponentName\nprivate @android.annotation.Nullable android.graphics.drawable.Drawable mIcon\nprivate @android.annotation.Nullable android.graphics.drawable.Drawable mMonochromeIcon\n @android.annotation.NonNull android.content.pm.ArchivedActivityParcel getParcel()\npublic static android.graphics.Bitmap drawableToBitmap(android.graphics.drawable.Drawable)\npublic static android.graphics.Bitmap drawableToBitmap(android.graphics.drawable.Drawable,int)\npublic static byte[] bytesFromBitmap(android.graphics.Bitmap)\nprivate static android.graphics.drawable.Drawable drawableFromCompressedBitmap(byte[])\nclass ArchivedActivityInfo extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=false, genConstructor=false, genSetters=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 23b9d0b..d259e97 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -137,6 +137,8 @@
private ArrayList<ApkAssets> mUserApkAssets = new ArrayList<>();
private ArrayList<ResourcesLoader> mLoaders = new ArrayList<>();
+ private boolean mNoInit = false;
+
public Builder addApkAssets(ApkAssets apkAssets) {
mUserApkAssets.add(apkAssets);
return this;
@@ -147,6 +149,11 @@
return this;
}
+ public Builder setNoInit() {
+ mNoInit = true;
+ return this;
+ }
+
public AssetManager build() {
// Retrieving the system ApkAssets forces their creation as well.
final ApkAssets[] systemApkAssets = getSystem().getApkAssets();
@@ -188,7 +195,7 @@
final AssetManager assetManager = new AssetManager(false /*sentinel*/);
assetManager.mApkAssets = apkAssets;
AssetManager.nativeSetApkAssets(assetManager.mObject, apkAssets,
- false /*invalidateCaches*/);
+ false /*invalidateCaches*/, mNoInit /*preset*/);
assetManager.mLoaders = mLoaders.isEmpty() ? null
: mLoaders.toArray(new ResourcesLoader[0]);
@@ -329,7 +336,7 @@
synchronized (this) {
ensureOpenLocked();
mApkAssets = newApkAssets;
- nativeSetApkAssets(mObject, mApkAssets, invalidateCaches);
+ nativeSetApkAssets(mObject, mApkAssets, invalidateCaches, false);
if (invalidateCaches) {
// Invalidate all caches.
invalidateCachesLocked(-1);
@@ -496,7 +503,7 @@
mApkAssets = Arrays.copyOf(mApkAssets, count + 1);
mApkAssets[count] = assets;
- nativeSetApkAssets(mObject, mApkAssets, true);
+ nativeSetApkAssets(mObject, mApkAssets, true, false);
invalidateCachesLocked(-1);
return count + 1;
}
@@ -1503,12 +1510,29 @@
int navigation, int screenWidth, int screenHeight, int smallestScreenWidthDp,
int screenWidthDp, int screenHeightDp, int screenLayout, int uiMode, int colorMode,
int grammaticalGender, int majorVersion) {
+ setConfigurationInternal(mcc, mnc, defaultLocale, locales, orientation,
+ touchscreen, density, keyboard, keyboardHidden, navigation, screenWidth,
+ screenHeight, smallestScreenWidthDp, screenWidthDp, screenHeightDp,
+ screenLayout, uiMode, colorMode, grammaticalGender, majorVersion, false);
+ }
+
+ /**
+ * Change the configuration used when retrieving resources, and potentially force a refresh of
+ * the state. Not for use by applications.
+ * @hide
+ */
+ void setConfigurationInternal(int mcc, int mnc, String defaultLocale, String[] locales,
+ int orientation, int touchscreen, int density, int keyboard, int keyboardHidden,
+ int navigation, int screenWidth, int screenHeight, int smallestScreenWidthDp,
+ int screenWidthDp, int screenHeightDp, int screenLayout, int uiMode, int colorMode,
+ int grammaticalGender, int majorVersion, boolean forceRefresh) {
synchronized (this) {
ensureValidLocked();
nativeSetConfiguration(mObject, mcc, mnc, defaultLocale, locales, orientation,
touchscreen, density, keyboard, keyboardHidden, navigation, screenWidth,
screenHeight, smallestScreenWidthDp, screenWidthDp, screenHeightDp,
- screenLayout, uiMode, colorMode, grammaticalGender, majorVersion);
+ screenLayout, uiMode, colorMode, grammaticalGender, majorVersion,
+ forceRefresh);
}
}
@@ -1593,13 +1617,13 @@
private static native long nativeCreate();
private static native void nativeDestroy(long ptr);
private static native void nativeSetApkAssets(long ptr, @NonNull ApkAssets[] apkAssets,
- boolean invalidateCaches);
+ boolean invalidateCaches, boolean preset);
private static native void nativeSetConfiguration(long ptr, int mcc, int mnc,
@Nullable String defaultLocale, @NonNull String[] locales, int orientation,
int touchscreen, int density, int keyboard, int keyboardHidden, int navigation,
int screenWidth, int screenHeight, int smallestScreenWidthDp, int screenWidthDp,
int screenHeightDp, int screenLayout, int uiMode, int colorMode, int grammaticalGender,
- int majorVersion);
+ int majorVersion, boolean forceRefresh);
private static native @NonNull SparseArray<String> nativeGetAssignedPackageIdentifiers(
long ptr, boolean includeOverlays, boolean includeLoaders);
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 5e442b8..079c2c1 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -200,7 +200,7 @@
mMetrics.setToDefaults();
mDisplayAdjustments = displayAdjustments;
mConfiguration.setToDefaults();
- updateConfiguration(config, metrics, displayAdjustments.getCompatibilityInfo());
+ updateConfigurationImpl(config, metrics, displayAdjustments.getCompatibilityInfo(), true);
}
public DisplayAdjustments getDisplayAdjustments() {
@@ -402,7 +402,12 @@
}
public void updateConfiguration(Configuration config, DisplayMetrics metrics,
- CompatibilityInfo compat) {
+ CompatibilityInfo compat) {
+ updateConfigurationImpl(config, metrics, compat, false);
+ }
+
+ private void updateConfigurationImpl(Configuration config, DisplayMetrics metrics,
+ CompatibilityInfo compat, boolean forceAssetsRefresh) {
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "ResourcesImpl#updateConfiguration");
try {
synchronized (mAccessLock) {
@@ -528,7 +533,7 @@
keyboardHidden = mConfiguration.keyboardHidden;
}
- mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
+ mAssets.setConfigurationInternal(mConfiguration.mcc, mConfiguration.mnc,
defaultLocale,
selectedLocales,
mConfiguration.orientation,
@@ -539,7 +544,7 @@
mConfiguration.screenWidthDp, mConfiguration.screenHeightDp,
mConfiguration.screenLayout, mConfiguration.uiMode,
mConfiguration.colorMode, mConfiguration.getGrammaticalGender(),
- Build.VERSION.RESOURCES_SDK_INT);
+ Build.VERSION.RESOURCES_SDK_INT, forceAssetsRefresh);
if (DEBUG_CONFIG) {
Slog.i(TAG, "**** Updating config of " + this + ": final config is "
diff --git a/core/java/android/util/MemoryIntArray.java b/core/java/android/util/MemoryIntArray.java
index 5cbbbef..2226881 100644
--- a/core/java/android/util/MemoryIntArray.java
+++ b/core/java/android/util/MemoryIntArray.java
@@ -58,6 +58,7 @@
private final boolean mIsOwner;
private final long mMemoryAddr;
+ private final int mSize;
private int mFd = -1;
/**
@@ -75,6 +76,9 @@
final String name = UUID.randomUUID().toString();
mFd = nativeCreate(name, size);
mMemoryAddr = nativeOpen(mFd, mIsOwner);
+ // Note that we use the effective size after allocation, rather than the provided size,
+ // preserving compat with the original behavior. In practice these should be equivalent.
+ mSize = nativeSize(mFd);
mCloseGuard.open("MemoryIntArray.close");
}
@@ -86,6 +90,7 @@
}
mFd = pfd.detachFd();
mMemoryAddr = nativeOpen(mFd, mIsOwner);
+ mSize = nativeSize(mFd);
mCloseGuard.open("MemoryIntArray.close");
}
@@ -127,13 +132,11 @@
}
/**
- * Gets the array size.
- *
- * @throws IOException If an error occurs while accessing the shared memory.
+ * @return Gets the array size.
*/
- public int size() throws IOException {
+ public int size() {
enforceNotClosed();
- return nativeSize(mFd);
+ return mSize;
}
/**
@@ -210,11 +213,10 @@
}
}
- private void enforceValidIndex(int index) throws IOException {
- final int size = size();
- if (index < 0 || index > size - 1) {
+ private void enforceValidIndex(int index) {
+ if (index < 0 || index > mSize - 1) {
throw new IndexOutOfBoundsException(
- index + " not between 0 and " + (size - 1));
+ index + " not between 0 and " + (mSize - 1));
}
}
diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java
index 4fe53c2..a8d4e2d 100644
--- a/core/java/android/view/KeyCharacterMap.java
+++ b/core/java/android/view/KeyCharacterMap.java
@@ -579,6 +579,17 @@
}
/**
+ * Get the combining character that corresponds with the provided accent.
+ *
+ * @param accent The accent character. eg. '`'
+ * @return The combining character
+ * @hide
+ */
+ public static int getCombiningChar(int accent) {
+ return sAccentToCombining.get(accent);
+ }
+
+ /**
* Describes the character mappings associated with a key.
*
* @deprecated instead use {@link KeyCharacterMap#getDisplayLabel(int)},
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 3ee15ab..3d0ab4e 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -314,7 +314,8 @@
}
static void NativeSetApkAssets(JNIEnv* env, jclass /*clazz*/, jlong ptr,
- jobjectArray apk_assets_array, jboolean invalidate_caches) {
+ jobjectArray apk_assets_array, jboolean invalidate_caches,
+ jboolean preset) {
ATRACE_NAME("AssetManager::SetApkAssets");
const jsize apk_assets_len = env->GetArrayLength(apk_assets_array);
@@ -343,7 +344,11 @@
}
auto assetmanager = LockAndStartAssetManager(ptr);
- assetmanager->SetApkAssets(apk_assets, invalidate_caches);
+ if (preset) {
+ assetmanager->PresetApkAssets(apk_assets);
+ } else {
+ assetmanager->SetApkAssets(apk_assets, invalidate_caches);
+ }
}
static void NativeSetConfiguration(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint mcc, jint mnc,
@@ -353,7 +358,7 @@
jint screen_height, jint smallest_screen_width_dp,
jint screen_width_dp, jint screen_height_dp, jint screen_layout,
jint ui_mode, jint color_mode, jint grammatical_gender,
- jint major_version) {
+ jint major_version, jboolean force_refresh) {
ATRACE_NAME("AssetManager::SetConfiguration");
const jsize locale_count = (locales == NULL) ? 0 : env->GetArrayLength(locales);
@@ -413,7 +418,7 @@
}
auto assetmanager = LockAndStartAssetManager(ptr);
- assetmanager->SetConfigurations(configs);
+ assetmanager->SetConfigurations(std::move(configs), force_refresh != JNI_FALSE);
assetmanager->SetDefaultLocale(default_locale_int);
}
@@ -1522,8 +1527,8 @@
// AssetManager setup methods.
{"nativeCreate", "()J", (void*)NativeCreate},
{"nativeDestroy", "(J)V", (void*)NativeDestroy},
- {"nativeSetApkAssets", "(J[Landroid/content/res/ApkAssets;Z)V", (void*)NativeSetApkAssets},
- {"nativeSetConfiguration", "(JIILjava/lang/String;[Ljava/lang/String;IIIIIIIIIIIIIIII)V",
+ {"nativeSetApkAssets", "(J[Landroid/content/res/ApkAssets;ZZ)V", (void*)NativeSetApkAssets},
+ {"nativeSetConfiguration", "(JIILjava/lang/String;[Ljava/lang/String;IIIIIIIIIIIIIIIIZ)V",
(void*)NativeSetConfiguration},
{"nativeGetAssignedPackageIdentifiers", "(JZZ)Landroid/util/SparseArray;",
(void*)NativeGetAssignedPackageIdentifiers},
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index fa15c3f..972fe7e 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -204,11 +204,4 @@
<dimen name="progress_bar_size_small">16dip</dimen>
<dimen name="progress_bar_size_medium">48dp</dimen>
<dimen name="progress_bar_size_large">76dp</dimen>
-
- <!-- System corner radius baseline sizes. Used by Material styling of rounded corner shapes-->
- <dimen name="system_corner_radius_xsmall">4dp</dimen>
- <dimen name="system_corner_radius_small">8dp</dimen>
- <dimen name="system_corner_radius_medium">16dp</dimen>
- <dimen name="system_corner_radius_large">26dp</dimen>
- <dimen name="system_corner_radius_xlarge">36dp</dimen>
</resources>
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index c797210..5987f6e 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -184,11 +184,11 @@
<staging-public-group type="dimen" first-id="0x01b90000">
<!-- System corner radius baseline sizes. Used by Material styling of rounded corner shapes-->
- <public name="system_corner_radius_xsmall" />
- <public name="system_corner_radius_small" />
- <public name="system_corner_radius_medium" />
- <public name="system_corner_radius_large" />
- <public name="system_corner_radius_xlarge" />
+ <public name="removed_system_corner_radius_xsmall" />
+ <public name="removed_system_corner_radius_small" />
+ <public name="removed_system_corner_radius_medium" />
+ <public name="removed_system_corner_radius_large" />
+ <public name="removed_system_corner_radius_xlarge" />
</staging-public-group>
<staging-public-group type="color" first-id="0x01b80000">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7c290b1..9d7acff 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -5356,11 +5356,4 @@
<java-symbol type="drawable" name="ic_satellite_alt_24px" />
<java-symbol type="bool" name="config_watchlistUseFileHashesCache" />
-
- <!-- System corner radius baseline sizes. Used by Material styling of rounded corner shapes-->
- <java-symbol type="dimen" name="system_corner_radius_xsmall" />
- <java-symbol type="dimen" name="system_corner_radius_small" />
- <java-symbol type="dimen" name="system_corner_radius_medium" />
- <java-symbol type="dimen" name="system_corner_radius_large" />
- <java-symbol type="dimen" name="system_corner_radius_xlarge" />
</resources>
diff --git a/core/tests/utiltests/src/android/util/MemoryIntArrayTest.java b/core/tests/utiltests/src/android/util/MemoryIntArrayTest.java
index 51013e4..8093af9 100644
--- a/core/tests/utiltests/src/android/util/MemoryIntArrayTest.java
+++ b/core/tests/utiltests/src/android/util/MemoryIntArrayTest.java
@@ -123,7 +123,7 @@
parcel.recycle();
assertNotNull("Should marshall file descriptor", secondArray);
-
+ assertEquals("Marshalled size must be three", 3, secondArray.size());
assertEquals("First element should be 1", 1, secondArray.get(0));
assertEquals("First element should be 2", 2, secondArray.get(1));
assertEquals("First element should be 3", 3, secondArray.get(2));
diff --git a/core/tests/utiltests/src/android/util/RemoteMemoryIntArrayService.java b/core/tests/utiltests/src/android/util/RemoteMemoryIntArrayService.java
index 9264c6c..32dda6b 100644
--- a/core/tests/utiltests/src/android/util/RemoteMemoryIntArrayService.java
+++ b/core/tests/utiltests/src/android/util/RemoteMemoryIntArrayService.java
@@ -84,11 +84,7 @@
@Override
public int size() {
synchronized (mLock) {
- try {
- return mArray.size();
- } catch (IOException e) {
- throw new IllegalStateException(e);
- }
+ return mArray.size();
}
}
diff --git a/graphics/java/android/graphics/pdf/TEST_MAPPING b/graphics/java/android/graphics/pdf/TEST_MAPPING
index d763598..afec35c 100644
--- a/graphics/java/android/graphics/pdf/TEST_MAPPING
+++ b/graphics/java/android/graphics/pdf/TEST_MAPPING
@@ -1,7 +1,12 @@
{
"presubmit": [
{
- "name": "CtsPdfTestCases"
+ "name": "CtsPdfTestCases",
+ "options": [
+ {
+ "include-filter": "android.graphics.pdf.cts.PdfDocumentTest"
+ }
+ ]
}
]
}
diff --git a/libs/WindowManager/Shell/aconfig/OWNERS b/libs/WindowManager/Shell/aconfig/OWNERS
new file mode 100644
index 0000000..9eba0f2
--- /dev/null
+++ b/libs/WindowManager/Shell/aconfig/OWNERS
@@ -0,0 +1,3 @@
+# Owners for flag changes
+madym@google.com
+hwwang@google.com
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
index 9a66c0f..0967f4e 100644
--- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig
+++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
@@ -64,3 +64,10 @@
description: "Enables the new bubble bar UI for tablets"
bug: "286246694"
}
+
+flag {
+ name: "enable_bubbles_long_press_nav_handle"
+ namespace: "multitasking"
+ description: "Enables long-press action for nav handle when a bubble is expanded"
+ bug: "324910035"
+}
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 8748dab..46f636e 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -117,6 +117,10 @@
return true;
}
+void AssetManager2::PresetApkAssets(ApkAssetsList apk_assets) {
+ BuildDynamicRefTable(apk_assets);
+}
+
bool AssetManager2::SetApkAssets(std::initializer_list<ApkAssetsPtr> apk_assets,
bool invalidate_caches) {
return SetApkAssets(ApkAssetsList(apk_assets.begin(), apk_assets.size()), invalidate_caches);
@@ -432,13 +436,18 @@
return false;
}
-void AssetManager2::SetConfigurations(std::vector<ResTable_config> configurations) {
+void AssetManager2::SetConfigurations(std::vector<ResTable_config> configurations,
+ bool force_refresh) {
int diff = 0;
- if (configurations_.size() != configurations.size()) {
+ if (force_refresh) {
diff = -1;
} else {
- for (int i = 0; i < configurations_.size(); i++) {
- diff |= configurations_[i].diff(configurations[i]);
+ if (configurations_.size() != configurations.size()) {
+ diff = -1;
+ } else {
+ for (int i = 0; i < configurations_.size(); i++) {
+ diff |= configurations_[i].diff(configurations[i]);
+ }
}
}
configurations_ = std::move(configurations);
@@ -775,8 +784,7 @@
bool has_locale = false;
if (result->config.locale == 0) {
if (default_locale_ != 0) {
- ResTable_config conf;
- conf.locale = default_locale_;
+ ResTable_config conf = {.locale = default_locale_};
// Since we know conf has a locale and only a locale, match will tell us if that locale
// matches
has_locale = conf.match(config);
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index d9ff35b..17a8ba6 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -124,6 +124,9 @@
// new resource IDs.
bool SetApkAssets(ApkAssetsList apk_assets, bool invalidate_caches = true);
bool SetApkAssets(std::initializer_list<ApkAssetsPtr> apk_assets, bool invalidate_caches = true);
+ // This one is an optimization - it skips all calculations for applying the currently set
+ // configuration, expecting a configuration update later with a forced refresh.
+ void PresetApkAssets(ApkAssetsList apk_assets);
const ApkAssetsPtr& GetApkAssets(ApkAssetsCookie cookie) const;
int GetApkAssetsCount() const {
@@ -156,7 +159,7 @@
// Sets/resets the configuration for this AssetManager. This will cause all
// caches that are related to the configuration change to be invalidated.
- void SetConfigurations(std::vector<ResTable_config> configurations);
+ void SetConfigurations(std::vector<ResTable_config> configurations, bool force_refresh = false);
inline const std::vector<ResTable_config>& GetConfigurations() const {
return configurations_;
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index 71f7926..27ea150 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -378,10 +378,17 @@
break;
case kAlpha_8_SkColorType:
formatInfo.isSupported = HardwareBitmapUploader::hasAlpha8Support();
- formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8_UNORM;
- formatInfo.format = GL_RED;
- formatInfo.type = GL_UNSIGNED_BYTE;
- formatInfo.vkFormat = VK_FORMAT_R8_UNORM;
+ if (formatInfo.isSupported) {
+ formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8_UNORM;
+ formatInfo.format = GL_RED;
+ formatInfo.type = GL_UNSIGNED_BYTE;
+ formatInfo.vkFormat = VK_FORMAT_R8_UNORM;
+ } else {
+ formatInfo.type = GL_UNSIGNED_BYTE;
+ formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
+ formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
+ formatInfo.format = GL_RGBA;
+ }
break;
default:
ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType());
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 8344a86..1854361 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -147,11 +147,7 @@
}
sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(const SkBitmap& bitmap) {
-#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
- if (bitmap.colorType() == kAlpha_8_SkColorType &&
- !uirenderer::HardwareBitmapUploader::hasAlpha8Support()) {
- return nullptr;
- }
+#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
return uirenderer::HardwareBitmapUploader::allocateHardwareBitmap(bitmap);
#else
return Bitmap::allocateHeapBitmap(bitmap.info());
diff --git a/media/java/android/media/audiofx/Visualizer.java b/media/java/android/media/audiofx/Visualizer.java
index 2795cfe..f05ea9c 100644
--- a/media/java/android/media/audiofx/Visualizer.java
+++ b/media/java/android/media/audiofx/Visualizer.java
@@ -336,8 +336,9 @@
* This method must not be called when the Visualizer is enabled.
* @param size requested capture size
* @return {@link #SUCCESS} in case of success,
- * {@link #ERROR_BAD_VALUE} in case of failure.
- * @throws IllegalStateException
+ * {@link #ERROR_INVALID_OPERATION} if Visualizer effect enginer not enabled.
+ * @throws IllegalStateException if the effect is not in proper state.
+ * @throws IllegalArgumentException if the size parameter is invalid (out of supported range).
*/
public int setCaptureSize(int size)
throws IllegalStateException {
@@ -345,7 +346,13 @@
if (mState != STATE_INITIALIZED) {
throw(new IllegalStateException("setCaptureSize() called in wrong state: "+mState));
}
- return native_setCaptureSize(size);
+
+ int ret = native_setCaptureSize(size);
+ if (ret == ERROR_BAD_VALUE) {
+ throw(new IllegalArgumentException("setCaptureSize to " + size + " failed"));
+ }
+
+ return ret;
}
}
diff --git a/media/jni/audioeffect/Visualizer.cpp b/media/jni/audioeffect/Visualizer.cpp
index 09c45ea..9ae5c99 100644
--- a/media/jni/audioeffect/Visualizer.cpp
+++ b/media/jni/audioeffect/Visualizer.cpp
@@ -25,7 +25,6 @@
#include <limits.h>
#include <audio_utils/fixedfft.h>
-#include <cutils/bitops.h>
#include <utils/Thread.h>
#include <android/content/AttributionSourceState.h>
@@ -59,8 +58,8 @@
status_t status = AudioEffect::set(
SL_IID_VISUALIZATION, nullptr, priority, cbf, user, sessionId, io, device, probe);
if (status == NO_ERROR || status == ALREADY_EXISTS) {
- initCaptureSize();
- initSampleRate();
+ status = initCaptureSize();
+ if (status == NO_ERROR) initSampleRate();
}
return status;
}
@@ -152,9 +151,8 @@
status_t Visualizer::setCaptureSize(uint32_t size)
{
- if (size > VISUALIZER_CAPTURE_SIZE_MAX ||
- size < VISUALIZER_CAPTURE_SIZE_MIN ||
- popcount(size) != 1) {
+ if (!isCaptureSizeValid(size)) {
+ ALOGE("%s with invalid capture size %u from HAL", __func__, size);
return BAD_VALUE;
}
@@ -172,7 +170,7 @@
*((int32_t *)p->data + 1)= size;
status_t status = setParameter(p);
- ALOGV("setCaptureSize size %d status %d p->status %d", size, status, p->status);
+ ALOGV("setCaptureSize size %u status %d p->status %d", size, status, p->status);
if (status == NO_ERROR) {
status = p->status;
@@ -257,8 +255,8 @@
if ((type != MEASUREMENT_MODE_PEAK_RMS)
// for peak+RMS measurement, the results are 2 int32_t values
|| (number != 2)) {
- ALOGE("Cannot retrieve int measurements, MEASUREMENT_MODE_PEAK_RMS returns 2 ints, not %d",
- number);
+ ALOGE("Cannot retrieve int measurements, MEASUREMENT_MODE_PEAK_RMS returns 2 ints, not %u",
+ number);
return BAD_VALUE;
}
@@ -390,7 +388,7 @@
}
}
-uint32_t Visualizer::initCaptureSize()
+status_t Visualizer::initCaptureSize()
{
uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
effect_param_t *p = (effect_param_t *)buf32;
@@ -405,14 +403,20 @@
}
uint32_t size = 0;
- if (status == NO_ERROR) {
- size = *((int32_t *)p->data + 1);
+ if (status != NO_ERROR) {
+ ALOGE("%s getParameter failed status %d", __func__, status);
+ return status;
}
+
+ size = *((int32_t *)p->data + 1);
+ if (!isCaptureSizeValid(size)) {
+ ALOGE("%s with invalid capture size %u from HAL", __func__, size);
+ return BAD_VALUE;
+ }
+
mCaptureSize = size;
-
- ALOGV("initCaptureSize size %d status %d", mCaptureSize, status);
-
- return size;
+ ALOGV("%s size %u status %d", __func__, mCaptureSize, status);
+ return NO_ERROR;
}
void Visualizer::initSampleRate()
diff --git a/media/jni/audioeffect/Visualizer.h b/media/jni/audioeffect/Visualizer.h
index b38c01f..26d58d0 100644
--- a/media/jni/audioeffect/Visualizer.h
+++ b/media/jni/audioeffect/Visualizer.h
@@ -20,6 +20,8 @@
#include <media/AudioEffect.h>
#include <system/audio_effects/effect_visualizer.h>
#include <utils/Thread.h>
+#include <cstdint>
+#include <cutils/bitops.h>
#include "android/content/AttributionSourceState.h"
/**
@@ -170,8 +172,12 @@
status_t doFft(uint8_t *fft, uint8_t *waveform);
void periodicCapture();
- uint32_t initCaptureSize();
+ status_t initCaptureSize();
void initSampleRate();
+ static constexpr bool isCaptureSizeValid(uint32_t size) {
+ return size <= VISUALIZER_CAPTURE_SIZE_MAX && size >= VISUALIZER_CAPTURE_SIZE_MIN &&
+ popcount(size) == 1;
+ }
Mutex mCaptureLock;
uint32_t mCaptureRate = CAPTURE_RATE_DEF;
diff --git a/packages/PackageInstaller/res/values-night/themes.xml b/packages/PackageInstaller/res/values-night/themes.xml
index 18320f7..a5b82b3 100644
--- a/packages/PackageInstaller/res/values-night/themes.xml
+++ b/packages/PackageInstaller/res/values-night/themes.xml
@@ -20,6 +20,9 @@
<style name="Theme.AlertDialogActivity"
parent="@android:style/Theme.DeviceDefault.Dialog.Alert">
<item name="alertDialogStyle">@style/AlertDialog</item>
+ <item name="android:windowActionBar">false</item>
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowAnimationStyle">@null</item>
</style>
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java b/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java
index cd35f67..be480b9 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java
@@ -308,11 +308,8 @@
final long token = proto.start(GenerationRegistryProto.BACKING_STORES);
final int key = mKeyToBackingStoreMap.keyAt(i);
proto.write(BackingStoreProto.KEY, key);
- try {
- proto.write(BackingStoreProto.BACKING_STORE_SIZE,
- mKeyToBackingStoreMap.valueAt(i).size());
- } catch (IOException ignore) {
- }
+ proto.write(BackingStoreProto.BACKING_STORE_SIZE,
+ mKeyToBackingStoreMap.valueAt(i).size());
proto.write(BackingStoreProto.NUM_CACHED_ENTRIES,
mKeyToIndexMapMap.get(key).size());
final ArrayMap<String, Integer> indexMap = mKeyToIndexMapMap.get(key);
@@ -357,10 +354,7 @@
pw.print("_Backing store for type:"); pw.print(SettingsState.settingTypeToString(
SettingsState.getTypeFromKey(key)));
pw.print(" user:"); pw.print(SettingsState.getUserIdFromKey(key));
- try {
- pw.print(" size:" + mKeyToBackingStoreMap.valueAt(i).size());
- } catch (IOException ignore) {
- }
+ pw.print(" size:" + mKeyToBackingStoreMap.valueAt(i).size());
pw.println(" cachedEntries:" + mKeyToIndexMapMap.get(key).size());
final ArrayMap<String, Integer> indexMap = mKeyToIndexMapMap.get(key);
final MemoryIntArray backingStore = getBackingStoreLocked(key,
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index f6c794c..7f229fb 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -29,6 +29,13 @@
}
flag {
+ name: "notification_color_update_logger"
+ namespace: "systemui"
+ description: "Enabled debug logging and dumping of notification color updates."
+ bug: "294347738"
+}
+
+flag {
name: "notifications_footer_view_refactor"
namespace: "systemui"
description: "Enables the refactored version of the footer view in the notification shade "
@@ -462,4 +469,3 @@
purpose: PURPOSE_BUGFIX
}
}
-
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
index 55cfcc2..ab55125 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
@@ -210,6 +210,32 @@
}
@Test
+ fun shouldHandleTouchesOnDetach() =
+ testScope.runTest {
+ val shouldHandleTouches by collectLastValue(mUdfpsOverlayInteractor.shouldHandleTouches)
+
+ // GIVEN view is attached + on the keyguard
+ mController.onViewAttached()
+ captureStatusBarStateListeners()
+ sendStatusBarStateChanged(StatusBarState.KEYGUARD)
+ whenever(mView.setPauseAuth(true)).thenReturn(true)
+ whenever(mView.unpausedAlpha).thenReturn(0)
+
+ // WHEN panelViewExpansion changes to expanded
+ val job = mController.listenForBouncerExpansion(this)
+ keyguardBouncerRepository.setPrimaryShow(true)
+ keyguardBouncerRepository.setPanelExpansion(KeyguardBouncerConstants.EXPANSION_VISIBLE)
+ runCurrent()
+
+ mController.onViewDetached()
+
+ // THEN UDFPS auth is paused and should not handle touches
+ assertThat(mController.shouldPauseAuth()).isTrue()
+ assertThat(shouldHandleTouches!!).isFalse()
+
+ job.cancel()
+ }
+ @Test
fun fadeFromDialogSuggestedAlpha() =
testScope.runTest {
// GIVEN view is attached and status bar expansion is 1f
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
index 3455050..3104842 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
@@ -18,8 +18,6 @@
package com.android.systemui.keyguard.ui.viewmodel
-import android.content.pm.UserInfo
-import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -27,21 +25,20 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
-import com.android.systemui.communal.domain.interactor.communalSettingsInteractor
+import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.communal.domain.interactor.setCommunalAvailable
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
-import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED
-import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificationsPlaceholderViewModel
import com.android.systemui.testKosmos
-import com.android.systemui.user.data.repository.fakeUserRepository
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
@@ -85,35 +82,21 @@
@EnableFlags(FLAG_COMMUNAL_HUB)
@Test
- fun leftTransitionSceneKey_communalIsEnabled_communal() =
+ fun leftTransitionSceneKey_communalIsAvailable_communal() =
testScope.runTest {
- with(kosmos.fakeUserRepository) {
- setUserInfos(listOf(PRIMARY_USER))
- setSelectedUserInfo(PRIMARY_USER)
- }
- kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true)
- val leftDestinationSceneKey by collectLastValue(underTest.leftDestinationSceneKey)
- assertThat(leftDestinationSceneKey).isEqualTo(SceneKey.Communal)
- }
-
- @DisableFlags(FLAG_COMMUNAL_HUB)
- @Test
- fun leftTransitionSceneKey_communalIsDisabled_null() =
- testScope.runTest {
- with(kosmos.fakeUserRepository) {
- setUserInfos(listOf(PRIMARY_USER))
- setSelectedUserInfo(PRIMARY_USER)
- }
- kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, false)
val leftDestinationSceneKey by collectLastValue(underTest.leftDestinationSceneKey)
assertThat(leftDestinationSceneKey).isNull()
+
+ kosmos.setCommunalAvailable(true)
+ runCurrent()
+ assertThat(leftDestinationSceneKey).isEqualTo(SceneKey.Communal)
}
private fun createLockscreenSceneViewModel(): LockscreenSceneViewModel {
return LockscreenSceneViewModel(
applicationScope = testScope.backgroundScope,
deviceEntryInteractor = kosmos.deviceEntryInteractor,
- communalSettingsInteractor = kosmos.communalSettingsInteractor,
+ communalInteractor = kosmos.communalInteractor,
longPress =
KeyguardLongPressViewModel(
interactor = mock(),
@@ -121,9 +104,4 @@
notifications = kosmos.notificationsPlaceholderViewModel,
)
}
-
- private companion object {
- val PRIMARY_USER =
- UserInfo(/* id= */ 0, /* name= */ "primary user", /* flags= */ UserInfo.FLAG_MAIN)
- }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
index 7c30c7e..9f89d34 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -40,7 +40,7 @@
import com.android.systemui.bouncer.ui.viewmodel.bouncerViewModel
import com.android.systemui.classifier.domain.interactor.falsingInteractor
import com.android.systemui.classifier.falsingCollector
-import com.android.systemui.communal.domain.interactor.communalSettingsInteractor
+import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
@@ -130,7 +130,7 @@
private val sceneInteractor by lazy { kosmos.sceneInteractor }
private val authenticationInteractor by lazy { kosmos.authenticationInteractor }
private val deviceEntryInteractor by lazy { kosmos.deviceEntryInteractor }
- private val communalSettingsInteractor by lazy { kosmos.communalSettingsInteractor }
+ private val communalInteractor by lazy { kosmos.communalInteractor }
private val transitionState by lazy {
MutableStateFlow<ObservableTransitionState>(
@@ -155,7 +155,7 @@
LockscreenSceneViewModel(
applicationScope = testScope.backgroundScope,
deviceEntryInteractor = deviceEntryInteractor,
- communalSettingsInteractor = communalSettingsInteractor,
+ communalInteractor = communalInteractor,
longPress =
KeyguardLongPressViewModel(
interactor = mock(),
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
index f5603ed..c3e7818 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
@@ -132,13 +132,13 @@
override fun onViewAttached() {
dialogManager.registerListener(dialogListener)
dumpManager.registerDumpable(dumpTag, this)
- udfpsOverlayInteractor.setHandleTouches(shouldHandle = true)
+ udfpsOverlayInteractor.setHandleTouches(shouldHandle = !shouldPauseAuth())
}
override fun onViewDetached() {
dialogManager.unregisterListener(dialogListener)
dumpManager.unregisterDumpable(dumpTag)
- udfpsOverlayInteractor.setHandleTouches(shouldHandle = true)
+ udfpsOverlayInteractor.setHandleTouches(shouldHandle = !shouldPauseAuth())
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt
index 018d92e..ec54e4ce 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt
@@ -378,7 +378,7 @@
}
}
- override fun onViewDetached() {
+ public override fun onViewDetached() {
super.onViewDetached()
alternateBouncerInteractor.setAlternateBouncerUIAvailable(false, uniqueIdentifier)
faceDetectRunning = false
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
index fa18557..9afe8fc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
@@ -16,7 +16,7 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
+import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
@@ -36,7 +36,7 @@
constructor(
@Application applicationScope: CoroutineScope,
deviceEntryInteractor: DeviceEntryInteractor,
- communalSettingsInteractor: CommunalSettingsInteractor,
+ communalInteractor: CommunalInteractor,
val longPress: KeyguardLongPressViewModel,
val notifications: NotificationsPlaceholderViewModel,
) {
@@ -56,7 +56,7 @@
/** The key of the scene we should switch to when swiping left. */
val leftDestinationSceneKey: StateFlow<SceneKey?> =
- communalSettingsInteractor.isCommunalEnabled
+ communalInteractor.isCommunalAvailable
.map { available -> if (available) SceneKey.Communal else null }
.stateIn(
scope = applicationScope,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 0e0f152..6155348 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar;
import static com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress;
+import static com.android.systemui.util.ColorUtilKt.hexColorString;
import android.content.Context;
import android.content.res.Configuration;
@@ -42,6 +43,7 @@
import com.android.systemui.flags.RefactorFlag;
import com.android.systemui.res.R;
import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
+import com.android.systemui.statusbar.notification.ColorUpdateLogger;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.SourceType;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
@@ -187,8 +189,8 @@
@Override
public String toString() {
- return "NotificationShelf"
- + "(hideBackground=" + mHideBackground
+ return super.toString()
+ + " (hideBackground=" + mHideBackground
+ " notGoneIndex=" + mNotGoneIndex
+ " hasItemsInStableShelf=" + mHasItemsInStableShelf
+ " interactive=" + mInteractive
@@ -368,6 +370,17 @@
&& isYInView(localY, slop, top, bottom);
}
+ @Override
+ public void updateBackgroundColors() {
+ super.updateBackgroundColors();
+ ColorUpdateLogger colorUpdateLogger = ColorUpdateLogger.getInstance();
+ if (colorUpdateLogger != null) {
+ colorUpdateLogger.logEvent("Shelf.updateBackgroundColors()",
+ "normalBgColor=" + hexColorString(getNormalBgColor())
+ + " background=" + mBackgroundNormal.toDumpString());
+ }
+ }
+
/**
* Update the shelf appearance based on the other notifications around it. This transforms
* the icons from the notification area into the shelf.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ColorUpdateLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ColorUpdateLogger.kt
new file mode 100644
index 0000000..c8f996a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ColorUpdateLogger.kt
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2023 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.systemui.statusbar.notification
+
+import android.icu.text.SimpleDateFormat
+import android.util.IndentingPrintWriter
+import com.android.systemui.Dumpable
+import com.android.systemui.Flags.notificationColorUpdateLogger
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.util.Compile
+import com.android.systemui.util.asIndenting
+import com.android.systemui.util.printCollection
+import com.android.systemui.util.withIncreasedIndent
+import com.google.errorprone.annotations.CompileTimeConstant
+import java.io.PrintWriter
+import java.util.Locale
+import java.util.SortedSet
+import java.util.TreeSet
+import javax.inject.Inject
+
+@SysUISingleton
+class ColorUpdateLogger
+@Inject
+constructor(
+ val featureFlags: FeatureFlagsClassic,
+ dumpManager: DumpManager,
+) : Dumpable {
+
+ inline val isEnabled
+ get() = Compile.IS_DEBUG && notificationColorUpdateLogger()
+ private val frames: MutableList<Frame> = mutableListOf()
+
+ init {
+ dumpManager.registerDumpable(this)
+ if (isEnabled) {
+ instance = this
+ }
+ }
+
+ @JvmOverloads
+ fun logTriggerEvent(@CompileTimeConstant type: String, extra: String? = null) {
+ if (!isEnabled) return
+ val event = Event(type = type, extraValue = extra)
+ val didAppend = frames.lastOrNull()?.tryAddTrigger(event) == true
+ if (!didAppend) {
+ frames.add(Frame(event))
+ if (frames.size > maxFrames) frames.removeFirst()
+ }
+ }
+
+ @JvmOverloads
+ fun logEvent(@CompileTimeConstant type: String, extra: String? = null) {
+ if (!isEnabled) return
+ val frame = frames.lastOrNull() ?: return
+ frame.events.add(Event(type = type, extraValue = extra))
+ frame.trim()
+ }
+
+ @JvmOverloads
+ fun logNotificationEvent(
+ @CompileTimeConstant type: String,
+ key: String,
+ extra: String? = null
+ ) {
+ if (!isEnabled) return
+ val frame = frames.lastOrNull() ?: return
+ frame.events.add(Event(type = type, extraValue = extra, notificationKey = key))
+ frame.trim()
+ }
+
+ override fun dump(pwOrig: PrintWriter, args: Array<out String>) {
+ val pw = pwOrig.asIndenting()
+ pw.println("enabled: $isEnabled")
+ pw.printCollection("frames", frames) { it.dump(pw) }
+ }
+
+ private class Frame(event: Event) {
+ val startTime: Long = event.time
+ val events: MutableList<Event> = mutableListOf(event)
+ val triggers: SortedSet<String> = TreeSet<String>().apply { add(event.type) }
+ var trimmedEvents: Int = 0
+
+ fun tryAddTrigger(newEvent: Event): Boolean {
+ if (newEvent.time < startTime) return false
+ if (newEvent.time - startTime > triggerStartsNewFrameAge) return false
+ if (newEvent.type in triggers) return false
+ triggers.add(newEvent.type)
+ events.add(newEvent)
+ trim()
+ return true
+ }
+
+ fun trim() {
+ if (events.size > maxEventsPerFrame) {
+ events.removeFirst()
+ trimmedEvents++
+ }
+ }
+
+ fun dump(pw: IndentingPrintWriter) {
+ pw.println("Frame")
+ pw.withIncreasedIndent {
+ pw.println("startTime: ${timeString(startTime)}")
+ pw.printCollection("triggers", triggers)
+ pw.println("trimmedEvents: $trimmedEvents")
+ pw.printCollection("events", events) { it.dump(pw) }
+ }
+ }
+ }
+
+ private class Event(
+ @CompileTimeConstant val type: String,
+ val extraValue: String? = null,
+ val notificationKey: String? = null,
+ ) {
+ val time: Long = System.currentTimeMillis()
+
+ fun dump(pw: IndentingPrintWriter) {
+ pw.append(timeString(time)).append(": ").append(type)
+ extraValue?.let { pw.append(" ").append(it) }
+ notificationKey?.let { pw.append(" ---- ").append(logKey(it)) }
+ pw.println()
+ }
+ }
+
+ private companion object {
+ @JvmStatic
+ var instance: ColorUpdateLogger? = null
+ private set
+ private const val maxFrames = 5
+ private const val maxEventsPerFrame = 250
+ private const val triggerStartsNewFrameAge = 5000
+
+ private val dateFormat = SimpleDateFormat("MM-dd HH:mm:ss.SSS", Locale.US)
+ private fun timeString(time: Long): String = dateFormat.format(time)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
index 3809ea0..b8a9594 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
@@ -23,6 +23,7 @@
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener
+import com.android.systemui.statusbar.notification.ColorUpdateLogger
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
import com.android.systemui.statusbar.notification.row.NotificationGutsManager
@@ -41,7 +42,8 @@
private val mConfigurationController: ConfigurationController,
private val mLockscreenUserManager: NotificationLockscreenUserManager,
private val mGutsManager: NotificationGutsManager,
- private val mKeyguardUpdateMonitor: KeyguardUpdateMonitor
+ private val mKeyguardUpdateMonitor: KeyguardUpdateMonitor,
+ private val colorUpdateLogger: ColorUpdateLogger,
) : Coordinator, ConfigurationController.ConfigurationListener {
private var mIsSwitchingUser = false
@@ -51,11 +53,13 @@
private val mKeyguardUpdateCallback = object : KeyguardUpdateMonitorCallback() {
override fun onUserSwitching(userId: Int) {
+ colorUpdateLogger.logTriggerEvent("VCC.mKeyguardUpdateCallback.onUserSwitching()")
log { "ViewConfigCoordinator.onUserSwitching(userId=$userId)" }
mIsSwitchingUser = true
}
override fun onUserSwitchComplete(userId: Int) {
+ colorUpdateLogger.logTriggerEvent("VCC.mKeyguardUpdateCallback.onUserSwitchComplete()")
log { "ViewConfigCoordinator.onUserSwitchComplete(userId=$userId)" }
mIsSwitchingUser = false
applyChangesOnUserSwitched()
@@ -64,6 +68,7 @@
private val mUserChangedListener = object : UserChangedListener {
override fun onUserChanged(userId: Int) {
+ colorUpdateLogger.logTriggerEvent("VCC.mUserChangedListener.onUserChanged()")
log { "ViewConfigCoordinator.onUserChanged(userId=$userId)" }
applyChangesOnUserSwitched()
}
@@ -77,6 +82,7 @@
}
override fun onDensityOrFontScaleChanged() {
+ colorUpdateLogger.logTriggerEvent("VCC.onDensityOrFontScaleChanged()")
log {
val keyguardIsSwitchingUser = mKeyguardUpdateMonitor.isSwitchingUser
"ViewConfigCoordinator.onDensityOrFontScaleChanged()" +
@@ -93,6 +99,7 @@
}
override fun onUiModeChanged() {
+ colorUpdateLogger.logTriggerEvent("VCC.onUiModeChanged()")
log {
val keyguardIsSwitchingUser = mKeyguardUpdateMonitor.isSwitchingUser
"ViewConfigCoordinator.onUiModeChanged()" +
@@ -107,10 +114,12 @@
}
override fun onThemeChanged() {
+ colorUpdateLogger.logTriggerEvent("VCC.onThemeChanged()")
onDensityOrFontScaleChanged()
}
private fun applyChangesOnUserSwitched() {
+ colorUpdateLogger.logEvent("VCC.applyChangesOnUserSwitched()")
if (mReinflateNotificationsOnUserSwitched) {
updateNotificationsOnDensityOrFontScaleChanged()
mReinflateNotificationsOnUserSwitched = false
@@ -122,6 +131,8 @@
}
private fun updateNotificationsOnUiModeChanged() {
+ colorUpdateLogger.logEvent("VCC.updateNotificationsOnUiModeChanged()",
+ "mode=" + mConfigurationController.nightModeName)
log { "ViewConfigCoordinator.updateNotificationsOnUiModeChanged()" }
traceSection("updateNotifOnUiModeChanged") {
mPipeline?.allNotifs?.forEach { entry ->
@@ -131,6 +142,7 @@
}
private fun updateNotificationsOnDensityOrFontScaleChanged() {
+ colorUpdateLogger.logEvent("VCC.updateNotificationsOnDensityOrFontScaleChanged()")
mPipeline?.allNotifs?.forEach { entry ->
entry.onDensityOrFontScaleChanged()
val exposedGuts = entry.areGutsExposed()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
index 16f18a3..f792898 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
@@ -19,6 +19,7 @@
import static android.graphics.PorterDuff.Mode.SRC_ATOP;
import static com.android.systemui.Flags.notificationBackgroundTintOptimization;
+import static com.android.systemui.util.ColorUtilKt.hexColorString;
import android.annotation.ColorInt;
import android.annotation.DrawableRes;
@@ -40,11 +41,13 @@
import com.android.settingslib.Utils;
import com.android.systemui.res.R;
+import com.android.systemui.statusbar.notification.ColorUpdateLogger;
import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor;
import com.android.systemui.statusbar.notification.row.FooterViewButton;
import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
import com.android.systemui.statusbar.notification.stack.ViewState;
+import com.android.systemui.util.DrawableDumpKt;
import com.android.systemui.util.DumpUtilsKt;
import java.io.PrintWriter;
@@ -239,6 +242,10 @@
@Override
protected void onFinishInflate() {
+ ColorUpdateLogger colorUpdateLogger = ColorUpdateLogger.getInstance();
+ if (colorUpdateLogger != null) {
+ colorUpdateLogger.logTriggerEvent("Footer.onFinishInflate()");
+ }
super.onFinishInflate();
mClearAllButton = (FooterViewButton) findSecondaryView();
mManageOrHistoryButton = findViewById(R.id.manage_text);
@@ -348,6 +355,10 @@
@Override
protected void onConfigurationChanged(Configuration newConfig) {
+ ColorUpdateLogger colorUpdateLogger = ColorUpdateLogger.getInstance();
+ if (colorUpdateLogger != null) {
+ colorUpdateLogger.logTriggerEvent("Footer.onConfigurationChanged()");
+ }
super.onConfigurationChanged(newConfig);
updateColors();
if (!FooterViewRefactor.isEnabled()) {
@@ -365,14 +376,17 @@
com.android.internal.R.attr.materialColorOnSurface);
final Drawable clearAllBg = theme.getDrawable(R.drawable.notif_footer_btn_background);
final Drawable manageBg = theme.getDrawable(R.drawable.notif_footer_btn_background);
+ final @ColorInt int scHigh;
if (!notificationBackgroundTintOptimization()) {
- final @ColorInt int scHigh = Utils.getColorAttrDefaultColor(mContext,
+ scHigh = Utils.getColorAttrDefaultColor(mContext,
com.android.internal.R.attr.materialColorSurfaceContainerHigh);
if (scHigh != 0) {
final ColorFilter bgColorFilter = new PorterDuffColorFilter(scHigh, SRC_ATOP);
clearAllBg.setColorFilter(bgColorFilter);
manageBg.setColorFilter(bgColorFilter);
}
+ } else {
+ scHigh = 0;
}
mClearAllButton.setBackground(clearAllBg);
mClearAllButton.setTextColor(onSurface);
@@ -380,6 +394,13 @@
mManageOrHistoryButton.setTextColor(onSurface);
mSeenNotifsFooterTextView.setTextColor(onSurface);
mSeenNotifsFooterTextView.setCompoundDrawableTintList(ColorStateList.valueOf(onSurface));
+ ColorUpdateLogger colorUpdateLogger = ColorUpdateLogger.getInstance();
+ if (colorUpdateLogger != null) {
+ colorUpdateLogger.logEvent("Footer.updateColors()",
+ "textColor(onSurface)=" + hexColorString(onSurface)
+ + " backgroundTint(surfaceContainerHigh)=" + hexColorString(scHigh)
+ + " background=" + DrawableDumpKt.dumpToString(manageBg));
+ }
}
private void updateResources() {
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 fca527f..7358034 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
@@ -88,7 +88,7 @@
private boolean mActivated;
private Interpolator mCurrentAppearInterpolator;
- NotificationBackgroundView mBackgroundNormal;
+ protected NotificationBackgroundView mBackgroundNormal;
private float mAnimationTranslationY;
private boolean mDrawingAppearAnimation;
private ValueAnimator mAppearAnimator;
@@ -142,6 +142,10 @@
updateBackgroundTint();
}
+ protected int getNormalBgColor() {
+ return mNormalColor;
+ }
+
/**
* @param width The actual width to apply to the background view.
*/
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 cc91ed3..d828ad7 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
@@ -21,6 +21,7 @@
import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.PARENT_DISMISSED;
import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
+import static com.android.systemui.util.ColorUtilKt.hexColorString;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -85,6 +86,7 @@
import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
+import com.android.systemui.statusbar.notification.ColorUpdateLogger;
import com.android.systemui.statusbar.notification.FeedbackIcon;
import com.android.systemui.statusbar.notification.LaunchAnimationParameters;
import com.android.systemui.statusbar.notification.NotificationFadeAware;
@@ -172,6 +174,7 @@
private Optional<BubblesManager> mBubblesManagerOptional;
private MetricsLogger mMetricsLogger;
private NotificationChildrenContainerLogger mChildrenContainerLogger;
+ private ColorUpdateLogger mColorUpdateLogger;
private NotificationDismissibilityProvider mDismissibilityProvider;
private FeatureFlags mFeatureFlags;
private int mIconTransformContentShift;
@@ -445,6 +448,7 @@
/**
* Sets animations running in the layouts of this row, including public, private, and children.
+ *
* @param running whether the animations should be started running or stopped.
*/
public void setAnimationRunning(boolean running) {
@@ -611,6 +615,12 @@
private void updateBackgroundColorsOfSelf() {
super.updateBackgroundColors();
+ if (mColorUpdateLogger.isEnabled()) {
+ mColorUpdateLogger.logNotificationEvent("ENR.updateBackgroundColorsOfSelf()",
+ mLoggingKey,
+ "normalBgColor=" + hexColorString(getNormalBgColor())
+ + " background=" + mBackgroundNormal.toDumpString());
+ }
}
@Override
@@ -1389,7 +1399,7 @@
}
public void setContentBackground(int customBackgroundColor, boolean animate,
- NotificationContentView notificationContentView) {
+ NotificationContentView notificationContentView) {
if (getShowingLayout() == notificationContentView) {
setTintColor(customBackgroundColor, animate);
}
@@ -1458,7 +1468,7 @@
}
/**
- * @return if this entry should be kept in its parent during removal.
+ * @return if this entry should be kept in its parent during removal.
*/
public boolean keepInParentForDismissAnimation() {
return mKeepInParentForDismissAnimation;
@@ -1769,6 +1779,7 @@
NotificationDismissibilityProvider dismissibilityProvider,
MetricsLogger metricsLogger,
NotificationChildrenContainerLogger childrenContainerLogger,
+ ColorUpdateLogger colorUpdateLogger,
SmartReplyConstants smartReplyConstants,
SmartReplyController smartReplyController,
FeatureFlags featureFlags,
@@ -1807,6 +1818,7 @@
mNotificationGutsManager = gutsManager;
mMetricsLogger = metricsLogger;
mChildrenContainerLogger = childrenContainerLogger;
+ mColorUpdateLogger = colorUpdateLogger;
mDismissibilityProvider = dismissibilityProvider;
mFeatureFlags = featureFlags;
}
@@ -2265,7 +2277,7 @@
}
public Animator getTranslateViewAnimator(final float leftTarget,
- AnimatorUpdateListener listener) {
+ AnimatorUpdateListener listener) {
if (mTranslateAnim != null) {
mTranslateAnim.cancel();
}
@@ -2664,6 +2676,7 @@
return getCollapsedHeight();
}
}
+
/**
* @return {@code true} if the notification can show it's heads up layout. This is mostly true
* except for legacy use cases.
@@ -2833,7 +2846,7 @@
@Override
public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
- long duration) {
+ long duration) {
if (getVisibility() == GONE) {
// If we are GONE, the hideSensitive parameter will not be calculated and always be
// false, which is incorrect, let's wait until a real call comes in later.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index 5614f3a..e59829b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -41,6 +41,7 @@
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.SmartReplyController;
+import com.android.systemui.statusbar.notification.ColorUpdateLogger;
import com.android.systemui.statusbar.notification.FeedbackIcon;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider;
@@ -86,6 +87,7 @@
private final SystemClock mClock;
private final String mAppName;
private final String mNotificationKey;
+ private final ColorUpdateLogger mColorUpdateLogger;
private final KeyguardBypassController mKeyguardBypassController;
private final GroupMembershipManager mGroupMembershipManager;
private final GroupExpansionManager mGroupExpansionManager;
@@ -200,6 +202,7 @@
ActivatableNotificationViewController activatableNotificationViewController,
RemoteInputViewSubcomponent.Factory rivSubcomponentFactory,
MetricsLogger metricsLogger,
+ ColorUpdateLogger colorUpdateLogger,
NotificationRowLogger logBufferLogger,
NotificationChildrenContainerLogger childrenContainerLogger,
NotificationListContainer listContainer,
@@ -256,6 +259,7 @@
mDragController = dragController;
mMetricsLogger = metricsLogger;
mChildrenContainerLogger = childrenContainerLogger;
+ mColorUpdateLogger = colorUpdateLogger;
mLogBufferLogger = logBufferLogger;
mSmartReplyConstants = smartReplyConstants;
mSmartReplyController = smartReplyController;
@@ -290,6 +294,7 @@
mDismissibilityProvider,
mMetricsLogger,
mChildrenContainerLogger,
+ mColorUpdateLogger,
mSmartReplyConstants,
mSmartReplyController,
mFeatureFlags,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index ec8e5d7..ea9df9a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.row;
+import static com.android.systemui.Flags.notificationColorUpdateLogger;
+
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.content.res.Configuration;
@@ -54,8 +56,8 @@
public abstract class ExpandableView extends FrameLayout implements Dumpable, Roundable {
private static final String TAG = "ExpandableView";
/** whether the dump() for this class should include verbose details */
- protected static final boolean DUMP_VERBOSE =
- Compile.IS_DEBUG && Log.isLoggable(TAG, Log.VERBOSE);
+ protected static final boolean DUMP_VERBOSE = Compile.IS_DEBUG
+ && (Log.isLoggable(TAG, Log.VERBOSE) || notificationColorUpdateLogger());
private RoundableState mRoundableState = null;
protected OnHeightChangedListener mOnHeightChangedListener;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
index 7ea9b14..ed3a38d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
@@ -36,6 +36,7 @@
import com.android.settingslib.Utils;
import com.android.systemui.Dumpable;
import com.android.systemui.res.R;
+import com.android.systemui.util.DrawableDumpKt;
import java.io.PrintWriter;
import java.util.Arrays;
@@ -333,6 +334,16 @@
pw.println("mActualHeight: " + mActualHeight);
pw.println("mTintColor: " + hexColorString(mTintColor));
pw.println("mRippleColor: " + hexColorString(mRippleColor));
- pw.println("mBackground: " + mBackground);
+ pw.println("mBackground: " + DrawableDumpKt.dumpToString(mBackground));
+ }
+
+ /** create a concise dump of this view's colors */
+ public String toDumpString() {
+ return "<NotificationBackgroundView"
+ + " tintColor=" + hexColorString(mTintColor)
+ + " rippleColor=" + hexColorString(mRippleColor)
+ + " bgColor=" + DrawableDumpKt.getSolidColor(mBackground)
+ + ">";
+
}
}
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 933a780..7925a1c 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
@@ -99,6 +99,7 @@
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.ColorUpdateLogger;
import com.android.systemui.statusbar.notification.FakeShadowView;
import com.android.systemui.statusbar.notification.LaunchAnimationParameters;
import com.android.systemui.statusbar.notification.NotificationTransitionAnimatorController;
@@ -122,6 +123,7 @@
import com.android.systemui.statusbar.policy.ScrollAdapter;
import com.android.systemui.statusbar.policy.SplitShadeStateController;
import com.android.systemui.util.Assert;
+import com.android.systemui.util.ColorUtilKt;
import com.android.systemui.util.DumpUtilsKt;
import com.google.errorprone.annotations.CompileTimeConstant;
@@ -805,8 +807,8 @@
updateBackgroundDimming();
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
- if (child instanceof ActivatableNotificationView) {
- ((ActivatableNotificationView) child).updateBackgroundColors();
+ if (child instanceof ActivatableNotificationView activatableView) {
+ activatableView.updateBackgroundColors();
}
}
}
@@ -4595,6 +4597,13 @@
final @ColorInt int onSurfaceVariant = Utils.getColorAttrDefaultColor(
mContext, com.android.internal.R.attr.materialColorOnSurfaceVariant);
+ ColorUpdateLogger colorUpdateLogger = ColorUpdateLogger.getInstance();
+ if (colorUpdateLogger != null) {
+ colorUpdateLogger.logEvent("NSSL.updateDecorViews()",
+ "onSurface=" + ColorUtilKt.hexColorString(onSurface)
+ + " onSurfaceVariant=" + ColorUtilKt.hexColorString(onSurfaceVariant));
+ }
+
mSectionsManager.setHeaderForegroundColors(onSurface, onSurfaceVariant);
if (mFooterView != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 78e6a79..d2ff266 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -96,6 +96,7 @@
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.notification.ColorUpdateLogger;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.LaunchAnimationParameters;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
@@ -177,6 +178,7 @@
private final ConfigurationController mConfigurationController;
private final ZenModeController mZenModeController;
private final MetricsLogger mMetricsLogger;
+ private final ColorUpdateLogger mColorUpdateLogger;
private final DumpManager mDumpManager;
private final FalsingCollector mFalsingCollector;
@@ -239,6 +241,7 @@
new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
+ mColorUpdateLogger.logTriggerEvent("NSSLC.onViewAttachedToWindow()");
mConfigurationController.addCallback(mConfigurationListener);
if (!FooterViewRefactor.isEnabled()) {
mZenModeController.addCallback(mZenModeControllerCallback);
@@ -254,6 +257,7 @@
@Override
public void onViewDetachedFromWindow(View v) {
+ mColorUpdateLogger.logTriggerEvent("NSSLC.onViewDetachedFromWindow()");
mConfigurationController.removeCallback(mConfigurationListener);
if (!FooterViewRefactor.isEnabled()) {
mZenModeController.removeCallback(mZenModeControllerCallback);
@@ -332,12 +336,16 @@
@Override
public void onUiModeChanged() {
+ mColorUpdateLogger.logTriggerEvent("NSSLC.onUiModeChanged()",
+ "mode=" + mConfigurationController.getNightModeName());
mView.updateBgColor();
mView.updateDecorViews();
}
@Override
public void onThemeChanged() {
+ mColorUpdateLogger.logTriggerEvent("NSSLC.onThemeChanged()",
+ "mode=" + mConfigurationController.getNightModeName());
mView.updateCornerRadius();
mView.updateBgColor();
mView.updateDecorViews();
@@ -719,6 +727,7 @@
ZenModeController zenModeController,
NotificationLockscreenUserManager lockscreenUserManager,
MetricsLogger metricsLogger,
+ ColorUpdateLogger colorUpdateLogger,
DumpManager dumpManager,
FalsingCollector falsingCollector,
FalsingManager falsingManager,
@@ -773,6 +782,7 @@
mZenModeController = zenModeController;
mLockscreenUserManager = lockscreenUserManager;
mMetricsLogger = metricsLogger;
+ mColorUpdateLogger = colorUpdateLogger;
mDumpManager = dumpManager;
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
mFalsingCollector = falsingCollector;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
index 6e8ad2e..dea9416 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
@@ -159,6 +159,15 @@
override fun isLayoutRtl(): Boolean {
return layoutDirection == LAYOUT_DIRECTION_RTL
}
+
+ override fun getNightModeName(): String {
+ return when (uiMode and Configuration.UI_MODE_NIGHT_MASK) {
+ Configuration.UI_MODE_NIGHT_YES -> "night"
+ Configuration.UI_MODE_NIGHT_NO -> "day"
+ Configuration.UI_MODE_NIGHT_UNDEFINED -> "undefined"
+ else -> "err"
+ }
+ }
}
// This could be done with a Collection.filter and Collection.forEach, but Collection.filter
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
index b2ef818..cec77c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
@@ -33,6 +33,9 @@
/** Query the current configuration's layout direction */
boolean isLayoutRtl();
+ /** Logging only; Query the current configuration's night mode name */
+ String getNightModeName();
+
interface ConfigurationListener {
default void onConfigChanged(Configuration newConfig) {}
default void onDensityOrFontScaleChanged() {}
diff --git a/packages/SystemUI/src/com/android/systemui/util/DrawableDump.kt b/packages/SystemUI/src/com/android/systemui/util/DrawableDump.kt
new file mode 100644
index 0000000..0c079a3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/DrawableDump.kt
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2023 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.systemui.util
+
+import android.content.res.ColorStateList
+import android.graphics.BlendMode
+import android.graphics.BlendModeColorFilter
+import android.graphics.ColorFilter
+import android.graphics.LightingColorFilter
+import android.graphics.PorterDuffColorFilter
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.DrawableWrapper
+import android.graphics.drawable.GradientDrawable
+import android.graphics.drawable.LayerDrawable
+import android.graphics.drawable.RippleDrawable
+import android.util.Log
+
+fun dumpToString(drawable: Drawable?): String =
+ if (Compile.IS_DEBUG) StringBuilder().appendDrawable(drawable).toString()
+ else drawable.toString()
+
+fun getSolidColor(drawable: Drawable?): String =
+ if (Compile.IS_DEBUG) hexColorString(getSolidColors(drawable)?.defaultColor)
+ else if (drawable == null) "null" else "?"
+
+private fun getSolidColors(drawable: Drawable?): ColorStateList? {
+ return when (drawable) {
+ is GradientDrawable -> {
+ return drawable.getStateField<ColorStateList>("mSolidColors")
+ }
+ is LayerDrawable -> {
+ for (iLayer in 0 until drawable.numberOfLayers) {
+ getSolidColors(drawable.getDrawable(iLayer))?.let {
+ return it
+ }
+ }
+ null
+ }
+ is DrawableWrapper -> {
+ return getSolidColors(drawable.drawable)
+ }
+ else -> null
+ }
+}
+
+private fun StringBuilder.appendDrawable(drawable: Drawable?): StringBuilder {
+ if (drawable == null) {
+ append("null")
+ return this
+ }
+ append("<")
+ append(drawable.javaClass.simpleName)
+
+ drawable.getStateField<ColorStateList>("mTint", fieldRequired = false)?.let {
+ append(" tint=")
+ appendColors(it)
+ append(" blendMode=")
+ append(drawable.getStateField<BlendMode>("mBlendMode"))
+ }
+ drawable.colorFilter
+ ?.takeUnless { drawable is DrawableWrapper }
+ ?.let {
+ append(" colorFilter=")
+ appendColorFilter(it)
+ }
+ when (drawable) {
+ is DrawableWrapper -> {
+ append(" wrapped=")
+ appendDrawable(drawable.drawable)
+ }
+ is LayerDrawable -> {
+ if (drawable is RippleDrawable) {
+ drawable.getStateField<ColorStateList>("mColor")?.let {
+ append(" color=")
+ appendColors(it)
+ }
+ drawable.effectColor?.let {
+ append(" effectColor=")
+ appendColors(it)
+ }
+ }
+ append(" layers=[")
+ for (iLayer in 0 until drawable.numberOfLayers) {
+ if (iLayer != 0) append(", ")
+ appendDrawable(drawable.getDrawable(iLayer))
+ }
+ append("]")
+ }
+ is GradientDrawable -> {
+ drawable
+ .getStateField<Int>("mShape")
+ ?.takeIf { it != 0 }
+ ?.let {
+ append(" shape=")
+ append(it)
+ }
+ drawable.getStateField<ColorStateList>("mSolidColors")?.let {
+ append(" solidColors=")
+ appendColors(it)
+ }
+ drawable.getStateField<ColorStateList>("mStrokeColors")?.let {
+ append(" strokeColors=")
+ appendColors(it)
+ }
+ drawable.colors?.let {
+ append(" gradientColors=[")
+ it.forEachIndexed { iColor, color ->
+ if (iColor != 0) append(", ")
+ append(hexColorString(color))
+ }
+ append("]")
+ }
+ }
+ }
+ append(">")
+ return this
+}
+
+private inline fun <reified T> Drawable.getStateField(
+ name: String,
+ fieldRequired: Boolean = true
+): T? {
+ val state = this.constantState ?: return null
+ val clazz = state.javaClass
+ return try {
+ val field = clazz.getDeclaredField(name)
+ field.isAccessible = true
+ field.get(state) as T?
+ } catch (ex: Exception) {
+ if (fieldRequired) {
+ Log.w(TAG, "Missing ${clazz.simpleName}.$name: ${T::class.simpleName}", ex)
+ } else if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "Missing ${clazz.simpleName}.$name: ${T::class.simpleName} ($ex)")
+ }
+ null
+ }
+}
+
+private fun Appendable.appendColors(colorStateList: ColorStateList?) {
+ if (colorStateList == null) {
+ append("null")
+ return
+ }
+ val colors = colorStateList.colors
+ if (colors.size == 1) {
+ append(hexColorString(colors[0]))
+ return
+ }
+ append("<ColorStateList size=")
+ append(colors.size.toString())
+ append(" default=")
+ append(hexColorString(colorStateList.defaultColor))
+ append(">")
+}
+
+private fun Appendable.appendColorFilter(colorFilter: ColorFilter?) {
+ if (colorFilter == null) {
+ append("null")
+ return
+ }
+ append("<")
+ append(colorFilter.javaClass.simpleName)
+ when (colorFilter) {
+ is PorterDuffColorFilter -> {
+ append(" color=")
+ append(hexColorString(colorFilter.color))
+ append(" mode=")
+ append(colorFilter.mode.toString())
+ }
+ is BlendModeColorFilter -> {
+ append(" color=")
+ append(hexColorString(colorFilter.color))
+ append(" mode=")
+ append(colorFilter.mode.toString())
+ }
+ is LightingColorFilter -> {
+ append(" multiply=")
+ append(hexColorString(colorFilter.colorMultiply))
+ append(" add=")
+ append(hexColorString(colorFilter.colorAdd))
+ }
+ else -> append(" unhandled")
+ }
+ append(">")
+}
+
+private const val TAG = "DrawableDump"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index 992658a..db455cb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -96,6 +96,7 @@
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewConfigurator;
+import com.android.systemui.keyguard.data.repository.FakeKeyguardClockRepository;
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor;
@@ -354,6 +355,7 @@
protected KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
protected KeyguardClockInteractor mKeyguardClockInteractor;
protected FakeKeyguardRepository mFakeKeyguardRepository;
+ protected FakeKeyguardClockRepository mFakeKeyguardClockRepository;
protected KeyguardInteractor mKeyguardInteractor;
protected ShadeAnimationInteractor mShadeAnimationInteractor;
protected KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
@@ -399,6 +401,8 @@
KeyguardInteractorFactory.create();
mFakeKeyguardRepository = keyguardInteractorDeps.getRepository();
mKeyguardBottomAreaInteractor = new KeyguardBottomAreaInteractor(mFakeKeyguardRepository);
+ mFakeKeyguardClockRepository = new FakeKeyguardClockRepository();
+ mKeyguardClockInteractor = new KeyguardClockInteractor(mFakeKeyguardClockRepository);
mKeyguardInteractor = keyguardInteractorDeps.getKeyguardInteractor();
mShadeRepository = new FakeShadeRepository();
mShadeAnimationInteractor = new ShadeAnimationInteractorLegacyImpl(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinatorTest.kt
index 0830191..b1d2ea21 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinatorTest.kt
@@ -23,6 +23,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener
+import com.android.systemui.statusbar.notification.ColorUpdateLogger
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
@@ -57,6 +58,7 @@
private val lockscreenUserManager: NotificationLockscreenUserManager = mock()
private val gutsManager: NotificationGutsManager = mock()
private val keyguardUpdateMonitor: KeyguardUpdateMonitor = mock()
+ private val colorUpdateLogger: ColorUpdateLogger = mock()
@Before
fun setUp() {
@@ -66,7 +68,9 @@
configurationController,
lockscreenUserManager,
gutsManager,
- keyguardUpdateMonitor)
+ keyguardUpdateMonitor,
+ colorUpdateLogger,
+ )
coordinator.attach(pipeline)
userChangedListener = withArgCaptor {
verify(lockscreenUserManager).addUserChangedListener(capture())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
index 8ac2a33..210b1a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
@@ -34,6 +34,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.SbnBuilder
import com.android.systemui.statusbar.SmartReplyController
+import com.android.systemui.statusbar.notification.ColorUpdateLogger
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider
@@ -82,6 +83,7 @@
private val rivSubComponentFactory: RemoteInputViewSubcomponent.Factory = mock()
private val metricsLogger: MetricsLogger = mock()
private val logBufferLogger = NotificationRowLogger(logcatLogBuffer(), logcatLogBuffer())
+ private val colorUpdateLogger: ColorUpdateLogger = mock()
private val listContainer: NotificationListContainer = mock()
private val childrenContainer: NotificationChildrenContainer = mock()
private val smartReplyConstants: SmartReplyConstants = mock()
@@ -117,6 +119,7 @@
activableNotificationViewController,
rivSubComponentFactory,
metricsLogger,
+ colorUpdateLogger,
logBufferLogger,
NotificationChildrenContainerLogger(logcatLogBuffer()),
listContainer,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index c717991..e78081f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -65,6 +65,7 @@
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.SmartReplyController;
+import com.android.systemui.statusbar.notification.ColorUpdateLogger;
import com.android.systemui.statusbar.notification.ConversationNotificationProcessor;
import com.android.systemui.statusbar.notification.SourceType;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -607,6 +608,7 @@
mDismissibilityProvider,
mock(MetricsLogger.class),
new NotificationChildrenContainerLogger(logcatLogBuffer()),
+ mock(ColorUpdateLogger.class),
mock(SmartReplyConstants.class),
mock(SmartReplyController.class),
mFeatureFlags,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index 354f3f6..f2ef4e1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -78,6 +78,7 @@
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.notification.ColorUpdateLogger;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -148,6 +149,7 @@
@Mock private PrimaryBouncerInteractor mPrimaryBouncerInteractor;
@Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
@Mock private MetricsLogger mMetricsLogger;
+ @Mock private ColorUpdateLogger mColorUpdateLogger;
@Mock private DumpManager mDumpManager;
@Mock(answer = Answers.RETURNS_SELF)
private NotificationSwipeHelper.Builder mNotificationSwipeHelperBuilder;
@@ -1007,6 +1009,7 @@
mZenModeController,
mNotificationLockscreenUserManager,
mMetricsLogger,
+ mColorUpdateLogger,
mDumpManager,
new FalsingCollectorFake(),
new FalsingManagerFake(),
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
index f7e9a11..566fc25 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
@@ -21,12 +21,16 @@
import com.android.systemui.communal.data.repository.communalRepository
import com.android.systemui.communal.data.repository.communalWidgetRepository
import com.android.systemui.communal.widgets.EditWidgetsActivityStarter
+import com.android.systemui.flags.Flags
+import com.android.systemui.flags.fakeFeatureFlagsClassic
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.log.logcatLogBuffer
import com.android.systemui.smartspace.data.repository.smartspaceRepository
+import com.android.systemui.user.data.repository.fakeUserRepository
import com.android.systemui.util.mockito.mock
val Kosmos.communalInteractor by Fixture {
@@ -47,3 +51,14 @@
}
val Kosmos.editWidgetsActivityStarter by Fixture<EditWidgetsActivityStarter> { mock() }
+
+suspend fun Kosmos.setCommunalAvailable(available: Boolean) {
+ fakeFeatureFlagsClassic.set(Flags.COMMUNAL_SERVICE_ENABLED, available)
+ if (available) {
+ fakeUserRepository.asMainUser()
+ with(fakeKeyguardRepository) {
+ setIsEncryptedOrLockdown(false)
+ setKeyguardShowing(true)
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt
index c51de33..46a1053 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt
@@ -43,6 +43,7 @@
}
override fun isLayoutRtl(): Boolean = isRtl
+ override fun getNightModeName(): String = "undefined"
}
@Module
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
index 1124425..931a59d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
@@ -39,13 +39,19 @@
// User id to represent a non system (human) user id. We presume this is the main user.
private const val MAIN_USER_ID = 10
- private val DEFAULT_SELECTED_USER = 0
+ private const val DEFAULT_SELECTED_USER = 0
private val DEFAULT_SELECTED_USER_INFO =
UserInfo(
/* id= */ DEFAULT_SELECTED_USER,
/* name= */ "default selected user",
/* flags= */ 0,
)
+ private val MAIN_USER =
+ UserInfo(
+ /* id= */ MAIN_USER_ID,
+ /* name= */ "main user",
+ /* flags= */ UserInfo.FLAG_MAIN,
+ )
}
private val _userSwitcherSettings = MutableStateFlow(UserSwitcherSettingsModel())
@@ -113,6 +119,13 @@
yield()
}
+ /** Makes the current user [MAIN_USER]. */
+ suspend fun asMainUser(): UserInfo {
+ setUserInfos(listOf(MAIN_USER))
+ setSelectedUserInfo(MAIN_USER)
+ return MAIN_USER
+ }
+
suspend fun setSettings(settings: UserSwitcherSettingsModel) {
_userSwitcherSettings.value = settings
yield()
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeConfigurationController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeConfigurationController.java
index 516eb6e..111c40d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeConfigurationController.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeConfigurationController.java
@@ -38,4 +38,9 @@
public boolean isLayoutRtl() {
return false;
}
+
+ @Override
+ public String getNightModeName() {
+ return "undefined";
+ }
}
diff --git a/services/core/java/com/android/server/input/debug/FocusEventDebugView.java b/services/core/java/com/android/server/input/debug/FocusEventDebugView.java
index 6eec0de..3ffd2e1 100644
--- a/services/core/java/com/android/server/input/debug/FocusEventDebugView.java
+++ b/services/core/java/com/android/server/input/debug/FocusEventDebugView.java
@@ -34,6 +34,7 @@
import android.util.TypedValue;
import android.view.Gravity;
import android.view.InputDevice;
+import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.RoundedCorner;
@@ -335,7 +336,15 @@
final int unicodeChar = event.getUnicodeChar();
if (unicodeChar != 0) {
- return new String(Character.toChars(unicodeChar));
+ if ((unicodeChar & KeyCharacterMap.COMBINING_ACCENT) != 0) {
+ // Show combining character
+ final int combiningChar = KeyCharacterMap.getCombiningChar(
+ unicodeChar & KeyCharacterMap.COMBINING_ACCENT_MASK);
+ // Return the Unicode dotted circle as part of the label as it is used is used to
+ // illustrate the effect of a combining marks
+ return "\u25cc" + String.valueOf((char) combiningChar);
+ }
+ return String.valueOf((char) unicodeChar);
}
final var label = KeyEvent.keyCodeToString(event.getKeyCode());
diff --git a/services/core/java/com/android/server/pdb/PersistentDataBlockService.java b/services/core/java/com/android/server/pdb/PersistentDataBlockService.java
index 133fc8f..59d3d17 100644
--- a/services/core/java/com/android/server/pdb/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/pdb/PersistentDataBlockService.java
@@ -143,7 +143,8 @@
// Magic number to mark block device as adhering to the format consumed by this service
private static final int PARTITION_TYPE_MARKER = 0x19901873;
/** Size of the block reserved for FRP credential, including 4 bytes for the size header. */
- private static final int FRP_CREDENTIAL_RESERVED_SIZE = 1000;
+ @VisibleForTesting
+ static final int FRP_CREDENTIAL_RESERVED_SIZE = 1000;
/** Maximum size of the FRP credential handle that can be stored. */
@VisibleForTesting
static final int MAX_FRP_CREDENTIAL_HANDLE_SIZE = FRP_CREDENTIAL_RESERVED_SIZE - 4;
@@ -158,7 +159,8 @@
/**
* Size of the block reserved for Test Harness Mode data, including 4 bytes for the size header.
*/
- private static final int TEST_MODE_RESERVED_SIZE = 10000;
+ @VisibleForTesting
+ static final int TEST_MODE_RESERVED_SIZE = 10000;
/** Maximum size of the Test Harness Mode data that can be stored. */
@VisibleForTesting
static final int MAX_TEST_MODE_DATA_SIZE = TEST_MODE_RESERVED_SIZE - 4;
@@ -393,7 +395,8 @@
return totalDataSize;
}
- private long getBlockDeviceSize() {
+ @VisibleForTesting
+ long getBlockDeviceSize() {
synchronized (mLock) {
if (mBlockDeviceSize == -1) {
if (mIsFileBacked) {
@@ -553,26 +556,33 @@
channel.write(buf);
channel.force(true);
- // 3. skip the test mode data and leave it unformatted.
+ // 3. Write the default FRP secret (all zeros).
+ if (mFrpEnforced) {
+ Slog.i(TAG, "Writing FRP secret magic");
+ channel.write(ByteBuffer.wrap(FRP_SECRET_MAGIC));
+
+ Slog.i(TAG, "Writing default FRP secret");
+ channel.write(ByteBuffer.allocate(FRP_SECRET_SIZE));
+ channel.force(true);
+
+ mFrpActive = false;
+ }
+
+ // 4. skip the test mode data and leave it unformatted.
// This is for a feature that enables testing.
channel.position(channel.position() + TEST_MODE_RESERVED_SIZE);
- // 4. wipe the FRP_CREDENTIAL explicitly
+ // 5. wipe the FRP_CREDENTIAL explicitly
buf = ByteBuffer.allocate(FRP_CREDENTIAL_RESERVED_SIZE);
channel.write(buf);
channel.force(true);
- // 5. set unlock = 0 because it's a formatPartitionLocked
+ // 6. set unlock = 0 because it's a formatPartitionLocked
buf = ByteBuffer.allocate(FRP_CREDENTIAL_RESERVED_SIZE);
buf.put((byte)0);
buf.flip();
channel.write(buf);
channel.force(true);
-
- // 6. Write the default FRP secret (all zeros).
- if (mFrpEnforced) {
- writeFrpMagicAndDefaultSecret();
- }
} catch (IOException e) {
Slog.e(TAG, "failed to format block", e);
return;
@@ -616,7 +626,7 @@
// version. If so, we deactivate FRP and set the secret to the default value.
if (isUpgradingFromPreVRelease()) {
Slog.w(TAG, "Upgrading from Android 14 or lower, defaulting FRP secret");
- writeFrpMagicAndDefaultSecret();
+ writeFrpMagicAndDefaultSecretLocked();
mFrpActive = false;
return true;
}
@@ -630,7 +640,7 @@
try {
return deactivateFrp(Files.readAllBytes(Paths.get(frpSecretFile)));
} catch (IOException e) {
- Slog.w(TAG, "Failed to read FRP secret file: " + frpSecretFile + " "
+ Slog.i(TAG, "Failed to read FRP secret file: " + frpSecretFile + " "
+ e.getClass().getSimpleName());
return false;
}
@@ -653,7 +663,8 @@
}
/**
- * Write the provided secret to the FRP secret file in /data and to the /persist partition.
+ * Write the provided secret to the FRP secret file in /data and to the persistent data block
+ * partition.
*
* Writing is a three-step process, to ensure that we can recover from a crash at any point.
*/
@@ -713,7 +724,7 @@
synchronized (mLock) {
if (!hasFrpSecretMagic()) {
Slog.i(TAG, "No FRP secret magic, system must have been upgraded.");
- writeFrpMagicAndDefaultSecret();
+ writeFrpMagicAndDefaultSecretLocked();
}
}
@@ -735,11 +746,9 @@
}
}
- private void writeFrpMagicAndDefaultSecret() {
+ private void writeFrpMagicAndDefaultSecretLocked() {
try (FileChannel channel = getBlockOutputChannelIgnoringFrp()) {
synchronized (mLock) {
- // Write secret first in case we crash between the writes, causing the first write
- // to be synced but the second to be lost.
Slog.i(TAG, "Writing default FRP secret");
channel.position(getFrpSecretDataOffset());
channel.write(ByteBuffer.allocate(FRP_SECRET_SIZE));
@@ -755,6 +764,7 @@
} catch (IOException e) {
Slog.e(TAG, "Failed to write FRP magic and default secret", e);
}
+ computeAndWriteDigestLocked();
}
@VisibleForTesting
@@ -879,7 +889,7 @@
if (printSecret) {
try {
pw.println("FRP secret in " + frpSecretFile + ": " + HexFormat.of()
- .formatHex(Files.readAllBytes(Paths.get(mFrpSecretFile))));
+ .formatHex(Files.readAllBytes(Paths.get(frpSecretFile))));
} catch (IOException e) {
Slog.e(TAG, "Failed to read " + frpSecretFile, e);
}
@@ -1230,6 +1240,7 @@
@Override
public boolean setFactoryResetProtectionSecret(byte[] secret) {
+ enforceConfigureFrpPermission();
enforceUid(Binder.getCallingUid());
if (secret == null || secret.length != FRP_SECRET_SIZE) {
throw new IllegalArgumentException(
diff --git a/services/core/java/com/android/server/pm/PackageArchiver.java b/services/core/java/com/android/server/pm/PackageArchiver.java
index a64d1ae..05e8f9a 100644
--- a/services/core/java/com/android/server/pm/PackageArchiver.java
+++ b/services/core/java/com/android/server/pm/PackageArchiver.java
@@ -122,6 +122,7 @@
public class PackageArchiver {
private static final String TAG = "PackageArchiverService";
+ private static final boolean DEBUG = true;
public static final String EXTRA_UNARCHIVE_INTENT_SENDER =
"android.content.pm.extra.UNARCHIVE_INTENT_SENDER";
@@ -362,6 +363,10 @@
// TODO(b/319238030) Move this into installd.
if (!FileUtils.deleteContentsAndDir(iconsDir)) {
Slog.e(TAG, "Failed to clean up archive files for " + packageName);
+ } else {
+ if (DEBUG) {
+ Slog.e(TAG, "Deleted icons at " + iconsDir.getAbsolutePath());
+ }
}
});
}
@@ -524,6 +529,9 @@
}
out.flush();
}
+ if (DEBUG && iconFile.exists()) {
+ Slog.i(TAG, "Stored icon at " + iconFile.getAbsolutePath());
+ }
return iconFile.toPath();
}
@@ -1194,6 +1202,9 @@
if (!iconsDir.isDirectory()) {
throw new IOException("Unable to create directory " + iconsDir);
}
+ if (DEBUG) {
+ Slog.i(TAG, "Created icons directory at " + iconsDir.getAbsolutePath());
+ }
}
SELinux.restorecon(iconsDir);
return iconsDir;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 29242aa..fe65010 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -5358,9 +5358,16 @@
pw.println(sdf.format(date));
if (pus.getArchiveState() != null) {
+ final ArchiveState archiveState = pus.getArchiveState();
pw.print(" archiveTime=");
- date.setTime(pus.getArchiveState().getArchiveTimeMillis());
+ date.setTime(archiveState.getArchiveTimeMillis());
pw.println(sdf.format(date));
+ pw.print(" unarchiveInstallerTitle=");
+ pw.println(archiveState.getInstallerTitle());
+ for (ArchiveState.ArchiveActivityInfo activity : archiveState.getActivityInfos()) {
+ pw.print(" archiveActivityInfo=");
+ pw.println(activity.toString());
+ }
}
pw.print(" uninstallReason=");
@@ -5475,10 +5482,6 @@
}
}
}
- ArchiveState archiveState = userState.getArchiveState();
- if (archiveState != null) {
- pw.print(archiveState.toString());
- }
}
}
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java
index 8637d91..b3c8b0b 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java
@@ -85,6 +85,7 @@
private final SystemInterface mSystemInterface;
private final Context mContext;
+ private final WebViewProviderInfo mDefaultProvider;
private long mMinimumVersionCode = -1;
@@ -105,6 +106,16 @@
WebViewUpdateServiceImpl2(Context context, SystemInterface systemInterface) {
mContext = context;
mSystemInterface = systemInterface;
+ WebViewProviderInfo[] webviewProviders = getWebViewPackages();
+ for (WebViewProviderInfo provider : webviewProviders) {
+ if (provider.availableByDefault) {
+ mDefaultProvider = provider;
+ break;
+ }
+ }
+ // This should be unreachable because the config parser enforces that there is at least one
+ // availableByDefault provider.
+ throw new AndroidRuntimeException("No available by default WebView Provider.");
}
@Override
@@ -163,11 +174,10 @@
if (mCurrentWebViewPackage == null) {
return true;
}
- WebViewProviderInfo defaultProvider = getDefaultWebViewPackage();
- if (mCurrentWebViewPackage.packageName.equals(defaultProvider.packageName)) {
+ if (mCurrentWebViewPackage.packageName.equals(mDefaultProvider.packageName)) {
List<UserPackage> userPackages =
mSystemInterface.getPackageInfoForProviderAllUsers(
- mContext, defaultProvider);
+ mContext, mDefaultProvider);
return !isInstalledAndEnabledForAllUsers(userPackages);
} else {
return false;
@@ -200,13 +210,12 @@
// default package for all users in case it was disabled, even if we already did the
// one-time migration before. If this actually changes the state, we will see the
// PackageManager broadcast shortly and try again.
- WebViewProviderInfo defaultProvider = getDefaultWebViewPackage();
Slog.w(
TAG,
"No provider available for all users, trying to enable "
- + defaultProvider.packageName);
+ + mDefaultProvider.packageName);
mSystemInterface.enablePackageForAllUsers(
- mContext, defaultProvider.packageName, true);
+ mContext, mDefaultProvider.packageName, true);
}
} catch (Throwable t) {
@@ -398,15 +407,7 @@
*/
@Override
public WebViewProviderInfo getDefaultWebViewPackage() {
- WebViewProviderInfo[] webviewProviders = getWebViewPackages();
- for (WebViewProviderInfo provider : webviewProviders) {
- if (provider.availableByDefault) {
- return provider;
- }
- }
- // This should be unreachable because the config parser enforces that there is at least one
- // availableByDefault provider.
- throw new AndroidRuntimeException("No available by default WebView Provider.");
+ return mDefaultProvider;
}
private static class ProviderAndPackageInfo {
@@ -467,14 +468,13 @@
// User did not choose, or the choice failed; return the default provider even if it is not
// installed or enabled for all users.
- WebViewProviderInfo defaultProvider = getDefaultWebViewPackage();
try {
- PackageInfo packageInfo = mSystemInterface.getPackageInfoForProvider(defaultProvider);
- if (validityResult(defaultProvider, packageInfo) == VALIDITY_OK) {
+ PackageInfo packageInfo = mSystemInterface.getPackageInfoForProvider(mDefaultProvider);
+ if (validityResult(mDefaultProvider, packageInfo) == VALIDITY_OK) {
return packageInfo;
}
} catch (NameNotFoundException e) {
- Slog.w(TAG, "Default WebView package (" + defaultProvider.packageName + ") not found");
+ Slog.w(TAG, "Default WebView package (" + mDefaultProvider.packageName + ") not found");
}
// This should never happen during normal operation (only with modified system images).
diff --git a/services/tests/servicestests/src/com/android/server/pdb/PersistentDataBlockServiceTest.java b/services/tests/servicestests/src/com/android/server/pdb/PersistentDataBlockServiceTest.java
index da8ec2e..f91f77a 100644
--- a/services/tests/servicestests/src/com/android/server/pdb/PersistentDataBlockServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pdb/PersistentDataBlockServiceTest.java
@@ -17,12 +17,17 @@
package com.android.server.pdb;
import static com.android.server.pdb.PersistentDataBlockService.DIGEST_SIZE_BYTES;
+import static com.android.server.pdb.PersistentDataBlockService.FRP_CREDENTIAL_RESERVED_SIZE;
+import static com.android.server.pdb.PersistentDataBlockService.FRP_SECRET_MAGIC;
import static com.android.server.pdb.PersistentDataBlockService.FRP_SECRET_SIZE;
+import static com.android.server.pdb.PersistentDataBlockService.HEADER_SIZE;
import static com.android.server.pdb.PersistentDataBlockService.MAX_DATA_BLOCK_SIZE;
import static com.android.server.pdb.PersistentDataBlockService.MAX_FRP_CREDENTIAL_HANDLE_SIZE;
import static com.android.server.pdb.PersistentDataBlockService.MAX_TEST_MODE_DATA_SIZE;
+import static com.android.server.pdb.PersistentDataBlockService.TEST_MODE_RESERVED_SIZE;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -36,6 +41,7 @@
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import android.Manifest;
+import android.annotation.NonNull;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Binder;
@@ -63,6 +69,7 @@
import java.nio.file.StandardOpenOption;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
@RunWith(JUnitParamsRunner.class)
public class PersistentDataBlockServiceTest {
@@ -397,6 +404,68 @@
@Test
@Parameters({"false", "true"})
+ public void testPartitionFormat(boolean frpEnabled) throws Exception {
+ setUp(frpEnabled);
+
+ /*
+ * 1. Fill the PDB with a specific value, so we can check regions that weren't touched
+ * by formatting
+ */
+ FileChannel channel = FileChannel.open(mDataBlockFile.toPath(), StandardOpenOption.WRITE,
+ StandardOpenOption.TRUNCATE_EXISTING);
+ byte[] bufArray = new byte[(int) mPdbService.getBlockDeviceSize()];
+ Arrays.fill(bufArray, (byte) 0x7f);
+ ByteBuffer buf = ByteBuffer.wrap(bufArray);
+ channel.write(buf);
+ channel.close();
+
+ /*
+ * 2. Format it.
+ */
+ mPdbService.formatPartitionLocked(true);
+
+ /*
+ * 3. Check it.
+ */
+ channel = FileChannel.open(mDataBlockFile.toPath(), StandardOpenOption.READ);
+
+ // 3a. Skip the digest and header
+ channel.position(channel.position() + DIGEST_SIZE_BYTES + HEADER_SIZE);
+
+ // 3b. Check the FRP data segment
+ assertContains("FRP data", readData(channel, mPdbService.getMaximumFrpDataSize()).array(),
+ (byte) 0);
+
+ if (frpEnabled) {
+ // 3c. The FRP secret magic & value
+ assertThat(mPdbService.getFrpSecretMagicOffset()).isEqualTo(channel.position());
+ assertThat(readData(channel, FRP_SECRET_MAGIC.length).array()).isEqualTo(
+ FRP_SECRET_MAGIC);
+
+ assertThat(mPdbService.getFrpSecretDataOffset()).isEqualTo(channel.position());
+ assertContains("FRP secret", readData(channel, FRP_SECRET_SIZE).array(), (byte) 0);
+ }
+
+ // 3d. The test mode data (unmodified by formatPartitionLocked()).
+ assertThat(mPdbService.getTestHarnessModeDataOffset()).isEqualTo(channel.position());
+ assertContains("Test data", readData(channel, TEST_MODE_RESERVED_SIZE).array(),
+ (byte) 0x7f);
+
+ // 3e. The FRP credential segment
+ assertThat(mPdbService.getFrpCredentialDataOffset()).isEqualTo(channel.position());
+ assertContains("FRP credential", readData(channel, FRP_CREDENTIAL_RESERVED_SIZE).array(),
+ (byte) 0);
+
+ // 3f. OEM unlock byte.
+ assertThat(mPdbService.getOemUnlockDataOffset()).isEqualTo(channel.position());
+ assertThat(new byte[]{1}).isEqualTo(readData(channel, 1).array());
+
+ // 3g. EOF
+ assertThat(channel.position()).isEqualTo(channel.size());
+ }
+
+ @Test
+ @Parameters({"false", "true"})
public void wipePermissionCheck(boolean frpEnabled) throws Exception {
setUp(frpEnabled);
denyOemUnlockPermission();
@@ -987,4 +1056,20 @@
return buffer;
}
}
+
+ @NonNull
+ private static ByteBuffer readData(FileChannel channel, int length) throws IOException {
+ ByteBuffer buf = ByteBuffer.allocate(length);
+ assertThat(channel.read(buf)).isEqualTo(length);
+ buf.flip();
+ assertThat(buf.limit()).isEqualTo(length);
+ return buf;
+ }
+
+ private static void assertContains(String sectionName, byte[] buf, byte expected) {
+ for (int i = 0; i < buf.length; i++) {
+ assertWithMessage(sectionName + " is incorrect at offset " + i)
+ .that(buf[i]).isEqualTo(expected);
+ }
+ }
}