Fix crash where some android Drawables doesn't implement getConstantState... (#4742)

Changed all places where getConstantState was used.
This commit is contained in:
Hristo Hristov
2017-08-24 11:06:33 +03:00
committed by GitHub
parent d6689a04b2
commit b6d5510627
4 changed files with 64 additions and 22 deletions

View File

@ -459,7 +459,16 @@ export class View extends ViewCommon {
[backgroundInternalProperty.getDefault](): android.graphics.drawable.Drawable {
const nativeView = this.nativeViewProtected;
const drawable = nativeView.getBackground();
return drawable ? drawable.getConstantState().newDrawable(nativeView.getResources()) : null;
if (drawable) {
const constantState = drawable.getConstantState();
if (constantState) {
return constantState.newDrawable(nativeView.getResources());
} else {
return drawable;
}
}
return null;
}
[backgroundInternalProperty.setNative](value: android.graphics.drawable.Drawable | Background) {
this._redrawNativeBackground(value);

View File

@ -12,15 +12,15 @@ const R_ATTR_STATE_SELECTED = 0x010100a1;
const TITLE_TEXT_VIEW_ID = 16908310; // http://developer.android.com/reference/android/R.id.html#title
interface TabChangeListener {
new (owner: SegmentedBar): android.widget.TabHost.OnTabChangeListener;
new(owner: SegmentedBar): android.widget.TabHost.OnTabChangeListener;
}
interface TabContentFactory {
new (owner: SegmentedBar): android.widget.TabHost.TabContentFactory;
new(owner: SegmentedBar): android.widget.TabHost.TabContentFactory;
}
interface TabHost {
new (context: android.content.Context, attrs: android.util.AttributeSet): android.widget.TabHost;
new(context: android.content.Context, attrs: android.util.AttributeSet): android.widget.TabHost;
}
let apiLevel: number;
@ -144,17 +144,18 @@ export class SegmentedBarItem extends SegmentedBarItemBase {
this.nativeViewProtected.setTypeface(value instanceof Font ? value.getAndroidTypeface() : value);
}
[selectedBackgroundColorProperty.getDefault](): android.graphics.drawable.Drawable.ConstantState {
[selectedBackgroundColorProperty.getDefault](): android.graphics.drawable.Drawable {
const viewGroup = <android.view.ViewGroup>this.nativeViewProtected.getParent();
return viewGroup.getBackground().getConstantState();
return viewGroup.getBackground();
}
[selectedBackgroundColorProperty.setNative](value: Color | android.graphics.drawable.Drawable.ConstantState) {
const viewGroup = <android.view.ViewGroup>this.nativeViewProtected.getParent();
[selectedBackgroundColorProperty.setNative](value: Color | android.graphics.drawable.Drawable) {
const nativeView = this.nativeViewProtected;
const viewGroup = <android.view.ViewGroup>nativeView.getParent();
if (value instanceof Color) {
const color = value.android;
const backgroundDrawable = viewGroup.getBackground();
if (apiLevel > 21 && backgroundDrawable && typeof backgroundDrawable.setColorFilter === "function") {
const newDrawable = backgroundDrawable.getConstantState().newDrawable();
if (apiLevel > 21 && backgroundDrawable) {
const newDrawable = tryCloneDrawable(backgroundDrawable, nativeView.getResources());
newDrawable.setColorFilter(color, android.graphics.PorterDuff.Mode.SRC_IN);
org.nativescript.widgets.ViewHelper.setBackground(viewGroup, newDrawable);
} else {
@ -164,15 +165,26 @@ export class SegmentedBarItem extends SegmentedBarItemBase {
arr[0] = R_ATTR_STATE_SELECTED;
stateDrawable.addState(arr, colorDrawable);
stateDrawable.setBounds(0, 15, viewGroup.getRight(), viewGroup.getBottom());
org.nativescript.widgets.ViewHelper.setBackground(viewGroup, stateDrawable);
}
} else {
org.nativescript.widgets.ViewHelper.setBackground(viewGroup, value.newDrawable());
const backgroundDrawable = tryCloneDrawable(value, nativeView.getResources());
org.nativescript.widgets.ViewHelper.setBackground(viewGroup, backgroundDrawable);
}
}
}
function tryCloneDrawable(value: android.graphics.drawable.Drawable, resources: android.content.res.Resources): android.graphics.drawable.Drawable {
if (value) {
const constantState = value.getConstantState();
if (constantState) {
return constantState.newDrawable(resources);
}
}
return value;
}
export class SegmentedBar extends SegmentedBarBase {
nativeViewProtected: android.widget.TabHost;
private _tabContentFactory: android.widget.TabHost.TabContentFactory;

View File

@ -6,7 +6,7 @@ import * as application from "../../application";
export * from "./background-common"
interface AndroidView {
_cachedDrawableConstState: android.graphics.drawable.Drawable.ConstantState;
_cachedDrawable: android.graphics.drawable.Drawable.ConstantState | android.graphics.drawable.Drawable;
}
// TODO: Change this implementation to use
@ -41,8 +41,9 @@ export module ad {
const drawable = nativeView.getBackground();
const androidView = <any>view as AndroidView;
// use undefined as not set. getBackground will never return undefined only Drawable or null;
if (androidView._cachedDrawableConstState === undefined && drawable) {
androidView._cachedDrawableConstState = drawable.getConstantState();
if (androidView._cachedDrawable === undefined && drawable) {
const constantState = drawable.getConstantState();
androidView._cachedDrawable = constantState || drawable;
}
if (isSetColorFilterOnlyWidget(nativeView)
@ -77,10 +78,19 @@ export module ad {
}
}
} else {
// TODO: newDrawable for BitmapDrawable will fail if we don't specify resource. Use the other overload.
const defaultDrawable = androidView._cachedDrawableConstState ? androidView._cachedDrawableConstState.newDrawable(nativeView.getResources()) : null;
const cachedDrawable = androidView._cachedDrawable;
let defaultDrawable: android.graphics.drawable.Drawable;
if (cachedDrawable instanceof android.graphics.drawable.Drawable.ConstantState) {
defaultDrawable = cachedDrawable.newDrawable(nativeView.getResources())
} else if (cachedDrawable instanceof android.graphics.drawable.Drawable) {
defaultDrawable = cachedDrawable;
} else {
defaultDrawable = null;
}
org.nativescript.widgets.ViewHelper.setBackground(nativeView, defaultDrawable);
androidView._cachedDrawableConstState = undefined;
// TODO: Do we need to clear the drawable here? Can't we just reuse it again?
androidView._cachedDrawable = undefined;
if (cache.layerType !== undefined) {
cache.setLayerType(cache.layerType, null);

View File

@ -412,14 +412,14 @@ export class TabView extends TabViewBase {
selectedIndexProperty.coerce(this);
}
[tabBackgroundColorProperty.getDefault](): android.graphics.drawable.Drawable.ConstantState {
return this._tabLayout.getBackground().getConstantState();
[tabBackgroundColorProperty.getDefault](): android.graphics.drawable.Drawable {
return this._tabLayout.getBackground();
}
[tabBackgroundColorProperty.setNative](value: android.graphics.drawable.Drawable.ConstantState | Color) {
[tabBackgroundColorProperty.setNative](value: android.graphics.drawable.Drawable | Color) {
if (value instanceof Color) {
this._tabLayout.setBackgroundColor(value.android);
} else {
this._tabLayout.setBackground(value ? value.newDrawable() : null);
this._tabLayout.setBackground(tryCloneDrawable(value, this.nativeViewProtected.getResources));
}
}
@ -448,3 +448,14 @@ export class TabView extends TabViewBase {
tabLayout.setSelectedIndicatorColors([color]);
}
}
function tryCloneDrawable(value: android.graphics.drawable.Drawable, resources: android.content.res.Resources): android.graphics.drawable.Drawable {
if (value) {
const constantState = value.getConstantState();
if (constantState) {
return constantState.newDrawable(resources);
}
}
return value;
}