Skip to content

Commit 9da9993

Browse files
pubiqqdsn5ft
authored andcommitted
[Drawable][Internal] Add constant state support to ScaledDrawableWrapper which fixes NPE crash in APIs <= 23
Resolves #3572 Resolves #4129 GIT_ORIGIN_REV_ID=9e4b5c3ba4f715afc5f198d0b6afb163480d0138 PiperOrigin-RevId: 631436018
1 parent 0429d44 commit 9da9993

File tree

1 file changed

+91
-6
lines changed

1 file changed

+91
-6
lines changed

lib/java/com/google/android/material/drawable/ScaledDrawableWrapper.java

Lines changed: 91 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,13 @@
1616

1717
package com.google.android.material.drawable;
1818

19+
import android.content.res.Resources;
1920
import android.graphics.drawable.Drawable;
21+
import android.os.Build.VERSION_CODES;
2022
import androidx.appcompat.graphics.drawable.DrawableWrapperCompat;
2123
import androidx.annotation.NonNull;
24+
import androidx.annotation.Nullable;
25+
import androidx.annotation.RequiresApi;
2226
import androidx.annotation.RestrictTo;
2327
import androidx.annotation.RestrictTo.Scope;
2428

@@ -28,22 +32,103 @@
2832
*/
2933
@RestrictTo(Scope.LIBRARY_GROUP)
3034
public class ScaledDrawableWrapper extends DrawableWrapperCompat {
31-
private final int width;
32-
private final int height;
35+
private ScaledDrawableWrapperState state;
36+
private boolean mutated;
3337

3438
public ScaledDrawableWrapper(@NonNull Drawable drawable, int width, int height) {
3539
super(drawable);
36-
this.width = width;
37-
this.height = height;
40+
state = new ScaledDrawableWrapperState(getConstantStateFrom(drawable), width, height);
41+
}
42+
43+
@Nullable
44+
private ConstantState getConstantStateFrom(@Nullable Drawable drawable) {
45+
return drawable != null ? drawable.getConstantState() : null;
3846
}
3947

4048
@Override
4149
public int getIntrinsicWidth() {
42-
return width;
50+
return state.width;
4351
}
4452

4553
@Override
4654
public int getIntrinsicHeight() {
47-
return height;
55+
return state.height;
56+
}
57+
58+
@Override
59+
public void setDrawable(@Nullable Drawable drawable) {
60+
super.setDrawable(drawable);
61+
62+
if (state != null) {
63+
state.wrappedDrawableState = getConstantStateFrom(drawable);
64+
mutated = false;
65+
}
66+
}
67+
68+
@Nullable
69+
@Override
70+
public ConstantState getConstantState() {
71+
return state.canConstantState() ? state : null;
72+
}
73+
74+
@NonNull
75+
@Override
76+
public Drawable mutate() {
77+
if (!mutated && super.mutate() == this) {
78+
Drawable drawable = getDrawable();
79+
if (drawable != null) {
80+
drawable.mutate();
81+
}
82+
83+
state =
84+
new ScaledDrawableWrapperState(getConstantStateFrom(drawable), state.width, state.height);
85+
mutated = true;
86+
}
87+
88+
return this;
89+
}
90+
91+
private static final class ScaledDrawableWrapperState extends ConstantState {
92+
private ConstantState wrappedDrawableState;
93+
private final int width;
94+
private final int height;
95+
96+
ScaledDrawableWrapperState(
97+
@Nullable ConstantState wrappedDrawableState, int width, int height) {
98+
this.wrappedDrawableState = wrappedDrawableState;
99+
this.width = width;
100+
this.height = height;
101+
}
102+
103+
@NonNull
104+
@Override
105+
public Drawable newDrawable() {
106+
Drawable newWrappedDrawable = wrappedDrawableState.newDrawable();
107+
return new ScaledDrawableWrapper(newWrappedDrawable, width, height);
108+
}
109+
110+
@NonNull
111+
@Override
112+
public Drawable newDrawable(@Nullable Resources res) {
113+
Drawable newWrappedDrawable = wrappedDrawableState.newDrawable(res);
114+
return new ScaledDrawableWrapper(newWrappedDrawable, width, height);
115+
}
116+
117+
@RequiresApi(VERSION_CODES.LOLLIPOP)
118+
@NonNull
119+
@Override
120+
public Drawable newDrawable(@Nullable Resources res, @Nullable Resources.Theme theme) {
121+
Drawable newWrappedDrawable = wrappedDrawableState.newDrawable(res, theme);
122+
return new ScaledDrawableWrapper(newWrappedDrawable, width, height);
123+
}
124+
125+
@Override
126+
public int getChangingConfigurations() {
127+
return wrappedDrawableState != null ? wrappedDrawableState.getChangingConfigurations() : 0;
128+
}
129+
130+
boolean canConstantState() {
131+
return wrappedDrawableState != null;
132+
}
48133
}
49134
}

0 commit comments

Comments
 (0)