Status Update
Comments
ch...@google.com <ch...@google.com> #2
This is a particularly hard device to come by - do you happen to have access to the device? If so could you provide us with the output of: adb shell dumpsys media.camera > info.txt
Thanks!
at...@monzo.com <at...@monzo.com> #3
Stacktrace:
Caused by: java.lang.IllegalArgumentException: Can not get supported output size under supported maximum for the format: 34
at androidx.camera.camera2.internal.SupportedSurfaceCombination.getSupportedOutputSizes(SupportedSurfaceCombination.java:355)
at androidx.camera.camera2.internal.SupportedSurfaceCombination.getSuggestedResolutions(SupportedSurfaceCombination.java:197)
at androidx.camera.camera2.internal.Camera2DeviceSurfaceManager.getSuggestedResolutions(Camera2DeviceSurfaceManager.java:198)
at androidx.camera.core.CameraX.calculateSuggestedResolutions(CameraX.java:943)
at androidx.camera.core.CameraX.bindToLifecycle(CameraX.java:293)
at androidx.camera.lifecycle.ProcessCameraProvider.bindToLifecycle(ProcessCameraProvider.java:227)
Below are some findings based on our debugging
When Dex is connected
previewConfig.getMaxResolution() is returning "731x411" as maxSize.
Inside Preview.Builder.build() -> Default_MAX_resolution is set to "CameraX.getSurfaceManager().getPreviewSize()" which is 731x411
this is being picked as maxSize.
While rendering maxSize is 731x411 and minSize is 640x480 and below are available outputSizes
0 = {Size@11860} "4032x3024"
1 = {Size@11861} "3984x2988"
2 = {Size@11862} "4032x2268"
3 = {Size@11863} "3024x3024"
4 = {Size@11864} "2976x2976"
5 = {Size@11865} "3840x2160"
6 = {Size@11866} "3264x2448"
7 = {Size@11867} "4032x1960"
8 = {Size@11868} "2880x2160"
9 = {Size@11869} "3264x1836"
10 = {Size@11870} "2160x2160"
11 = {Size@11871} "2560x1440"
12 = {Size@11872} "2224x1080"
13 = {Size@11873} "2048x1152"
14 = {Size@11874} "1920x1080"
15 = {Size@11875} "1440x1080"
16 = {Size@11876} "1088x1088"
17 = {Size@11877} "1280x720"
18 = {Size@11878} "1024x768"
19 = {Size@11879} "1056x704"
20 = {Size@11880} "960x720"
21 = {Size@11881} "960x540"
22 = {Size@11882} "720x720"
23 = {Size@11883} "800x450"
24 = {Size@11884} "720x480"
25 = {Size@11885} "640x480"
26 = {Size@11886} "352x288"
27 = {Size@11887} "320x240"
28 = {Size@11888} "256x144"
29 = {Size@11889} "176x144"
and couldn't find any size in this range.
When Dex not connected
minsize = 640x480
maxsize = 1920x1080
0 = {Size@11836} "4032x3024"
1 = {Size@11837} "3984x2988"
2 = {Size@11838} "4032x2268"
3 = {Size@11839} "3024x3024"
4 = {Size@11840} "2976x2976"
5 = {Size@11841} "3840x2160"
6 = {Size@11842} "3264x2448"
7 = {Size@11843} "4032x1960"
8 = {Size@11844} "2880x2160"
9 = {Size@11845} "3264x1836"
10 = {Size@11846} "2160x2160"
11 = {Size@11847} "2560x1440"
12 = {Size@11848} "2224x1080"
13 = {Size@11849} "2048x1152"
14 = {Size@11850} "1920x1080"
15 = {Size@11851} "1440x1080"
16 = {Size@11852} "1088x1088"
17 = {Size@11853} "1280x720"
18 = {Size@11854} "1024x768"
19 = {Size@11855} "1056x704"
20 = {Size@11856} "960x720"
21 = {Size@11857} "960x540"
22 = {Size@11858} "720x720"
23 = {Size@11859} "800x450"
24 = {Size@11860} "720x480"
25 = {Size@11861} "640x480"
26 = {Size@11862} "352x288"
27 = {Size@11863} "320x240"
28 = {Size@11864} "256x144"
29 = {Size@11865} "176x144"
and we have 12 available sizes in this range
Camera2DeviceSurfaceManager.java:: getPreviewSize()
mCameraSupportedSurfaceCombinationMap.get(cameraId).getSurfaceDefinition().getPreviewSize() = "1920x1080"
cameraId=0
ch...@google.com <ch...@google.com> #4
The issue root cause is that CameraX will default filter out sizes smaller than 640x480. For Preview, the max size will be limited to under display size. I checked the HW spec info for the issue related devices. Display size of FUJITSU F-04J/F-05J is 360x640. That will result int that no size exists in the conditions that is larger or equal to 640x480 and smaller or equal to 360x640.
A temporary workaround for this situation is to use Preview.Builder#setTargetResolution() to set a size smaller than 640x480 to bypass the problem.
For device FUJITSU arrowsM04, I checked its HW spec info and its display size I found is 1280x720. It seems that the problem should not exist in the device.
Could you confirm that the problem exist on arrowsM04 device? What will be the returned value when using Display#getRealSize to obtain the display size?
he...@ataulm.com <he...@ataulm.com> #5
> A temporary workaround for this situation is to use Preview.Builder#setTargetResolution() to set a size smaller than 640x480 to bypass the problem.
OK. I will try it.
> Could you confirm that the problem exist on arrowsM04 device?
We receive the crash report (Crashlytics) that this crash has occurred on arrowsM04.
We don't have this device so we can't confirm that the problem really exist on arrowsM04.
> What will be the returned value when using Display#getRealSize to obtain the display size?
We can't investigate it for the same reason.
Thank you.
at...@monzo.com <at...@monzo.com> #6
This issue happened on devices that the display size is smaller than 640x480. In original auto-resolution mechanism, supported sizes smaller than 640x480 will be default filter out.
The auto-resolution mechanism encodes the guaranteed configurations tables in CameraDevice#createCaptureSession(SessionConfiguration). It defines that the PREVIEW size is the small one of the device display size and 1080p. The PREVIEW size will be the maximal size limitation for Preview use case. The reason it limits the size to display size and 1080p is the stream output in display size or 1080p has been able to provide good enough preview quality. Therefore, auto-resolution mechanism will limit the selected size to be smaller than the small one of the device display size and 1080p.
With above two conditions, in this issue, all sizes smaller than 640x480 have been filter out, therefore, there is no size smaller than the display size 320x240 can be selected to use. And cause the exception.
Solution:
When the display size is smaller than 640x480, auto-resolution mechanism won't filter out those small sizes smaller than 640x480. This makes those small size be left and can be selected for the Preview use case on small display devices.
The solution has been merged and will be included in next CameraX release.
at...@monzo.com <at...@monzo.com> #7
Hello.
This crash still occurs.
- CAMERAX VERSION: 1.0.0-beta4
- ANDROID OS BUILD NUMBER: Android 7.1.1
- DEVICE NAME: FUJITSU F-02H
We receive following crash report from FUJITSU F-02H. So far We have received this crash report only from F-02H.
java.lang.IllegalArgumentException
Can not get supported output size under supported maximum for the format: 34
androidx.camera.camera2.internal.SupportedSurfaceCombination.getSupportedOutputSizes (SupportedSurfaceCombination.java:349)
androidx.camera.camera2.internal.SupportedSurfaceCombination.getSuggestedResolutions (SupportedSurfaceCombination.java:197)
androidx.camera.camera2.internal.Camera2DeviceSurfaceManager.getSuggestedResolutions (Camera2DeviceSurfaceManager.java:198)
androidx.camera.core.CameraX.calculateSuggestedResolutions (CameraX.java:949)
androidx.camera.core.CameraX.bindToLifecycle (CameraX.java:351)
androidx.camera.lifecycle.ProcessCameraProvider.bindToLifecycle (ProcessCameraProvider.java:230)
(our application's package name).CameraFragment.bindCameraUseCases (CameraFragment.java:174)
ch...@google.com <ch...@google.com> #8
Could you help to provide the following information to clarify the issue?
1. Is the full name of the device Fujitsu Arrows NX F-02H that has a 1440x2560 display?
2. Please help to provide the supported output sizes of ImageFormat.PRIVATE that is obtained by StreamConfigurationMap#getOutputSizes(int).
he...@ataulm.com <he...@ataulm.com> #9
- Is the full name of the device Fujitsu Arrows NX F-02H that has a 1440x2560 display?
Yes
- Please help to provide the supported output sizes of ImageFormat.PRIVATE that is obtained by StreamConfigurationMap#getOutputSizes(int).
Since we don't have this device, we'll try to collect this information in the next version of our app. The next version will be released later this month.
ki...@google.com <ki...@google.com> #10
Hello.
- Please help to provide the supported output sizes of ImageFormat.PRIVATE that is obtained by StreamConfigurationMap#getOutputSizes(int).
We have collected the output of the device where the crash occurs.
Device1
- Model : arrows Be F-05J
- Android Version : 7.1.1
- Supported output sizes of ImageFormat.PRIVATE
CameraId 0: 480x480
CameraId 1: 2048x1536 ,1920x1080 ,1280x720 ,960x720 ,640x480 ,320x240 ,176x144
Device2
- Model : Fujitsu arrows M04
- Android Version : 7.1.1
- Supported output sizes of ImageFormat.PRIVATE
CameraId 0: 480x480
CameraId 1: 2048x1536 ,1920x1080 ,1280x720 ,960x720 ,640x480 ,320x240 ,176x144
Additional Information
CameraX version : 1.0.0-beta04
We collect the supported output sizes by following code.
val errorString = buildString {
append("The supported output sizes of ImageFormat.PRIVATE: ")
(requireContext().getSystemService(Context.CAMERA_SERVICE) as CameraManager).apply {
cameraIdList.forEachIndexed { index, cameraId ->
val msg = if (VERSION.SDK_INT >= VERSION_CODES.M) {
val configurationMap =
getCameraCharacteristics(cameraId).get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
val sizes = configurationMap?.getOutputSizes(ImageFormat.PRIVATE)
"CameraId $index: ${sizes?.joinToString(" ,")}"
} else {
"CameraId $index: This device version is under M."
}
append(msg)
}
}
}
he...@ataulm.com <he...@ataulm.com> #11
he...@ataulm.com <he...@ataulm.com> #12
I tried to find the device specs and both 720x1280
size display. For the camera id 0 device, it is a different case that the display size is larger than 640x480
but the device only supports a 480x480
size. The case also caused the same IllegalArgumentException and was also fixed by 1.0.0-beta04
release. Before 480x480
size would be filtered out and then caused the IllegalArgumentException. After it was merged, the 640x480
size threshold was removed and then the 480x480
size would be kept and selected to use.
It looks like 1.0.0-beta04
release had been used to collect the supported sizes information. But the issue should have been fixed by 1.0.0-beta04
release. Did you only check the device model name to collect the supported sizes information or collect the information when the IllegalArgumentException issue happens again?
CameraX's 1.0.0-beta04
version. Maybe you can also consider to upgrade to the latest 1.0.0-rc01
version for your application. Thanks.
ch...@google.com <ch...@google.com> #13
Did you only check the device model name to collect the supported sizes information or collect the information when the IllegalArgumentException issue happens again?
We collect informations only from the device on which IllegalArgumentException happened.
Our latest app uses CameraX version 1.0.0-beta10
and this issue still occurres.
However we don't receive crash report from Fujitsu arrows Be F-05J
or Fujitsu arrows M04
so far. (This doesn't mean this issue is fixed on these devices because our app is heavily rely on camera so these device's user wouldn't use our app anymore.)
Instead, we receive crash report from
- Model : Fujitsu F-03K
- Android Version : 7.1.2
- Supported output sizes of ImageFormat.PRIVATE
CameraId 0 : 480x480
CameraId 1 : 2048x1536 ,1920x1080 ,1280x720 ,960x720 ,640x480 ,320x240 ,176x144
al...@google.com <al...@google.com> #14
I missed some settings when I simulated the issue by robolectric test so that I was not able to reproduce it. Now, I can reproduce the issue if the device only supports one 480x480 resolution. I'm working on the solution and target to make it included in next release.
ki...@google.com <ki...@google.com> #15
Branch: androidx-main
commit 69d15dff7bb857ee33a0f643ff42a0f8bc475ab2
Author: charcoalchen <charcoalchen@google.com>
Date: Fri Jan 08 18:30:03 2021
Fixed IllegalArgumentException issue happened when all preview supported sizes are smaller than 640x480 and display size is larger than 640x480.
Do not filter out sizes smaller than 640x480 when all preview supported sizes are smaller than 640x480 and display size is larger than 640x480.
Relnote:"Fixed IllegalArgumentException issue happened when all preview supported sizes are smaller than 640x480 and display size is larger than 640x480."
Bug: 150506192
Test: SupportedSurfaceCombinationTest
Change-Id: I2a63ce8e2ad42a9cc060c8635ac3603bf440b1ec
M camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java
M camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.java
ch...@google.com <ch...@google.com> #16
at...@monzo.com <at...@monzo.com> #17
I had a look into adding a callback so that CSLInflaterCompat could hook back into ResourcesCompat, if it needed to inflate another CSL, which has a cache of inflated CSLs.
/**
* @hide
*/
@RestrictTo(LIBRARY_GROUP_PREFIX)
interface ColorStateListCache {
@Nullable
ColorStateList getCachedColorStateList(Resources resources, @ColorRes int resId);
}
Since ResourcesCompat
is the only one with a CSL cache, we could pass a nullable cache to createFromXml
:
@NonNull
public static ColorStateList createFromXml(
@NonNull Resources r,
@NonNull XmlPullParser parser,
@Nullable Resources.Theme theme,
@Nullable ColorStateListCache cache
) throws XmlPullParserException, IOException {
final AttributeSet attrs = Xml.asAttributeSet(parser);
// ...
and createFromXmlInner
:
@NonNull
public static ColorStateList createFromXmlInner(
@NonNull Resources r,
@NonNull XmlPullParser parser,
@NonNull AttributeSet attrs,
@Nullable Resources.Theme theme,
@Nullable ColorStateListCache cache
) throws XmlPullParserException, IOException {
final String name = parser.getName();
// ...
Although these functions are public, this class is restricted to the library group, so only a few changes are required (and no public API changes):
ComplexColorCompat.inflate()
usescreateFromXmlInner
. This would pass anull
cache.TypedArrayUtils.getNamedColorStateList()
usescreateFromXml()
. This would pass anull
cache too.ResourcesCompat
usescreateFromXml()
. This passes a non-null cache:
@Nullable
private static ColorStateList inflateColorStateList(Resources resources, int resId,
@Nullable Theme theme) {
if (isColorInt(resources, resId)) {
// The resource is a color int, we can't handle it so return null
return null;
}
final XmlPullParser xml = resources.getXml(resId);
try {
return ColorStateListInflaterCompat.createFromXml(resources, xml, theme, cache);
} catch (Exception e) {
Log.e(TAG, "Failed to inflate ColorStateList, leaving it to the framework", e);
}
return null;
}
private static final ColorStateListCache cache = new ColorStateListCache() {
@Nullable
@Override
public ColorStateList getCachedColorStateList(Resources resources, int resId) {
return ResourcesCompat.getCachedColorStateList(resources, resId);
}
};
What do you think?
at...@monzo.com <at...@monzo.com> #18
*The logic in the private inflate
function gets pretty gnarly in Java though:
int resourceId = a.getResourceId(R.styleable.ColorStateListItem_android_color, -1);
int baseColor;
if (resourceId != -1 && !isColorInt(r, resourceId)) {
try {
if (cache != null) {
ColorStateList cachedCsl = cache.getCachedColorStateList(r, resourceId);
if (cachedCsl != null) {
baseColor = cachedCsl.getDefaultColor();
} else {
baseColor = createFromXml(r, r.getXml(resourceId),
theme).getDefaultColor();
}
} else {
baseColor = createFromXml(r, r.getXml(resourceId), theme).getDefaultColor();
}
} catch (Exception e) {
baseColor = a.getColor(R.styleable.ColorStateListItem_android_color,
Color.MAGENTA);
}
} else {
baseColor = a.getColor(R.styleable.ColorStateListItem_android_color, Color.MAGENTA);
}
ch...@google.com <ch...@google.com> #19
Hmmm, I say we keep to the simple solution which we spoke about in #8.
ki...@google.com <ki...@google.com> #20
The contributor CL has been merged and will be available in the next alphas of core and appcompat
ap...@google.com <ap...@google.com> #21
Branch: androidx-master-dev
commit e232f52b6f340b10ac5bed52d065068ac78e7b06
Author: Ataul Munim <hello@ataulm.com>
Date: Fri May 29 21:41:42 2020
Add CSL value support to ColorStateListInflaterCompat
Bug: 155579892
Test: ColorStateListInflaterCompatTest
Change-Id: I61efc84945a4ac1633b085b8fe1b83aca1a6cd4b
M appcompat/appcompat-resources/src/main/java/androidx/appcompat/content/res/AppCompatResources.java
M core/core/src/androidTest/java/androidx/core/content/res/ColorStateListInflaterCompatTest.java
A core/core/src/androidTest/res/color/color_state_list_secondary_text.xml
M core/core/src/androidTest/res/values/styles.xml
M core/core/src/main/java/androidx/core/content/ContextCompat.java
M core/core/src/main/java/androidx/core/content/res/ColorStateListInflaterCompat.java
M core/core/src/main/java/androidx/core/content/res/ResourcesCompat.java
ki...@google.com <ki...@google.com>
ki...@google.com <ki...@google.com> #22
Detected a regression that this CL introduced.
al...@google.com <al...@google.com> #23
P1 to block stable.
Looks like the CSL cache is keying resolved CSLs on Resources
without accounting for the Theme
against which they was resolved. It was always broken, we just never noticed.
Global cache keyed on Resources
:
private static final WeakHashMap<Resources, SparseArray<ColorStateListCacheEntry>>
sColorStateCaches = new WeakHashMap<>(0);
Resolved ColorStateList
and no mention of Theme
:
private static class ColorStateListCacheEntry {
final ColorStateList mValue;
final Configuration mConfiguration;
ColorStateListCacheEntry(@NonNull ColorStateList value,
@NonNull Configuration configuration) {
mValue = value;
mConfiguration = configuration;
}
}
ki...@google.com <ki...@google.com> #24
From Alan:
The base cache class is Resources.ThemeKey
. The old implementation in appcompat-resources
never ran into this issue since it never supported nested CSLs. However, now you can run into a cached CSL that was resolved against a Theme
, and then get the same CSL when you were asking for one that matches Resources
with no Theme
. So keying on Configuration
alone is not enough for caching.
A potential quick fix is to disable caching altogether (same as in framework). Or alternatively add something to the ColorStateListCacheEntry
that would respect the Theme
set on Resources
al...@google.com <al...@google.com> #25
Note that the platform's ResourcesImpl
keys the cache on Resources
, Theme
, and asset cookie:
final long key = (((long) value.assetCookie) << 32) | value.data;
final ConfigurationBoundResourceCache<ComplexColor> cache = mComplexColorCache;
ComplexColor complexColor = cache.getInstance(key, wrapper, theme);
Theme
doesn't implement hashCode
and its comparable ThemeKey
isn't public API, but you'd still get some benefits from keying off the Object
implementation of hashCode
.
al...@google.com <al...@google.com>
he...@ataulm.com <he...@ataulm.com> #26
What's the preferred approach? I can pick this up.
he...@ataulm.com <he...@ataulm.com> #27
I didn't understand when the Resources
might be different - is it this?
ResourcesCompat.getColorStateList(
context.resources,
R.color.my_csl,
ContextThemeWrapper(context, R.style.ThemeOverlay_EverythingDifferent).theme
)
If adding Theme
to ColorStateListCacheEntry
isn't good enough because the lack of a legit hashcode implementation means potential collisions, could we instead keep Resources
as the key in the global cache, but use theme?.resources ?: res
instead?
he...@ataulm.com <he...@ataulm.com> #28
The old implementation in appcompat-resources never ran into this issue since it never supported nested CSLs. However, now you can run into a cached CSL that was resolved against a Theme, and then get the same CSL when you were asking for one that matches Resources with no Theme.
This is the part I didn't understand. The nested CSL isn't resolved from the cache, it's always inflated, so I didn't follow why this is a problem now, but wasn't before.
he...@ataulm.com <he...@ataulm.com> #29
@Alan, is this still blocking?
al...@google.com <al...@google.com> #30
could we instead keep
Resources
as the key in the global cache, but usetheme?.resources ?: res
instead?
No, because many Theme
s will reference the same Resources
object. Theme
is a non-static inner class of Resources
and contains a reference to the Resources
object from which it was created.
@Alan, is this still blocking?
Not blocking, per se. We had to revert the CL. Lowering to P2 and considering this a FR now.
he...@ataulm.com <he...@ataulm.com> #32
I'm able to reproduce the bug and I understand what you mean now. It's a very common case, e.g. when using theme overlays:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Purple"
android:textColor="@color/csl_pointing_to_color_primary_which_is_purple" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Green"
android:textColor="@color/csl_pointing_to_color_primary_which_is_purple"
android:theme="@style/ThemeOverlay.GreenPrimary" />
We'd expect green text for the second one, but @color/csl_pointing_to_color_primary_which_is_purple
is cached, so it'll be purple. :+1:
I added a key that takes Theme
into account:
private static class ColorStateListCacheKey {
final Resources mResources;
@Nullable final Theme mTheme;
ColorStateListCacheKey(@NonNull Resources resources, @Nullable Theme theme) {
mResources = resources;
mTheme = theme;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ColorStateListCacheKey that = (ColorStateListCacheKey) o;
return mResources.equals(that.mResources) &&
Objects.equals(mTheme, that.mTheme);
}
@Override
public int hashCode() {
return Objects.hash(mResources, mTheme);
}
}
I don't think there would be any false positive matches anymore (the cache bug), but there could still be some false negatives (unnecessary inflation, duplicate values in cache). As you said this is what ResourcesImpl
does (*), is this a sufficient solution?
(*) I didn't understand the value of including the asset cookie in the key. Is that applicable for this case?
he...@ataulm.com <he...@ataulm.com> #33
Bump, I've got time to work on this this month. If I submit a CL with the above, reckon someone could take a look?
ki...@google.com <ki...@google.com> #34
Sure, if you have a CL with test covering the new paths, we'll be happy to get it in and see if it breaks any of the app tests that we have.
he...@ataulm.com <he...@ataulm.com> #35
CL here
I didn't add any new tests - ResourcesCompatTest
already covered the bug as I understood it, where R.color.complex_themed_selector
is loaded twice with distinct themes. I extended the coverage down to the minSdkVersion of the library (but could only test it on API 15).
ki...@google.com <ki...@google.com>
ap...@google.com <ap...@google.com> #36
Branch: androidx-main
commit 63f5fe8e647c9b5b704a33c34201dbc3bab946ef
Author: Ataul Munim <hello@ataulm.com>
Date: Sun Jul 26 10:05:33 2020
Add CSL value support to ColorStateListInflaterCompat
Bug: 155579892
Test: ColorStateListInflaterCompatTest verifies nested CSLs are loaded,
ResourcesCompatTest extends getThemedCsl coverage to all API versions
(tested down to API 15)
Change-Id: I2e4098d45173a443dda97a23923c02755e83acfb
M appcompat/appcompat-resources/src/main/java/androidx/appcompat/content/res/AppCompatResources.java
M core/core/src/androidTest/java/androidx/core/content/res/ColorStateListInflaterCompatTest.java
M core/core/src/androidTest/java/androidx/core/content/res/ResourcesCompatTest.java
A core/core/src/androidTest/res/color/color_state_list_secondary_text.xml
M core/core/src/androidTest/res/values/styles.xml
M core/core/src/main/java/androidx/core/content/ContextCompat.java
M core/core/src/main/java/androidx/core/content/res/ColorStateListInflaterCompat.java
M core/core/src/main/java/androidx/core/content/res/ResourcesCompat.java
Description
Issue
Steps to reproduce
colorPrimary
has a value@color/blue
(a plain hex color).@color/primary_60
is a single value CSL used to apply 60% alpha@color/text_tertiary
is a CSL with enabled/disabled states. It references@color/primary_60
for both states, applying a further 60% alpha for the disabled state.(This is a contrived use case, since we could define
@color/text_tertiary
in terms of?attr/colorPrimary
rather than@color/primary_60
.)The bug is that
AppCompatResources.getColorStateList
behaviour doesn't match the framework's resolution of CSLs.The same behavior is exhibited if using
android:textColor
or manually loading the@color/text_tertiary
withAppCompatResources
and usingsetTextColor(ColorStateList)
(AppCompatTextView
usesAppCompatResources
for this attribute under the hood).Screenshots
Attached screenshot comparing API 22 and API 29.