Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
A
appinventor-sources
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
xpstem
appinventor-sources
Commits
20fd772d
Commit
20fd772d
authored
Sep 10, 2021
by
Evan W. Patton
Committed by
Jeffrey Schiller
Oct 22, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement @UsesQueries for SDK 30 <queries> manifest emelent
Change-Id: I2c608f084512171bb91b4c72338c4fd9af4a6304
parent
48dbedf4
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
196 additions
and
24 deletions
+196
-24
appinventor/buildserver/src/com/google/appinventor/buildserver/Compiler.java
...rver/src/com/google/appinventor/buildserver/Compiler.java
+47
-8
appinventor/components/src/com/google/appinventor/components/annotations/UsesQueries.java
...oogle/appinventor/components/annotations/UsesQueries.java
+35
-0
appinventor/components/src/com/google/appinventor/components/common/ComponentDescriptorConstants.java
...entor/components/common/ComponentDescriptorConstants.java
+1
-0
appinventor/components/src/com/google/appinventor/components/scripts/ComponentDescriptorGenerator.java
...ntor/components/scripts/ComponentDescriptorGenerator.java
+13
-4
appinventor/components/src/com/google/appinventor/components/scripts/ComponentListGenerator.java
...ppinventor/components/scripts/ComponentListGenerator.java
+8
-4
appinventor/components/src/com/google/appinventor/components/scripts/ComponentProcessor.java
...le/appinventor/components/scripts/ComponentProcessor.java
+92
-8
No files found.
appinventor/buildserver/src/com/google/appinventor/buildserver/Compiler.java
View file @
20fd772d
...
...
@@ -221,6 +221,8 @@ public final class Compiler {
new
ConcurrentHashMap
<
String
,
Set
<
String
>>();
private
final
ConcurrentMap
<
String
,
Set
<
String
>>
broadcastReceiversNeeded
=
new
ConcurrentHashMap
<
String
,
Set
<
String
>>();
private
final
ConcurrentMap
<
String
,
Set
<
String
>>
queriesNeeded
=
new
ConcurrentHashMap
<>();
private
final
ConcurrentMap
<
String
,
Set
<
String
>>
servicesNeeded
=
new
ConcurrentHashMap
<
String
,
Set
<
String
>>();
private
final
ConcurrentMap
<
String
,
Set
<
String
>>
contentProvidersNeeded
=
...
...
@@ -480,6 +482,11 @@ public final class Compiler {
return
broadcastReceiversNeeded
;
}
@VisibleForTesting
Map
<
String
,
Set
<
String
>>
getQueries
()
{
return
queriesNeeded
;
}
// Just used for testing
@VisibleForTesting
Map
<
String
,
Set
<
String
>>
getServices
()
{
...
...
@@ -672,6 +679,24 @@ public final class Compiler {
mergeConditionals
(
conditionals
.
get
(
ComponentDescriptorConstants
.
BROADCAST_RECEIVERS_TARGET
),
broadcastReceiversNeeded
);
}
/*
* Generate a set of conditionally included queries needed by this project.
*/
@VisibleForTesting
void
generateQueries
()
{
try
{
loadJsonInfo
(
queriesNeeded
,
ComponentDescriptorConstants
.
QUERIES_TARGET
);
}
catch
(
IOException
e
)
{
// This is fatal.
userErrors
.
print
(
String
.
format
(
ERROR_IN_STAGE
,
"Services"
));
}
catch
(
JSONException
e
)
{
// This is fatal, but shouldn't actually ever happen.
userErrors
.
print
(
String
.
format
(
ERROR_IN_STAGE
,
"Services"
));
}
mergeConditionals
(
conditionals
.
get
(
ComponentDescriptorConstants
.
QUERIES_TARGET
),
queriesNeeded
);
}
/*
* Generate a set of conditionally included services needed by this project.
*/
...
...
@@ -1056,6 +1081,18 @@ public final class Compiler {
}
}
if
(
queriesNeeded
.
size
()
>
0
)
{
out
.
write
(
" <queries>\n"
);
for
(
Map
.
Entry
<
String
,
Set
<
String
>>
componentSubElSetPair
:
queriesNeeded
.
entrySet
())
{
Set
<
String
>
subelementSet
=
componentSubElSetPair
.
getValue
();
for
(
String
subelement
:
subelementSet
)
{
// replace %packageName% with the actual packageName
out
.
write
(
subelement
.
replace
(
"%packageName%"
,
packageName
));
}
}
out
.
write
(
" </queries>\n"
);
}
int
minSdk
=
Integer
.
parseInt
((
project
.
getMinSdk
()
==
null
)
?
DEFAULT_MIN_SDK
:
project
.
getMinSdk
());
if
(!
isForCompanion
)
{
for
(
Set
<
String
>
minSdks
:
minSdksNeeded
.
values
())
{
...
...
@@ -1390,28 +1427,30 @@ public final class Compiler {
reporter
.
report
(
0
);
}
statReporter
.
nextStage
(
compiler
,
"generateAssets"
);
compiler
.
generateAssets
();
statReporter
.
nextStage
(
compiler
,
"generateActivities"
);
compiler
.
generateActivities
();
statReporter
.
nextStage
(
compiler
,
"generateMetadata"
);
compiler
.
generateMetadata
();
statReporter
.
nextStage
(
compiler
,
"generateActivityMetadata"
);
compiler
.
generateActivityMetadata
();
statReporter
.
nextStage
(
compiler
,
"generateAssets"
);
compiler
.
generateAssets
();
statReporter
.
nextStage
(
compiler
,
"generateBroadcastReceivers"
);
compiler
.
generateBroadcastReceivers
();
statReporter
.
nextStage
(
compiler
,
"generateServices"
);
compiler
.
generateServices
();
statReporter
.
nextStage
(
compiler
,
"generateContentProviders"
);
compiler
.
generateContentProviders
();
statReporter
.
nextStage
(
compiler
,
"generateLibNames"
);
compiler
.
generateLibNames
();
statReporter
.
nextStage
(
compiler
,
"generateMetadata"
);
compiler
.
generateMetadata
();
statReporter
.
nextStage
(
compiler
,
"generateMinSdks"
);
compiler
.
generateMinSdks
();
statReporter
.
nextStage
(
compiler
,
"generateNativeLibNames"
);
compiler
.
generateNativeLibNames
();
statReporter
.
nextStage
(
compiler
,
"generatePermissions"
);
compiler
.
generatePermissions
();
statReporter
.
nextStage
(
compiler
,
"generateMinSdks"
);
compiler
.
generateMinSdks
();
statReporter
.
nextStage
(
compiler
,
"generateQueries"
);
compiler
.
generateQueries
();
statReporter
.
nextStage
(
compiler
,
"generateServices"
);
compiler
.
generateServices
();
// TODO(Will): Remove the following call once the deprecated
// @SimpleBroadcastReceiver annotation is removed. It should
...
...
appinventor/components/src/com/google/appinventor/components/annotations/UsesQueries.java
0 → 100644
View file @
20fd772d
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2021 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
package
com.google.appinventor.components.annotations
;
import
com.google.appinventor.components.annotations.androidmanifest.IntentFilterElement
;
import
com.google.appinventor.components.annotations.androidmanifest.ProviderElement
;
/**
* Annotation to describe a <queries> entry required by Android SDK 30.
*/
public
@interface
UsesQueries
{
/**
* An array of intents that will be included in the <queries> element.
*
* @return the array of intents of interest
*/
IntentFilterElement
[]
intents
()
default
{};
/**
* A package name that will be included in the <queries> element.
*
* @return the array containing package names of interest
*/
String
[]
packageNames
()
default
{};
/**
* A provider element that will be included in the <queries>
*
* @return the array containing provider elements of interest
*/
ProviderElement
[]
providers
()
default
{};
}
appinventor/components/src/com/google/appinventor/components/common/ComponentDescriptorConstants.java
View file @
20fd772d
...
...
@@ -26,6 +26,7 @@ public final class ComponentDescriptorConstants {
public
static
final
String
NATIVE_TARGET
=
"native"
;
public
static
final
String
PERMISSIONS_TARGET
=
"permissions"
;
public
static
final
String
BROADCAST_RECEIVERS_TARGET
=
"broadcastReceivers"
;
public
static
final
String
QUERIES_TARGET
=
"queries"
;
public
static
final
String
SERVICES_TARGET
=
"services"
;
public
static
final
String
CONTENT_PROVIDERS_TARGET
=
"contentProviders"
;
public
static
final
String
ANDROIDMINSDK_TARGET
=
"androidMinSdk"
;
...
...
appinventor/components/src/com/google/appinventor/components/scripts/ComponentDescriptorGenerator.java
View file @
20fd772d
...
...
@@ -250,10 +250,11 @@ public final class ComponentDescriptorGenerator extends ComponentProcessor {
* @param sb The StringBuilder to receive the JSON descriptor.
*/
private
void
outputConditionalAnnotations
(
ComponentInfo
component
,
StringBuilder
sb
)
{
if
(
component
.
conditionalPermissions
.
size
()
+
component
.
conditionalBroadcastReceivers
.
size
()
+
component
.
conditionalServices
.
size
()
+
component
.
conditionalContentProviders
.
size
()
==
0
)
{
if
(
component
.
conditionalBroadcastReceivers
.
size
()
+
component
.
conditionalContentProviders
.
size
()
+
component
.
conditionalPermissions
.
size
()
+
component
.
conditionalQueries
.
size
()
+
component
.
conditionalServices
.
size
()
==
0
)
{
return
;
}
sb
.
append
(
",\n \"conditionals\":{\n "
);
...
...
@@ -269,6 +270,14 @@ public final class ComponentDescriptorGenerator extends ComponentProcessor {
outputMultimap
(
sb
,
" "
,
component
.
conditionalBroadcastReceivers
);
first
=
false
;
}
if
(
component
.
conditionalQueries
.
size
()
>
0
)
{
if
(!
first
)
{
sb
.
append
(
",\n "
);
}
sb
.
append
(
"\"queries\": "
);
outputMultimap
(
sb
,
" "
,
component
.
conditionalQueries
);
first
=
false
;
}
if
(
component
.
conditionalServices
.
size
()
>
0
)
{
if
(!
first
)
sb
.
append
(
",\n "
);
sb
.
append
(
"\"services\": "
);
...
...
appinventor/components/src/com/google/appinventor/components/scripts/ComponentListGenerator.java
View file @
20fd772d
...
...
@@ -85,6 +85,7 @@ public final class ComponentListGenerator extends ComponentProcessor {
appendComponentInfo
(
sb
,
ComponentDescriptorConstants
.
ACTIVITY_METADATA_TARGET
,
component
.
activityMetadata
);
appendComponentInfo
(
sb
,
ComponentDescriptorConstants
.
ANDROIDMINSDK_TARGET
,
Collections
.
singleton
(
Integer
.
toString
(
component
.
getAndroidMinSdk
())));
appendComponentInfo
(
sb
,
ComponentDescriptorConstants
.
BROADCAST_RECEIVERS_TARGET
,
component
.
broadcastReceivers
);
appendComponentInfo
(
sb
,
ComponentDescriptorConstants
.
QUERIES_TARGET
,
component
.
queries
);
appendComponentInfo
(
sb
,
ComponentDescriptorConstants
.
SERVICES_TARGET
,
component
.
services
);
appendComponentInfo
(
sb
,
ComponentDescriptorConstants
.
CONTENT_PROVIDERS_TARGET
,
component
.
contentProviders
);
appendConditionalComponentInfo
(
component
,
sb
);
...
...
@@ -104,10 +105,11 @@ public final class ComponentListGenerator extends ComponentProcessor {
* @param sb Target StringBuilder to receive the conditional description
*/
private
static
void
appendConditionalComponentInfo
(
ComponentInfo
component
,
StringBuilder
sb
)
{
if
(
component
.
conditionalPermissions
.
size
()
+
component
.
conditionalBroadcastReceivers
.
size
()
+
component
.
conditionalServices
.
size
()
+
component
.
conditionalContentProviders
.
size
()
==
0
)
{
if
(
component
.
conditionalBroadcastReceivers
.
size
()
+
component
.
conditionalContentProviders
.
size
()
+
component
.
conditionalPermissions
.
size
()
+
component
.
conditionalQueries
.
size
()
+
component
.
conditionalServices
.
size
()
==
0
)
{
return
;
}
sb
.
append
(
", \""
+
ComponentDescriptorConstants
.
CONDITIONALS_TARGET
+
"\": { "
);
...
...
@@ -115,6 +117,8 @@ public final class ComponentListGenerator extends ComponentProcessor {
appendMap
(
sb
,
component
.
conditionalPermissions
);
sb
.
append
(
", \""
+
ComponentDescriptorConstants
.
BROADCAST_RECEIVERS_TARGET
+
"\": "
);
appendMap
(
sb
,
component
.
conditionalBroadcastReceivers
);
sb
.
append
(
", \""
+
ComponentDescriptorConstants
.
QUERIES_TARGET
+
"\": "
);
appendMap
(
sb
,
component
.
conditionalQueries
);
sb
.
append
(
", \""
+
ComponentDescriptorConstants
.
SERVICES_TARGET
+
"\": "
);
appendMap
(
sb
,
component
.
conditionalServices
);
sb
.
append
(
", \""
+
ComponentDescriptorConstants
.
CONTENT_PROVIDERS_TARGET
+
"\": "
);
...
...
appinventor/components/src/com/google/appinventor/components/scripts/ComponentProcessor.java
View file @
20fd772d
...
...
@@ -24,6 +24,7 @@ import com.google.appinventor.components.annotations.UsesPermissions;
import
com.google.appinventor.components.annotations.UsesActivities
;
import
com.google.appinventor.components.annotations.UsesBroadcastReceivers
;
import
com.google.appinventor.components.annotations.UsesContentProviders
;
import
com.google.appinventor.components.annotations.UsesQueries
;
import
com.google.appinventor.components.annotations.UsesServices
;
import
com.google.appinventor.components.annotations.androidmanifest.ActivityElement
;
import
com.google.appinventor.components.annotations.androidmanifest.ReceiverElement
;
...
...
@@ -160,6 +161,7 @@ public abstract class ComponentProcessor extends AbstractProcessor {
"com.google.appinventor.components.annotations.UsesActivities"
,
"com.google.appinventor.components.annotations.UsesBroadcastReceivers"
,
"com.google.appinventor.components.annotations.UsesPermissions"
,
"com.google.appinventor.components.annotations.UsesQueries"
,
"com.google.appinventor.components.annotations.UsesServices"
,
"com.google.appinventor.components.annotations.UsesContentProviders"
);
...
...
@@ -1086,6 +1088,12 @@ public abstract class ComponentProcessor extends AbstractProcessor {
*/
protected
final
Map
<
String
,
String
[]>
conditionalBroadcastReceivers
;
/**
* Mapping of component block names to queries that should be included
* if the block is used.
*/
protected
final
Map
<
String
,
String
[]>
conditionalQueries
;
/**
* Mapping of component block names to services that should be
* included if the block is used.
...
...
@@ -1133,6 +1141,11 @@ public abstract class ComponentProcessor extends AbstractProcessor {
*/
protected
final
Set
<
String
>
broadcastReceivers
;
/**
* Queries required by this component.
*/
protected
final
Set
<
String
>
queries
;
/**
* Services required by this component.
*/
...
...
@@ -1214,21 +1227,26 @@ public abstract class ComponentProcessor extends AbstractProcessor {
"Component"
,
false
,
elementUtils
.
isDeprecated
(
element
));
type
=
element
.
asType
().
toString
();
displayName
=
getDisplayNameForComponentType
(
name
);
permissions
=
Sets
.
newHashSet
();
conditionalPermissions
=
Maps
.
newTreeMap
();
conditionalBroadcastReceivers
=
Maps
.
newTreeMap
();
conditionalServices
=
Maps
.
newTreeMap
();
conditionalContentProviders
=
Maps
.
newTreeMap
();
libraries
=
Sets
.
newHashSet
();
nativeLibraries
=
Sets
.
newHashSet
();
conditionalPermissions
=
Maps
.
newTreeMap
();
conditionalQueries
=
Maps
.
newTreeMap
();
conditionalServices
=
Maps
.
newTreeMap
();
assets
=
Sets
.
newHashSet
();
activities
=
Sets
.
newHashSet
();
metadata
=
Sets
.
newHashSet
();
activityMetadata
=
Sets
.
newHashSet
();
broadcastReceivers
=
Sets
.
newHashSet
();
services
=
Sets
.
newHashSet
();
contentProviders
=
Sets
.
newHashSet
();
classNameAndActionsBR
=
Sets
.
newHashSet
();
contentProviders
=
Sets
.
newHashSet
();
libraries
=
Sets
.
newHashSet
();
metadata
=
Sets
.
newHashSet
();
nativeLibraries
=
Sets
.
newHashSet
();
permissions
=
Sets
.
newHashSet
();
queries
=
Sets
.
newHashSet
();
services
=
Sets
.
newHashSet
();
designerProperties
=
Maps
.
newTreeMap
();
properties
=
Maps
.
newTreeMap
();
methods
=
Maps
.
newTreeMap
();
...
...
@@ -1587,6 +1605,7 @@ public abstract class ComponentProcessor extends AbstractProcessor {
componentInfo
.
metadata
.
addAll
(
parentComponent
.
metadata
);
componentInfo
.
activityMetadata
.
addAll
(
parentComponent
.
activityMetadata
);
componentInfo
.
broadcastReceivers
.
addAll
(
parentComponent
.
broadcastReceivers
);
componentInfo
.
queries
.
addAll
(
parentComponent
.
queries
);
componentInfo
.
services
.
addAll
(
parentComponent
.
services
);
componentInfo
.
contentProviders
.
addAll
(
parentComponent
.
contentProviders
);
// TODO(Will): Remove the following call once the deprecated
...
...
@@ -1730,6 +1749,30 @@ public abstract class ComponentProcessor extends AbstractProcessor {
}
}
// Gather the required queries and build their element strings.
UsesQueries
usesQueries
=
element
.
getAnnotation
(
UsesQueries
.
class
);
if
(
usesQueries
!=
null
)
{
try
{
for
(
String
packageName
:
usesQueries
.
packageNames
())
{
componentInfo
.
queries
.
add
(
"<package android:name=\""
+
packageName
+
"\" />"
);
}
for
(
IntentFilterElement
intent
:
usesQueries
.
intents
())
{
updateWithNonEmptyValue
(
componentInfo
.
queries
,
intentFilterElementToIntentString
(
intent
));
}
for
(
ProviderElement
provider
:
usesQueries
.
providers
())
{
updateWithNonEmptyValue
(
componentInfo
.
queries
,
providerElementToString
(
provider
));
}
}
catch
(
IllegalAccessException
e
)
{
messager
.
printMessage
(
Diagnostic
.
Kind
.
ERROR
,
"IllegalAccessException when gathering "
+
"service attributes and subelements for component "
+
componentInfo
.
name
);
throw
new
RuntimeException
(
e
);
}
catch
(
InvocationTargetException
e
)
{
messager
.
printMessage
(
Diagnostic
.
Kind
.
ERROR
,
"InvocationTargetException when gathering "
+
"service attributes and subelements for component "
+
componentInfo
.
name
);
throw
new
RuntimeException
(
e
);
}
}
// Gather the required services and build their element strings.
UsesServices
usesServices
=
element
.
getAnnotation
(
UsesServices
.
class
);
if
(
usesServices
!=
null
)
{
...
...
@@ -2279,6 +2322,21 @@ public abstract class ComponentProcessor extends AbstractProcessor {
return
elementString
.
append
(
" </intent-filter>\\n"
).
toString
();
}
private
static
String
intentFilterElementToIntentString
(
IntentFilterElement
element
)
throws
IllegalAccessException
,
InvocationTargetException
{
// First, we build the <intent-filter> element's opening tag including any
// receiver element attributes.
StringBuilder
elementString
=
new
StringBuilder
(
" <intent>\\n"
);
// Now, we collect any <intent-filter> subelements.
elementString
.
append
(
subelementsToString
(
element
.
actionElements
()));
elementString
.
append
(
subelementsToString
(
element
.
categoryElements
()));
elementString
.
append
(
subelementsToString
(
element
.
dataElements
()));
// Finally, we close the <intent-filter> element and create its String.
return
elementString
.
append
(
" </intent>\\n"
).
toString
();
}
// Transform an @ActionElement into an XML element String for use later
// in creating AndroidManifest.xml.
private
static
String
actionElementToString
(
ActionElement
element
)
...
...
@@ -2686,6 +2744,32 @@ public abstract class ComponentProcessor extends AbstractProcessor {
}
}
// Gather the required queries and build their element strings.
UsesQueries
usesQueries
=
element
.
getAnnotation
(
UsesQueries
.
class
);
if
(
usesQueries
!=
null
)
{
try
{
Set
<
String
>
queries
=
new
HashSet
<>();
for
(
String
packageName
:
usesQueries
.
packageNames
())
{
updateWithNonEmptyValue
(
queries
,
"<package android:name=\""
+
packageName
+
"\" />"
);
}
for
(
IntentFilterElement
intent
:
usesQueries
.
intents
())
{
updateWithNonEmptyValue
(
queries
,
intentFilterElementToIntentString
(
intent
));
}
for
(
ProviderElement
provider
:
usesQueries
.
providers
())
{
updateWithNonEmptyValue
(
queries
,
providerElementToString
(
provider
));
}
componentInfo
.
conditionalQueries
.
put
(
blockName
,
queries
.
toArray
(
new
String
[
0
]));
}
catch
(
IllegalAccessException
e
)
{
messager
.
printMessage
(
Diagnostic
.
Kind
.
ERROR
,
"IllegalAccessException when gathering "
+
"service attributes and subelements for component "
+
componentInfo
.
name
);
throw
new
RuntimeException
(
e
);
}
catch
(
InvocationTargetException
e
)
{
messager
.
printMessage
(
Diagnostic
.
Kind
.
ERROR
,
"InvocationTargetException when gathering "
+
"service attributes and subelements for component "
+
componentInfo
.
name
);
throw
new
RuntimeException
(
e
);
}
}
UsesServices
service
=
element
.
getAnnotation
(
UsesServices
.
class
);
if
(
service
!=
null
)
{
try
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment