Skip to content
This repository was archived by the owner on Feb 26, 2023. It is now read-only.

Commit 122bb6d

Browse files
committed
ContextCompat corner cases for minSdk<21 and compileSdk>21 without ContextCompat
1 parent 587c8cf commit 122bb6d

7 files changed

Lines changed: 257 additions & 3 deletions

File tree

‎AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/handler/ResHandler.java‎

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,14 @@
1818
import static com.sun.codemodel.JExpr.invoke;
1919
import static com.sun.codemodel.JExpr.ref;
2020

21+
import java.util.List;
22+
2123
import javax.annotation.processing.ProcessingEnvironment;
2224
import javax.lang.model.element.Element;
25+
import javax.lang.model.element.ExecutableElement;
26+
import javax.lang.model.element.TypeElement;
2327
import javax.lang.model.type.TypeMirror;
28+
import javax.lang.model.util.ElementFilter;
2429

2530
import org.androidannotations.annotations.res.DrawableRes;
2631
import org.androidannotations.annotations.res.HtmlRes;
@@ -36,10 +41,14 @@
3641
import org.androidannotations.rclass.IRClass;
3742

3843
import com.sun.codemodel.JBlock;
44+
import com.sun.codemodel.JConditional;
3945
import com.sun.codemodel.JFieldRef;
46+
import com.sun.codemodel.JVar;
4047

4148
public class ResHandler extends BaseAnnotationHandler<EComponentHolder> {
4249

50+
private static final int MIN_SDK_WITH_CONTEXT_GET_DRAWABLE = 21;
51+
4352
private AndroidRes androidRes;
4453
private IdAnnotationHelper annotationHelper;
4554

@@ -89,8 +98,9 @@ public void process(Element element, EComponentHolder holder) {
8998
// Special case for @HtmlRes
9099
if (element.getAnnotation(HtmlRes.class) != null) {
91100
methodBody.assign(ref(fieldName), classes().HTML.staticInvoke("fromHtml").arg(invoke(holder.getResourcesRef(), resourceMethodName).arg(idRef)));
92-
} else if (element.getAnnotation(DrawableRes.class) != null && hasContextCompatInClasspath()) {
93-
methodBody.assign(ref(fieldName), classes().CONTEXT_COMPAT.staticInvoke("getDrawable").arg(holder.getContextRef()).arg(idRef));
101+
} else if (element.getAnnotation(DrawableRes.class) != null) {
102+
// Special case for @DrawableRes
103+
handleDrawableCompatibility(holder, ref(fieldName), methodBody, idRef, resourceMethodName);
94104
} else {
95105
methodBody.assign(ref(fieldName), invoke(holder.getResourcesRef(), resourceMethodName).arg(idRef));
96106
}
@@ -100,4 +110,51 @@ public void process(Element element, EComponentHolder holder) {
100110
protected boolean hasContextCompatInClasspath() {
101111
return processingEnvironment().getElementUtils().getTypeElement(CanonicalNameConstants.CONTEXT_COMPAT) != null;
102112
}
113+
114+
protected boolean shouldUseContextGetDrawableMethod() {
115+
return androidManifest.getMinSdkVersion() >= MIN_SDK_WITH_CONTEXT_GET_DRAWABLE;
116+
}
117+
118+
protected boolean hasGetDrawableInContext() {
119+
TypeElement context = processingEnvironment().getElementUtils().getTypeElement(CanonicalNameConstants.CONTEXT);
120+
121+
return hasGetDrawable(context);
122+
}
123+
124+
private void handleDrawableCompatibility(EComponentHolder holder, JFieldRef ref, JBlock methodBody, JFieldRef idRef, String resourceMethodName) {
125+
if (hasContextCompatInClasspath()) {
126+
methodBody.assign(ref, classes().CONTEXT_COMPAT.staticInvoke("getDrawable").arg(holder.getContextRef()).arg(idRef));
127+
} else if (shouldUseContextGetDrawableMethod() && !hasContextCompatInClasspath()) {
128+
methodBody.assign(ref, holder.getContextRef().invoke("getDrawable").arg(idRef));
129+
} else if (!shouldUseContextGetDrawableMethod() && hasGetDrawableInContext() && !hasContextCompatInClasspath()) {
130+
createCallWithIfGuard(holder, ref, methodBody, idRef);
131+
} else {
132+
methodBody.assign(ref, invoke(holder.getResourcesRef(), resourceMethodName).arg(idRef));
133+
}
134+
}
135+
136+
private void createCallWithIfGuard(EComponentHolder holder, JFieldRef ref, JBlock methodBody, JFieldRef idRef) {
137+
JVar resourcesRef = holder.getResourcesRef();
138+
JConditional guardIf = methodBody._if(holder.classes().BUILD_VERSION.staticRef("SDK_INT").gte(holder.classes().BUILD_VERSION_CODES.staticRef("LOLLIPOP")));
139+
JBlock ifBlock = guardIf._then();
140+
ifBlock.assign(ref, holder.getContextRef().invoke("getDrawable").arg(idRef));
141+
142+
JBlock elseBlock = guardIf._else();
143+
elseBlock.assign(ref, resourcesRef.invoke("getDrawable").arg(idRef));
144+
}
145+
146+
private boolean hasGetDrawable(TypeElement type) {
147+
if (type == null) {
148+
return false;
149+
}
150+
151+
List<? extends Element> allMembers = processingEnvironment().getElementUtils().getAllMembers(type);
152+
for (ExecutableElement element : ElementFilter.methodsIn(allMembers)) {
153+
if (element.getSimpleName().contentEquals("getDrawable")) {
154+
return true;
155+
}
156+
}
157+
return false;
158+
}
159+
103160
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* Copyright (C) 2010-2015 eBusiness Information, Excilys Group
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed To in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
package org.androidannotations.generation;
17+
18+
import org.androidannotations.annotations.EActivity;
19+
import org.androidannotations.annotations.res.DrawableRes;
20+
21+
import android.app.Activity;
22+
import android.graphics.drawable.Drawable;
23+
24+
@EActivity
25+
public class ActivityWithGetDrawableMethod extends Activity {
26+
27+
@DrawableRes(R.drawable.myDrawable)
28+
Drawable myDrawable;
29+
30+
// http://developer.android.com/reference/android/content/Context.html#getDrawable(int)
31+
// This method was added in API 21 and should be used to get a Drawable which is styled/adjusted for the current theme.
32+
public Drawable getDrawable(int drawableId) {
33+
return null;
34+
}
35+
36+
}

‎AndroidAnnotations/androidannotations/src/test/java/org/androidannotations/generation/ContextCompatDrawableTest.java‎

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,24 @@ public class ContextCompatDrawableTest extends AAProcessorTestHelper {
2626

2727
private static final String DRAWABLE_SIGNATURE = ".*myDrawable = resources_\\.getDrawable\\(drawable\\.myDrawable\\);.*";
2828
private static final String DRAWABLE_VIA_SUPPORT_SIGNATURE = ".*myDrawable = ContextCompat\\.getDrawable\\(this, drawable\\.myDrawable\\);.*";
29+
private static final String DRAWABLE_VIA_CONTEXT_ON_LOLLIPOP = ".*myDrawable = this\\.getDrawable\\(drawable\\.myDrawable\\);.*";
30+
private static final String[] DRAWABLE_CONDITIONAL_WITHOUT_CONTEXT_COMPAT = new String[] {
31+
" if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {",
32+
" myDrawable = this.getDrawable(drawable.myDrawable);",
33+
" } else {",
34+
" myDrawable = resources_.getDrawable(drawable.myDrawable);",
35+
" }",
36+
};
2937

3038
@Before
3139
public void setUp() {
3240
addProcessor(AndroidAnnotationProcessor.class);
33-
addManifestProcessorParameter(ContextCompatDrawableTest.class, "AndroidManifestForDrawable.xml");
3441
}
3542

3643
@Test
3744
public void activityCompilesWithRegularDrawable() {
45+
addManifestProcessorParameter(ContextCompatDrawableTest.class, "AndroidManifestForDrawable.xml");
46+
3847
CompileResult result = compileFiles(ActivityWithDrawable.class);
3948
File generatedFile = toGeneratedFile(ActivityWithDrawable.class);
4049

@@ -47,10 +56,36 @@ public void activityCompilesWithContextCompatDrawable() {
4756
// To simulate android support v4 in classpath, we add
4857
// android.support.v4.content.ContextCompat
4958
// in classpath
59+
addManifestProcessorParameter(ContextCompatDrawableTest.class, "AndroidManifestForDrawable.xml");
5060
CompileResult result = compileFiles(toPath(ContextCompatDrawableTest.class, "ContextCompat.java"), ActivityWithDrawable.class);
5161
File generatedFile = toGeneratedFile(ActivityWithDrawable.class);
5262

5363
assertCompilationSuccessful(result);
5464
assertGeneratedClassMatches(generatedFile, DRAWABLE_VIA_SUPPORT_SIGNATURE);
5565
}
66+
67+
@Test
68+
public void activityCompilesOnMinSdk21WithoutContextCompat() throws Exception {
69+
addManifestProcessorParameter(ContextCompatDrawableTest.class, "AndroidManifestForDrawableMinSdk21.xml");
70+
71+
CompileResult result = compileFiles(ActivityWithGetDrawableMethod.class);
72+
File generatedFile = toGeneratedFile(ActivityWithGetDrawableMethod.class);
73+
74+
assertCompilationSuccessful(result);
75+
assertGeneratedClassMatches(generatedFile, DRAWABLE_VIA_CONTEXT_ON_LOLLIPOP);
76+
}
77+
78+
@Test
79+
public void activityCompilesOnMinSdkLower21CompileSdkHigher21WithoutContextCompat() throws Exception {
80+
addManifestProcessorParameter(ContextCompatDrawableTest.class, "AndroidManifestForDrawableMinSdk20.xml");
81+
82+
CompileResult result = compileFiles(toPath(ContextCompatDrawableTest.class, "Context.java"),
83+
toPath(ContextCompatDrawableTest.class, "Build.java"),
84+
ActivityWithGetDrawableMethod.class);
85+
File generatedFile = toGeneratedFile(ActivityWithGetDrawableMethod.class);
86+
87+
assertCompilationSuccessful(result);
88+
assertGeneratedClassContains(generatedFile, DRAWABLE_CONDITIONAL_WITHOUT_CONTEXT_COMPAT);
89+
}
90+
5691
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
4+
Copyright (C) 2010-2015 eBusiness Information, Excilys Group
5+
6+
Licensed under the Apache License, Version 2.0 (the "License"); you may not
7+
use this file except in compliance with the License. You may obtain a copy of
8+
the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed To in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14+
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15+
License for the specific language governing permissions and limitations under
16+
the License.
17+
18+
-->
19+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
20+
package="org.androidannotations.generation"
21+
android:versionCode="1"
22+
android:versionName="1.0" >
23+
24+
<uses-sdk
25+
android:minSdkVersion="20"
26+
/>
27+
28+
<application>
29+
<activity android:name="org.androidannotations.generation.ActivityWithGetDrawableMethod_" />
30+
</application>
31+
32+
</manifest>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
4+
Copyright (C) 2010-2015 eBusiness Information, Excilys Group
5+
6+
Licensed under the Apache License, Version 2.0 (the "License"); you may not
7+
use this file except in compliance with the License. You may obtain a copy of
8+
the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed To in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14+
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15+
License for the specific language governing permissions and limitations under
16+
the License.
17+
18+
-->
19+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
20+
package="org.androidannotations.generation"
21+
android:versionCode="1"
22+
android:versionName="1.0" >
23+
24+
<uses-sdk
25+
android:minSdkVersion="21"
26+
/>
27+
28+
<application>
29+
<activity android:name="org.androidannotations.generation.ActivityWithGetDrawableMethod_" />
30+
</application>
31+
32+
</manifest>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* Copyright (C) 2010-2015 eBusiness Information, Excilys Group
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed To in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
package android.os;
17+
18+
/**
19+
* We have to put this on resources folder because we want to add it to
20+
* classpath only on some unit tests methods
21+
*/
22+
public class Build {
23+
24+
public static class VERSION {
25+
public static final int SDK_INT = 20;
26+
}
27+
28+
public static class VERSION_CODES {
29+
public static final int LOLLIPOP = 21;
30+
}
31+
32+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* Copyright (C) 2010-2015 eBusiness Information, Excilys Group
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed To in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
package android.content;
17+
18+
import android.content.Intent;
19+
import android.graphics.drawable.Drawable;
20+
import android.os.Bundle;
21+
22+
public class Context {
23+
24+
public void startActivity(Intent intent, Bundle options) {
25+
}
26+
27+
public Drawable getDrawable(int id) {
28+
return null;
29+
}
30+
}

0 commit comments

Comments
 (0)