Skip to content

Commit 72c62af

Browse files
Fix special permissions handling
1 parent a03021f commit 72c62af

File tree

6 files changed

+233
-122
lines changed

6 files changed

+233
-122
lines changed

androidannotationspermissionsdispatcherplugin/src/main/java/com/github/aleksandermielczarek/androidannotationspermissionsdispatcherplugin/NeedsPermissionHandler.java

Lines changed: 96 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.helger.jcodemodel.JInvocation;
99
import com.helger.jcodemodel.JMethod;
1010
import com.helger.jcodemodel.JVar;
11+
1112
import org.androidannotations.AndroidAnnotationsEnvironment;
1213
import org.androidannotations.ElementValidation;
1314
import org.androidannotations.annotations.EActivity;
@@ -22,69 +23,98 @@
2223

2324
public class NeedsPermissionHandler extends BaseAnnotationHandler<EComponentHolder> {
2425

25-
public NeedsPermissionHandler(AndroidAnnotationsEnvironment environment) {
26-
super("permissions.dispatcher.NeedsPermission", environment);
27-
}
28-
29-
@Override
30-
protected void validate(Element element, ElementValidation validation) {
31-
if (validatorHelper.elementHasAnnotation(EActivity.class, element.getEnclosingElement())
32-
|| validatorHelper.elementHasAnnotation(EFragment.class, element.getEnclosingElement())) {
33-
validatorHelper.isNotPrivate(element, validation);
34-
validatorHelper.isNotFinal(element, validation);
35-
validatorHelper.returnTypeIsVoid((ExecutableElement) element, validation);
36-
}
37-
}
38-
39-
@Override
40-
public void process(Element element, EComponentHolder holder) throws Exception {
41-
TypeElement annotatedElement = holder.getAnnotatedElement();
42-
String delegateClassName = annotatedElement.getQualifiedName().toString() + "PermissionsDispatcher";
43-
AbstractJClass delegateClass = getJClass(delegateClassName);
44-
45-
PermissionDispatcherHolder permissionDispatcherHolder = holder.getPluginHolder(new PermissionDispatcherHolder(holder));
46-
permissionDispatcherHolder.setDelegateCall(delegateClass);
47-
JFieldVar dispatcherCalledField = permissionDispatcherHolder.getPermissionDispatcherCalledField();
48-
49-
ExecutableElement executableElement = (ExecutableElement) element;
50-
51-
JMethod overrideMethod = codeModelHelper.overrideAnnotatedMethod(executableElement, holder);
52-
JBlock previousMethodBody = codeModelHelper.removeBody(overrideMethod);
53-
54-
JBlock overrideMethodBody = overrideMethod.body();
55-
JConditional conditional = overrideMethodBody._if(dispatcherCalledField.not());
56-
57-
JBlock thenBlock = conditional._then();
58-
thenBlock.assign(dispatcherCalledField, JExpr.TRUE);
59-
String delegateMethodName = element.getSimpleName().toString() + "WithCheck";
60-
61-
JInvocation delegateCall = delegateClass.staticInvoke(delegateMethodName)
62-
.arg(JExpr._this());
63-
64-
for (JVar param : overrideMethod.params()) {
65-
delegateCall.arg(param);
66-
}
67-
68-
if (overrideMethod.hasVarArgs()) {
69-
delegateCall.arg(overrideMethod.varParam());
70-
}
71-
72-
codeModelHelper.copyAnnotation(overrideMethod, findAnnotation(element));
73-
74-
thenBlock.add(delegateCall);
75-
76-
JBlock elseBlock = conditional._else();
77-
elseBlock.assign(dispatcherCalledField, JExpr.FALSE);
78-
elseBlock.add(previousMethodBody);
79-
}
80-
81-
private AnnotationMirror findAnnotation(Element element) {
82-
for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) {
83-
if (annotationMirror.getAnnotationType().asElement().getSimpleName().toString().equals("NeedsPermission")) {
84-
return annotationMirror;
85-
}
86-
}
87-
88-
throw new IllegalStateException("Handled annotation should be on the method!");
89-
}
90-
}
26+
public static final String PERMISSION_WRITE_SETTINGS = "\"android.permission.WRITE_SETTINGS\"";
27+
public static final String PERMISSION_SYSTEM_ALERT_WINDOW = "\"android.permission.SYSTEM_ALERT_WINDOW\"";
28+
29+
public NeedsPermissionHandler(AndroidAnnotationsEnvironment environment) {
30+
super("permissions.dispatcher.NeedsPermission", environment);
31+
}
32+
33+
@Override
34+
protected void validate(Element element, ElementValidation validation) {
35+
if (validatorHelper.elementHasAnnotation(EActivity.class, element.getEnclosingElement())
36+
|| validatorHelper.elementHasAnnotation(EFragment.class, element.getEnclosingElement())) {
37+
validatorHelper.isNotPrivate(element, validation);
38+
validatorHelper.isNotFinal(element, validation);
39+
validatorHelper.returnTypeIsVoid((ExecutableElement) element, validation);
40+
}
41+
}
42+
43+
@Override
44+
public void process(Element element, EComponentHolder holder) throws Exception {
45+
TypeElement annotatedElement = holder.getAnnotatedElement();
46+
String delegateClassName = annotatedElement.getQualifiedName().toString() + "PermissionsDispatcher";
47+
AbstractJClass delegateClass = getJClass(delegateClassName);
48+
49+
PermissionDispatcherHolder permissionDispatcherHolder = holder.getPluginHolder(new PermissionDispatcherHolder(holder));
50+
51+
if (hasSpecialPermissions(element)) {
52+
permissionDispatcherHolder.setOnActivityResultDelegateCall(delegateClass);
53+
}
54+
if (hasNormalPermissions(element)) {
55+
permissionDispatcherHolder.setOnRequestPermissionsResultDelegateCall(delegateClass);
56+
}
57+
58+
JFieldVar dispatcherCalledField = permissionDispatcherHolder.getPermissionDispatcherCalledField();
59+
60+
ExecutableElement executableElement = (ExecutableElement) element;
61+
62+
JMethod overrideMethod = codeModelHelper.overrideAnnotatedMethod(executableElement, holder);
63+
JBlock previousMethodBody = codeModelHelper.removeBody(overrideMethod);
64+
65+
JBlock overrideMethodBody = overrideMethod.body();
66+
JConditional conditional = overrideMethodBody._if(dispatcherCalledField.not());
67+
68+
JBlock thenBlock = conditional._then();
69+
thenBlock.assign(dispatcherCalledField, JExpr.TRUE);
70+
String delegateMethodName = element.getSimpleName().toString() + "WithCheck";
71+
72+
JInvocation delegateCall = delegateClass.staticInvoke(delegateMethodName)
73+
.arg(JExpr._this());
74+
75+
overrideMethod.params().forEach(delegateCall::arg);
76+
77+
if (overrideMethod.hasVarArgs()) {
78+
JVar jVar = overrideMethod.varParam();
79+
if (jVar != null) {
80+
delegateCall.arg(jVar);
81+
}
82+
}
83+
84+
codeModelHelper.copyAnnotation(overrideMethod, findAnnotation(element));
85+
86+
thenBlock.add(delegateCall);
87+
88+
JBlock elseBlock = conditional._else();
89+
elseBlock.assign(dispatcherCalledField, JExpr.FALSE);
90+
elseBlock.add(previousMethodBody);
91+
}
92+
93+
private AnnotationMirror findAnnotation(Element element) {
94+
return element.getAnnotationMirrors().stream()
95+
.filter(this::isNeedsPermission)
96+
.findAny()
97+
.orElseThrow(() -> new IllegalStateException("Handled annotation should be on the method!"));
98+
}
99+
100+
private boolean hasSpecialPermissions(Element element) {
101+
return element.getAnnotationMirrors().stream()
102+
.filter(this::isNeedsPermission)
103+
.anyMatch(this::hasSpecialPermissions);
104+
}
105+
106+
private boolean hasNormalPermissions(Element element) {
107+
return element.getAnnotationMirrors().stream()
108+
.filter(this::isNeedsPermission)
109+
.anyMatch(annotationMirror -> !hasSpecialPermissions(annotationMirror));
110+
}
111+
112+
private boolean hasSpecialPermissions(AnnotationMirror annotationMirror) {
113+
String name = annotationMirror.toString();
114+
return name.contains(PERMISSION_SYSTEM_ALERT_WINDOW) || name.contains(PERMISSION_WRITE_SETTINGS);
115+
}
116+
117+
private boolean isNeedsPermission(AnnotationMirror annotationMirror) {
118+
return annotationMirror.getAnnotationType().asElement().getSimpleName().toString().equals("NeedsPermission");
119+
}
120+
}

androidannotationspermissionsdispatcherplugin/src/main/java/com/github/aleksandermielczarek/androidannotationspermissionsdispatcherplugin/PermissionDispatcherHolder.java

Lines changed: 88 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -7,72 +7,112 @@
77
import com.helger.jcodemodel.JMethod;
88
import com.helger.jcodemodel.JMod;
99
import com.helger.jcodemodel.JVar;
10+
1011
import org.androidannotations.holder.EComponentHolder;
1112
import org.androidannotations.plugin.PluginClassHolder;
1213

1314
public class PermissionDispatcherHolder extends PluginClassHolder<EComponentHolder> {
1415

15-
private JFieldVar permissionDispatcherCalledField;
16-
private JMethod onRequestPermissionsResultMethod;
17-
private JBlock onRequestPermissionsResultMethodDelegateBlock;
18-
private JVar requestCodeParam;
19-
private JVar grantResultsParam;
16+
private JFieldVar permissionDispatcherCalledField;
17+
18+
private JMethod onRequestPermissionsResultMethod;
19+
private JBlock onRequestPermissionsResultMethodDelegateBlock;
20+
private JVar onRequestPermissionsResultGrantResultsParam;
21+
private JVar onRequestPermissionsResultRequestCodeParam;
22+
23+
private JMethod onActivityResultMethod;
24+
private JBlock onActivityResultMethodDelegateBlock;
25+
private JVar onActivityResultRequestCodeParam;
26+
27+
public PermissionDispatcherHolder(EComponentHolder holder) {
28+
super(holder);
29+
}
30+
31+
public JFieldVar getPermissionDispatcherCalledField() {
32+
if (permissionDispatcherCalledField == null) {
33+
setPermissionDispatcherCalledField();
34+
}
35+
36+
return permissionDispatcherCalledField;
37+
}
38+
39+
private void setPermissionDispatcherCalledField() {
40+
permissionDispatcherCalledField = holder().getGeneratedClass().field(JMod.PRIVATE, getCodeModel().BOOLEAN, "permissionDispatcherCalled_");
41+
}
42+
43+
private void setOnRequestPermissionsResultMethod() {
44+
onRequestPermissionsResultMethod = holder().getGeneratedClass().method(JMod.PUBLIC, getCodeModel().VOID, "onRequestPermissionsResult");
45+
onRequestPermissionsResultMethod.annotate(Override.class);
46+
47+
onRequestPermissionsResultRequestCodeParam = onRequestPermissionsResultMethod.param(getCodeModel().INT, "requestCode");
48+
JVar permissionsParam = onRequestPermissionsResultMethod.param(getJClass("java.lang.String").array(), "permissions");
49+
onRequestPermissionsResultGrantResultsParam = onRequestPermissionsResultMethod.param(getCodeModel().INT.array(), "grantResults");
50+
51+
JBlock onRequestPermissionsResultMethodBody = onRequestPermissionsResultMethod.body();
2052

21-
public PermissionDispatcherHolder(EComponentHolder holder) {
22-
super(holder);
23-
}
53+
onRequestPermissionsResultMethodBody.invoke(JExpr._super(), "onRequestPermissionsResult")
54+
.arg(onRequestPermissionsResultRequestCodeParam)
55+
.arg(permissionsParam)
56+
.arg(onRequestPermissionsResultGrantResultsParam);
2457

25-
public JFieldVar getPermissionDispatcherCalledField() {
26-
if (permissionDispatcherCalledField == null) {
27-
setPermissionDispatcherCalledField();
28-
}
58+
onRequestPermissionsResultMethodDelegateBlock = onRequestPermissionsResultMethodBody.blockVirtual();
2959

30-
return permissionDispatcherCalledField;
31-
}
60+
onRequestPermissionsResultMethodBody.assign(getPermissionDispatcherCalledField(), JExpr.FALSE);
61+
}
3262

33-
private void setPermissionDispatcherCalledField() {
34-
permissionDispatcherCalledField = holder().getGeneratedClass().field(JMod.PRIVATE, getCodeModel().BOOLEAN, "permissionDispatcherCalled_");
35-
}
63+
private void setOnActivityResultMethod() {
64+
onActivityResultMethod = holder().getGeneratedClass().methods().stream()
65+
.filter(jMethod -> jMethod.name().contains("onActivityResult"))
66+
.findFirst()
67+
.orElseGet(() -> {
68+
JMethod onActivityResultMethod = holder().getGeneratedClass().method(JMod.PUBLIC, getCodeModel().VOID, "onActivityResult");
69+
onActivityResultMethod.annotate(Override.class);
3670

37-
public JMethod getOnRequestPermissionsResult() {
38-
if (onRequestPermissionsResultMethod == null) {
39-
setOnRequestPermissionsResultMethod();
40-
}
71+
onActivityResultRequestCodeParam = onActivityResultMethod.param(getCodeModel().INT, "requestCode");
72+
JVar resultCodeParam = onActivityResultMethod.param(getCodeModel().INT, "resultCode");
73+
JVar dataParam = onActivityResultMethod.param(getCodeModel().parseType("android.content.Intent"), "data");
4174

42-
return onRequestPermissionsResultMethod;
43-
}
75+
JBlock onActivityResultMethodBody = onActivityResultMethod.body();
4476

45-
private void setOnRequestPermissionsResultMethod() {
46-
onRequestPermissionsResultMethod = holder().getGeneratedClass().method(JMod.PUBLIC, getCodeModel().VOID, "onRequestPermissionsResult");
47-
onRequestPermissionsResultMethod.annotate(Override.class);
77+
onActivityResultMethodBody.invoke(JExpr._super(), "onActivityResult")
78+
.arg(onActivityResultRequestCodeParam)
79+
.arg(resultCodeParam)
80+
.arg(dataParam);
81+
return onActivityResultMethod;
82+
});
4883

49-
requestCodeParam = onRequestPermissionsResultMethod.param(getCodeModel().INT, "requestCode");
50-
JVar permissionsParam = onRequestPermissionsResultMethod.param(getJClass("java.lang.String").array(), "permissions");
51-
grantResultsParam = onRequestPermissionsResultMethod.param(getCodeModel().INT.array(), "grantResults");
84+
JBlock onActivityResultMethodBody = onActivityResultMethod.body();
85+
onActivityResultMethodDelegateBlock = onActivityResultMethodBody.blockVirtual();
5286

53-
JBlock onRequestPermissionsResultMethodBody = onRequestPermissionsResultMethod.body();
87+
if (onActivityResultRequestCodeParam == null) {
88+
onActivityResultRequestCodeParam = onActivityResultMethod.paramAtIndex(0);
89+
}
5490

55-
onRequestPermissionsResultMethodBody.invoke(JExpr._super(), "onRequestPermissionsResult")
56-
.arg(requestCodeParam)
57-
.arg(permissionsParam)
58-
.arg(grantResultsParam);
91+
onActivityResultMethodBody.assign(getPermissionDispatcherCalledField(), JExpr.FALSE);
92+
}
5993

60-
onRequestPermissionsResultMethodDelegateBlock = onRequestPermissionsResultMethodBody.blockVirtual();
94+
public void setOnRequestPermissionsResultDelegateCall(AbstractJClass delegateClass) {
95+
if (onRequestPermissionsResultMethod != null) {
96+
return;
97+
}
6198

62-
onRequestPermissionsResultMethodBody.assign(getPermissionDispatcherCalledField(), JExpr.FALSE);
63-
}
99+
setOnRequestPermissionsResultMethod();
64100

65-
public void setDelegateCall(AbstractJClass delegateClass) {
66-
if (onRequestPermissionsResultMethod != null) {
67-
return;
68-
}
101+
onRequestPermissionsResultMethodDelegateBlock.add(delegateClass.staticInvoke("onRequestPermissionsResult")
102+
.arg(JExpr._this())
103+
.arg(onRequestPermissionsResultRequestCodeParam)
104+
.arg(onRequestPermissionsResultGrantResultsParam));
105+
}
69106

70-
setOnRequestPermissionsResultMethod();
107+
public void setOnActivityResultDelegateCall(AbstractJClass delegateClass) {
108+
if (onActivityResultMethod != null) {
109+
return;
110+
}
71111

72-
onRequestPermissionsResultMethodDelegateBlock.add(delegateClass.staticInvoke("onRequestPermissionsResult")
73-
.arg(JExpr._this())
74-
.arg(requestCodeParam)
75-
.arg(grantResultsParam));
76-
}
112+
setOnActivityResultMethod();
77113

78-
}
114+
onActivityResultMethodDelegateBlock.add(delegateClass.staticInvoke("onActivityResult")
115+
.arg(JExpr._this())
116+
.arg(onActivityResultRequestCodeParam));
117+
}
118+
}

app/src/main/AndroidManifest.xml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
<manifest package="com.github.aleksandermielczarek.androidannotationspermissionsdispatcherpluginexample"
2-
xmlns:android="http://schemas.android.com/apk/res/android">
1+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2+
package="com.github.aleksandermielczarek.androidannotationspermissionsdispatcherpluginexample">
33

4-
<uses-permission android:name="android.permission.CAMERA"/>
4+
<uses-permission android:name="android.permission.CAMERA" />
5+
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
6+
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
57

68
<application
79
android:allowBackup="true"
@@ -12,8 +14,8 @@
1214

1315
<activity android:name=".MainActivity_">
1416
<intent-filter>
15-
<action android:name="android.intent.action.MAIN"/>
16-
<category android:name="android.intent.category.LAUNCHER"/>
17+
<action android:name="android.intent.action.MAIN" />
18+
<category android:name="android.intent.category.LAUNCHER" />
1719
</intent-filter>
1820

1921
</activity>

app/src/main/java/com/github/aleksandermielczarek/androidannotationspermissionsdispatcherpluginexample/MainActivity.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package com.github.aleksandermielczarek.androidannotationspermissionsdispatcherpluginexample;
22

33
import android.Manifest;
4+
import android.content.Intent;
45
import android.support.v7.app.AppCompatActivity;
56
import android.widget.Toast;
67

78
import org.androidannotations.annotations.Click;
89
import org.androidannotations.annotations.EActivity;
10+
import org.androidannotations.annotations.OnActivityResult;
911

1012
import permissions.dispatcher.NeedsPermission;
1113
import permissions.dispatcher.OnNeverAskAgain;
@@ -41,4 +43,13 @@ protected void showNeverAskForCamera() {
4143
Toast.makeText(this, "OnNeverAskAgain for camera", Toast.LENGTH_SHORT).show();
4244
}
4345

44-
}
46+
@NeedsPermission(Manifest.permission.WRITE_SETTINGS)
47+
protected void writeSettings() {
48+
Toast.makeText(this, "Permission for write settings granted", Toast.LENGTH_SHORT).show();
49+
}
50+
51+
@OnActivityResult(10)
52+
protected void onResult(int resultCode, Intent data) {
53+
54+
}
55+
}

app/src/main/java/com/github/aleksandermielczarek/androidannotationspermissionsdispatcherpluginexample/MainFragment.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,4 @@ protected void showRationaleForCamera(PermissionRequest request) {
4040
protected void showNeverAskForCamera() {
4141
Toast.makeText(getContext(), "OnNeverAskAgain for camera in fragment", Toast.LENGTH_SHORT).show();
4242
}
43-
44-
}
43+
}

0 commit comments

Comments
 (0)