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
c503528d
Unverified
Commit
c503528d
authored
Jul 01, 2020
by
Shreyash Saitwal
Committed by
GitHub
Jun 30, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement annotations for Services and Content Providers (#2217)
parent
1843bdd6
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
952 additions
and
12 deletions
+952
-12
appinventor/buildserver/src/com/google/appinventor/buildserver/Compiler.java
...rver/src/com/google/appinventor/buildserver/Compiler.java
+65
-3
appinventor/components/src/com/google/appinventor/components/annotations/UsesContentProviders.java
...inventor/components/annotations/UsesContentProviders.java
+33
-0
appinventor/components/src/com/google/appinventor/components/annotations/UsesServices.java
...ogle/appinventor/components/annotations/UsesServices.java
+33
-0
appinventor/components/src/com/google/appinventor/components/annotations/androidmanifest/GrantUriPermissionElement.java
...nnotations/androidmanifest/GrantUriPermissionElement.java
+78
-0
appinventor/components/src/com/google/appinventor/components/annotations/androidmanifest/PathPermissionElement.java
...ts/annotations/androidmanifest/PathPermissionElement.java
+91
-0
appinventor/components/src/com/google/appinventor/components/annotations/androidmanifest/ProviderElement.java
...mponents/annotations/androidmanifest/ProviderElement.java
+262
-0
appinventor/components/src/com/google/appinventor/components/annotations/androidmanifest/ServiceElement.java
...omponents/annotations/androidmanifest/ServiceElement.java
+194
-0
appinventor/components/src/com/google/appinventor/components/common/ComponentDescriptorConstants.java
...entor/components/common/ComponentDescriptorConstants.java
+2
-0
appinventor/components/src/com/google/appinventor/components/scripts/ComponentDescriptorGenerator.java
...ntor/components/scripts/ComponentDescriptorGenerator.java
+15
-1
appinventor/components/src/com/google/appinventor/components/scripts/ComponentListGenerator.java
...ppinventor/components/scripts/ComponentListGenerator.java
+11
-3
appinventor/components/src/com/google/appinventor/components/scripts/ComponentProcessor.java
...le/appinventor/components/scripts/ComponentProcessor.java
+168
-5
No files found.
appinventor/buildserver/src/com/google/appinventor/buildserver/Compiler.java
View file @
c503528d
...
...
@@ -170,6 +170,10 @@ 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
>>
servicesNeeded
=
new
ConcurrentHashMap
<
String
,
Set
<
String
>>();
private
final
ConcurrentMap
<
String
,
Set
<
String
>>
contentProvidersNeeded
=
new
ConcurrentHashMap
<
String
,
Set
<
String
>>();
private
final
ConcurrentMap
<
String
,
Set
<
String
>>
libsNeeded
=
new
ConcurrentHashMap
<
String
,
Set
<
String
>>();
private
final
ConcurrentMap
<
String
,
Set
<
String
>>
nativeLibsNeeded
=
...
...
@@ -420,6 +424,18 @@ public final class Compiler {
return
broadcastReceiversNeeded
;
}
// Just used for testing
@VisibleForTesting
Map
<
String
,
Set
<
String
>>
getServices
()
{
return
servicesNeeded
;
}
// Just used for testing
@VisibleForTesting
Map
<
String
,
Set
<
String
>>
getContentProviders
()
{
return
contentProvidersNeeded
;
}
// Just used for testing
@VisibleForTesting
Map
<
String
,
Set
<
String
>>
getActivities
()
{
...
...
@@ -600,6 +616,46 @@ public final class Compiler {
mergeConditionals
(
conditionals
.
get
(
ComponentDescriptorConstants
.
BROADCAST_RECEIVERS_TARGET
),
broadcastReceiversNeeded
);
}
/*
* Generate a set of conditionally included services needed by this project.
*/
@VisibleForTesting
void
generateServices
()
{
try
{
loadJsonInfo
(
servicesNeeded
,
ComponentDescriptorConstants
.
SERVICES_TARGET
);
}
catch
(
IOException
e
)
{
// This is fatal.
e
.
printStackTrace
();
userErrors
.
print
(
String
.
format
(
ERROR_IN_STAGE
,
"Services"
));
}
catch
(
JSONException
e
)
{
// This is fatal, but shouldn't actually ever happen.
e
.
printStackTrace
();
userErrors
.
print
(
String
.
format
(
ERROR_IN_STAGE
,
"Services"
));
}
mergeConditionals
(
conditionals
.
get
(
ComponentDescriptorConstants
.
SERVICES_TARGET
),
servicesNeeded
);
}
/*
* Generate a set of conditionally included content providers needed by this project.
*/
@VisibleForTesting
void
generateContentProviders
()
{
try
{
loadJsonInfo
(
contentProvidersNeeded
,
ComponentDescriptorConstants
.
CONTENT_PROVIDERS_TARGET
);
}
catch
(
IOException
e
)
{
// This is fatal.
e
.
printStackTrace
();
userErrors
.
print
(
String
.
format
(
ERROR_IN_STAGE
,
"Content Providers"
));
}
catch
(
JSONException
e
)
{
// This is fatal, but shouldn't actually ever happen.
e
.
printStackTrace
();
userErrors
.
print
(
String
.
format
(
ERROR_IN_STAGE
,
"Content Providers"
));
}
mergeConditionals
(
conditionals
.
get
(
ComponentDescriptorConstants
.
CONTENT_PROVIDERS_TARGET
),
contentProvidersNeeded
);
}
/*
* TODO(Will): Remove this method once the deprecated @SimpleBroadcastReceiver
* annotation is removed. This should remain for the time being so
...
...
@@ -1119,10 +1175,13 @@ public final class Compiler {
subelements
.
addAll
(
activitiesNeeded
.
entrySet
());
subelements
.
addAll
(
metadataNeeded
.
entrySet
());
subelements
.
addAll
(
broadcastReceiversNeeded
.
entrySet
());
subelements
.
addAll
(
servicesNeeded
.
entrySet
());
subelements
.
addAll
(
contentProvidersNeeded
.
entrySet
());
// If any component needs to register additional activities or
// broadcast receivers, insert them into the manifest here.
// If any component needs to register additional activities,
// broadcast receivers, services or content providers, insert
// them into the manifest here.
if
(!
subelements
.
isEmpty
())
{
for
(
Map
.
Entry
<
String
,
Set
<
String
>>
componentSubElSetPair
:
subelements
)
{
Set
<
String
>
subelementSet
=
componentSubElSetPair
.
getValue
();
...
...
@@ -1234,6 +1293,8 @@ public final class Compiler {
compiler
.
generateMetadata
();
compiler
.
generateActivityMetadata
();
compiler
.
generateBroadcastReceivers
();
compiler
.
generateServices
();
compiler
.
generateContentProviders
();
compiler
.
generateLibNames
();
compiler
.
generateNativeLibNames
();
compiler
.
generatePermissions
();
...
...
@@ -2514,7 +2575,8 @@ public final class Compiler {
* @param type The name of the type being processed
* @param targetInfo Name of the annotation target being processed (e.g.,
* permissions). Any of: PERMISSIONS_TARGET,
* BROADCAST_RECEIVERS_TARGET
* BROADCAST_RECEIVERS_TARGET, SERVICES_TARGET,
* CONTENT_PROVIDERS_TARGET
*/
private
void
processConditionalInfo
(
JSONObject
compJson
,
String
type
,
String
targetInfo
)
{
// Strip off the package name since SCM and BKY use unqualified names
...
...
appinventor/components/src/com/google/appinventor/components/annotations/UsesContentProviders.java
0 → 100644
View file @
c503528d
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2020 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.ProviderElement
;
import
java.lang.annotation.ElementType
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.Target
;
/**
* Annotation to indicate any content providers used by
* a component so that corresponding <provider> elements can be
* created in AndroidManifest.xml.
*
* @author https://github.com/ShreyashSaitwal (Shreyash Saitwal)
*/
@Retention
(
RetentionPolicy
.
RUNTIME
)
@Target
({
ElementType
.
TYPE
,
ElementType
.
METHOD
})
public
@interface
UsesContentProviders
{
/**
* An array containing each {@link ProviderElement}
* that is required by the component.
*
* @return the array containing the relevant providers
*/
ProviderElement
[]
providers
();
}
appinventor/components/src/com/google/appinventor/components/annotations/UsesServices.java
0 → 100644
View file @
c503528d
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2020 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.ServiceElement
;
import
java.lang.annotation.ElementType
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.Target
;
/**
* Annotation to indicate any services used by
* a component so that corresponding <service> elements can be
* created in AndroidManifest.xml.
*
* @author https://github.com/ShreyashSaitwal (Shreyash Saitwal)
*/
@Retention
(
RetentionPolicy
.
RUNTIME
)
@Target
({
ElementType
.
TYPE
,
ElementType
.
METHOD
})
public
@interface
UsesServices
{
/**
* An array containing each {@link ServiceElement}
* that is required by the component.
*
* @return the array containing the relevant services
*/
ServiceElement
[]
services
();
}
appinventor/components/src/com/google/appinventor/components/annotations/androidmanifest/GrantUriPermissionElement.java
0 → 100644
View file @
c503528d
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2020 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.androidmanifest
;
import
java.lang.annotation.ElementType
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.Target
;
/**
* Specifies the subsets of app data that the parent content provider has permission to access.
* Data subsets are indicated by the path part of a content: URI. (The authority part of the URI
* identifies the content provider.) Granting permission is a way of enabling clients of the <provider>
* that don't normally have permission to access its data to overcome that restriction on a one-time
* basis.
*
* If a content provider's grantUriPermissions attribute is "true", permission can be granted for
* any the data under the provider's purview. However, if that attribute is "false", permission can
* be granted only to data subsets that are specified by this element. A provider can contain any
* number of <grant-uri-permission> elements. Each one can specify only one path (only one of the
* three possible attributes).
*
* Note: Most of this documentation is adapted from the Android framework specification
* linked below. That documentation is licensed under the
* {@link <a href="https://creativecommons.org/licenses/by/2.5/">
* Creative Commons Attribution license v2.5
* </a>}.
*
* See {@link <a href="https://developer.android.com/guide/topics/manifest/grant-uri-permission-element">
* https://developer.android.com/guide/topics/manifest/grant-uri-permission-element
* </a>}.
*
* @author https://github.com/ShreyashSaitwal (Shreyash Saitwal)
*/
@Retention
(
RetentionPolicy
.
RUNTIME
)
@Target
(
ElementType
.
TYPE
)
public
@interface
GrantUriPermissionElement
{
/**
* A complete URI path for a subset of content provider data. Permission can be granted only
* to the particular data identified by this path. When used to provide search suggestion
* content, it must be appended with "/search_suggest_query".
*
* @return the grant uri permission path attribute
*/
String
path
()
default
""
;
/**
* The initial part of a URI path for a subset of content provider data. Permission can be
* granted to all data subsets with paths that share this initial part.
*
* @return the grant uri permission pathPrefix attribute
*/
String
pathPrefix
()
default
""
;
/**
* A path identifying the data subset or subsets that permission can be granted for. The path
* attribute specifies a complete path; permission can be granted only to the particular data
* subset identified by that path. The pathPrefix attribute specifies the initial part of a path;
* permission can be granted to all data subsets with paths that share that initial part. The
* pathPattern attribute specifies a complete path, but one that can contain the following wildcards:
* - An asterisk ('*') matches a sequence of 0 to many occurrences of the immediately preceding
* character.
* - A period followed by an asterisk (".*") matches any sequence of 0 to many characters.
* Because '\' is used as an escape character when the string is read from XML (before it is parsed
* as a pattern), you will need to double-escape: For example, a literal '*' would be written as "\\*"
* and a literal '\' would be written as "\\\\". This is basically the same as what you would need to
* write if constructing the string in Java code.
*
* @return the grant uri permission pathPattern attribute respectively
*/
String
pathPattern
()
default
""
;
}
appinventor/components/src/com/google/appinventor/components/annotations/androidmanifest/PathPermissionElement.java
0 → 100644
View file @
c503528d
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2020 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.androidmanifest
;
import
java.lang.annotation.ElementType
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.Target
;
/**
* Defines the path and required permissions for a specific subset of data within a
* <provider>. This element can be specified multiple times to supply multiple paths.
*
* Note: Most of this documentation is adapted from the Android framework specification
* linked below. That documentation is licensed under the
* {@link <a href="https://creativecommons.org/licenses/by/2.5/">
* Creative Commons Attribution license v2.5
* </a>}.
*
* See {@link <a href="https://developer.android.com/guide/topics/manifest/path-permission-element">
* https://developer.android.com/guide/topics/manifest/path-permission-element
* </a>}.
*
* @author https://github.com/ShreyashSaitwal (Shreyash Saitwal)
*/
@Retention
(
RetentionPolicy
.
RUNTIME
)
@Target
(
ElementType
.
TYPE
)
public
@interface
PathPermissionElement
{
/**
* A complete URI path for a subset of content provider data. Permission can be granted only
* to the particular data identified by this path. When used to provide search suggestion
* content, it must be appended with "/search_suggest_query".
*
* @return the path permission path attribute
*/
String
path
()
default
""
;
/**
* The initial part of a URI path for a subset of content provider data. Permission can be
* granted to all data subsets with paths that share this initial part.
*
* @return the path permission pathPrefix attribute
*/
String
pathPrefix
()
default
""
;
/**
* A complete URI path for a subset of content provider data, but one that can use the following
* wildcards:
* - An asterisk ('*'). This matches a sequence of 0 to many occurrences of the immediately
* preceding character.
* - A period followed by an asterisk (".*"). This matches any sequence of 0 or more characters.
*
* Because '\' is used as an escape character when the string is read from XML (before it is parsed
* as a pattern), you will need to double-escape. For example, a literal '*' would be written as "\\*"
* and a literal '\' would be written as "\\". This is basically the same as what you would need to
* write if constructing the string in Java code.
*
* @return the path permission pathPattern attribute
*/
String
pathPattern
()
default
""
;
/**
* The name of a permission that clients must have in order to read or write the content provider's
* data. This attribute is a convenient way of setting a single permission for both reading and
* writing. However, the {@link #readPermission()} and {@link #writePermission()} attributes take
* precedence over this one.
*
* @return the path permission permission attribute
*/
String
permission
()
default
""
;
/**
* A permission that clients must have in order to query the content provider.
*
* @return the path permission readPermission attribute
*/
String
readPermission
()
default
""
;
/**
* A permission that clients must have in order to make changes to the data controlled by the
* content provider.
*
* @return the path permission writePermission attribute
*/
String
writePermission
()
default
""
;
}
appinventor/components/src/com/google/appinventor/components/annotations/androidmanifest/ProviderElement.java
0 → 100644
View file @
c503528d
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2020 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.androidmanifest
;
import
java.lang.annotation.ElementType
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.Target
;
/**
* Annotation to describe a <provider> element required by a component so that
* it can be added to AndroidManifest.xml. <provider> elements indicate that
* a component is a content provider. <provider> element attributes that are not
* set explicitly default to "" or {} and are ignored when the element is created
* in the manifest.
*
* Note: Most of this documentation is adapted from the Android framework specification
* linked below. That documentation is licensed under the
* {@link <a href="https://creativecommons.org/licenses/by/2.5/">
* Creative Commons Attribution license v2.5
* </a>}.
*
* See {@link <a href="https://developer.android.com/guide/topics/manifest/provider-element">
* https://developer.android.com/guide/topics/manifest/provider-element
* </a>}.
*
* @author https://github.com/ShreyashSaitwal (Shreyash Saitwal)
*/
@Retention
(
RetentionPolicy
.
RUNTIME
)
@Target
(
ElementType
.
TYPE
)
public
@interface
ProviderElement
{
/**
* An array containing any meta data used by this <provider> element.
*
* @return an array containing the <meta-data> subelements for this
* <provider> element
*/
MetaDataElement
[]
metaDataElements
()
default
{};
/**
* An array containing any path permissions used by this <provider> element.
*
* @return an array containing the <path-permission> subelements for this
* <provider> element
*/
PathPermissionElement
[]
pathPermissionElement
()
default
{};
/**
* An array containing any path permissions used by this <provider> element.
*
* @return an array containing the <path-permission> subelements for this
* <provider> element
*/
GrantUriPermissionElement
[]
grantUriPermissionElement
()
default
{};
/**
* A list of one or more URI authorities that identify data offered by the content provider.
* Multiple authorities are listed by separating their names with a semicolon. To avoid conflicts,
* authority names should use a Java-style naming convention (such as com.example.provider.cartoonprovider).
* Typically, it's the name of the ContentProvider subclass that implements the provider
*
* There is no default. At least one authority must be specified.
*
* @return the provider authorities attribute
*/
String
authorities
();
/**
* Whether or not the content provider can be instantiated by the system — "true" if it can be,
* and "false" if not. The default value is "true".
* The <application> element has its own enabled attribute that applies to all application components,
* including content providers. The <application> and <provider> attributes must both be "true" (as
* they both are by default) for the content provider to be enabled. If either is "false", the provider
* is disabled; it cannot be instantiated.
*
* @return the provider enabled attribute
*/
String
enabled
()
default
""
;
/**
* Whether or not the content provider is direct-boot aware; that is, whether or not it can run
* before the user unlocks the device.
*
* The default value is "false".
*
* @return the provider directBootAware attribute
*/
String
directBootAware
()
default
"false"
;
/**
* Whether the content provider is available for other applications to use:
* - true: The provider is available to other applications. Any application can use the provider's
* content URI to access it, subject to the permissions specified for the provider.
* - false: The provider is not available to other applications. Set android:exported="false" to
* limit access to the provider to your applications. Only applications that have the same
* user ID (UID) as the provider, or applications that have been temporarily granted access
* to the provider through the android:grantUriPermissions element, have access to it.
*
* Because this attribute was introduced in API level 17, all devices running API level 16 and lower
* behave as though this attribute is set "true". If you set android:targetSdkVersion to 17 or higher,
* then the default value is "false" for devices running API level 17 and higher.
* You can set android:exported="false" and still limit access to your provider by setting permissions
* with the {@link #permission()} attribute.
*
* @return the provider exported attribute
*/
String
exported
()
default
""
;
/**
* Whether or not those who ordinarily would not have permission to access the content
* provider's data can be granted permission to do so, temporarily overcoming the restriction
* imposed by the readPermission, writePermission, permission, and exported attributes — "true"
* if permission can be granted, and "false" if not. If "true", permission can be granted to
* any of the content provider's data. If "false", permission can be granted only to the data
* subsets listed in <grant-uri-permission> subelements, if any. The default value is "false".
*
* Granting permission is a way of giving an application component one-time access to data
* protected by a permission. For example, when an e-mail message contains an attachment, the
* mail application may call upon the appropriate viewer to open it, even though the viewer
* doesn't have general permission to look at all the content provider's data.
* In such cases, permission is granted by FLAG_GRANT_READ_URI_PERMISSION and FLAG_GRANT_WRITE_URI_PERMISSION
* flags in the Intent object that activates the component. For example, the mail application
* might put FLAG_GRANT_READ_URI_PERMISSION in the Intent passed to Context.startActivity().
* The permission is specific to the URI in the Intent.
* If you enable this feature, either by setting this attribute to "true" or by defining
* <grant-uri-permission> subelements, you must call Context.revokeUriPermission() when a
* covered URI is deleted from the provider.
* See also the {@link #GrantUriPermissionElement}.
*
* @return the provider grantUriPermission attribute
*/
String
grantUriPermissions
()
default
""
;
/**
* An icon representing the content provider. This attribute must be set as a reference to a
* drawable resource containing the image definition. If it is not set, the icon specified
* for the application as a whole is used instead.
*
* @return the provider icon attribute
*/
String
icon
()
default
""
;
/**
* The order in which the content provider should be instantiated, relative to other content
* providers hosted by the same process. When there are dependencies among content providers,
* setting this attribute for each of them ensures that they are created in the order required
* by those dependencies. The value is a simple integer, with higher numbers being initialized
* first.
*
* @return the provider initOrder attribute
*/
String
initOrder
()
default
""
;
/**
* A user-readable label for the content provided. If this attribute is not set, the label
* set for the application as a whole is used instead (see the <application> element's label
* attribute).
*
* The label should be set as a reference to a string resource, so that it can be localized
* like other strings in the user interface. However, as a convenience while you're developing
* the application, it can also be set as a raw string.
*
* @return the provider label attribute
*/
String
label
()
default
""
;
/**
* If the app runs in multiple processes, this attribute determines whether multiple instances
* of the content provider are created. If true, each of the app's processes has its own content
* provider object. If false, the app's processes share only one content provider object. The
* default value is false.
* Setting this flag to true may improve performance by reducing the overhead of interprocess
* communication, but it also increases the memory footprint of each process.
*
* @return the provider multiprocess attribute
*/
String
multiprocess
()
default
""
;
/**
* The name of the class that implements the content provider, a subclass of ContentProvider.
* This should be a fully qualified class name (such as, "com.example.project.TransportationProvider").
* However, as a shorthand, if the first character of the name is a period, it is appended to
* the package name specified in the <manifest> element.
*
* There is no default. The name must be specified.
*
* @return the provider class name
*/
String
name
();
/**
* The name of a permission that clients must have to read or write the content provider's data.
* This attribute is a convenient way of setting a single permission for both reading and writing.
* However, the {@link #readPermission()}, {@link #writePermission()}, and {@link #grantUriPermissions()}
* attributes take precedence over this one. If the {@link #readPermission()} attribute is also set,
* it controls access for querying the content provider. And if the writePermission attribute is set,
* it controls access for modifying the provider's data.
*
* @return the provider permission attribute
*/
String
permission
()
default
""
;
/**
* The name of the process in which the content provider should run. Normally, all components of an
* application run in the default process created for the application. It has the same name as the
* application package. The <application> element's process attribute can set a different default
* for all components. But each component can override the default with its own process attribute,
* allowing you to spread your application across multiple processes.
*
* If the name assigned to this attribute begins with a colon (':'), a new process, private to the
* application, is created when it's needed and the activity runs in that process. If the process
* name begins with a lowercase character, the activity will run in a global process of that name,
* provided that it has permission to do so. This allows components in different applications to
* share a process, reducing resource usage.
*
* @return the provider process attribute
*/
String
process
()
default
""
;
/**
* A permission that clients must have to query the content provider.
*
* If the provider sets android:grantUriPermissions to true, or if a given client satisfies the
* conditions of a <grant-uri-permission> subelement, the client can gain temporary read access
* to the content provider's data.
*
* See also the {@link #permission()} and {@link #writePermission()} attributes.
*
* @return the provider readPermission attribute
*/
String
readPermission
()
default
""
;
/**
* Whether or not the data under the content provider's control is to be synchronized with data on
* a server — "true" if it is to be synchronized, and "false" if not.
*
* @return the provider syncable attribute
*/
String
syncable
()
default
""
;
/**
* A permission that clients must have to make changes to the data controlled by the content provider.
* If the provider sets android:grantUriPermissions to true, or if a given client satisfies the conditions
* of a <grant-uri-permission> subelement, the client can gain temporary write access to modify the content
* provider's data.
* See also the {@link #permission()} and {@link #readPermission()} attributes.
*
* @return
*/
String
writePermission
()
default
""
;
}
appinventor/components/src/com/google/appinventor/components/annotations/androidmanifest/ServiceElement.java
0 → 100644
View file @
c503528d
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2020 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.androidmanifest
;
import
java.lang.annotation.ElementType
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.Target
;
/**
* Annotation to describe a <service> element required by a component so that
* it can be added to AndroidManifest.xml. <service> elements indicate that
* a component is a service. <service> element attributes that are not
* set explicitly default to "" or {} and are ignored when the element is created
* in the manifest.
*
* Note: Most of this documentation is adapted from the Android framework specification
* linked below. That documentation is licensed under the
* {@link <a href="https://creativecommons.org/licenses/by/2.5/">
* Creative Commons Attribution license v2.5
* </a>}.
*
* See {@link <a href="https://developer.android.com/guide/topics/manifest/service-element">
* https://developer.android.com/guide/topics/manifest/service-element
* </a>}.
*
* @author https://github.com/ShreyashSaitwal (Shreyash Saitwal)
*/
@Retention
(
RetentionPolicy
.
RUNTIME
)
@Target
(
ElementType
.
TYPE
)
public
@interface
ServiceElement
{
/**
* An array containing any intent filters used by this <service> element.
*
* @return an array containing the <intent-filter> subelements for this
* <service> element
*/
IntentFilterElement
[]
intentFilters
()
default
{};
/**
* An array containing any meta data used by this <service> element.
*
* @return an array containing the <meta-data> subelements for this
* <service> element
*/
MetaDataElement
[]
metaDataElements
()
default
{};
/**
* The name of the class that implements the service. This should
* be a fully qualified class name (such as, "com.example.project.RoomService").
* However, as a shorthand, if the first character of the name is
* a period (for example, ".RoomService"), it is appended to the
* package name of the application.
*
* @return the Service class name
*/
String
name
();
/**
* If set to true, this service will run under a special process that
* is isolated from the rest of the system and has no permissions
* of its own. The only communication with it is through the Service
* API (binding and starting).
*
* @return the service isolatedProcess attribute
*/
String
isolatedProcess
()
default
""
;
/**
* Specify that the service is a foreground service that satisfies a
* particular use case. For example, a foreground service type of
* "location" indicates that an app is getting the device's current
* location, usually to continue a user-initiated action related to
* device location.
* You can assign multiple foreground service types to a particular service.
*
* @return the service foregroundServiceType attribute
*/
String
foregroundServiceType
()
default
""
;
/**
* A string that describes the service to users. The label should be
* set as a reference to a string resource, so that it can be localized
* like other strings in the user interface.
*
* @return the service desciption attribute
*/
String
description
()
default
""
;
/**
* Whether or not the service is direct-boot aware; that is, whether or
* not it can run before the user unlocks the device.
*
* @return the service directBootAware attribute
*/
String
directBootAware
()
default
""
;
/**
* Whether or not the service can be instantiated by the system — "true"
* if it can be, and "false" if not. The default value is "true".
* The <application> element has its own enabled attribute that applies
* to all application components, including services. The <application>
* and <service> attributes must both be "true" (as they both are by default)
* for the service to be enabled. If either is "false", the service is
* disabled; it cannot be instantiated.
*
* @return the service enabled attribute
*/
String
enabled
()
default
""
;
/**
* Whether or not components of other applications can invoke the service
* or interact with it — "true" if they can, and "false" if not. When the
* value is "false", only components of the same application or applications
* with the same user ID can start the service or bind to it.
*
* The default value depends on whether the service contains intent filters.
* The absence of any filters means that it can be invoked only by specifying
* its exact class name. This implies that the service is intended only for
* application-internal use (since others would not know the class name). So
* in this case, the default value is "false". On the other hand, the presence
* of at least one filter implies that the service is intended for external use,
* so the default value is "true".
* This attribute is not the only way to limit the exposure of a service to other
* applications. You can also use a permission to limit the external entities that
* can interact with the service.
*
* @return the service exported attribute
*/
String
exported
()
default
""
;
/**
* An icon representing the service. This attribute must be set as
* a reference to a drawable resource containing the image definition. If it is
* not set, the icon specified for the application as a whole is used instead.
*
* The service's icon — whether set here or by the <application>
* element — is also the default icon for all the service's intent filters
* (see the {@link IntentFilterElement#icon()} attribute).
*
* @return the service icon attribute
*/
String
icon
()
default
""
;
/**
* A name for the service that can be displayed to users. If this attribute
* is not set, the label set for the application as a whole is used instead.
*
* The service's label — whether set here or by the <application> element —
* is also the default label for all the service's intent filters.
*
* @return the service label attribute
*/
String
label
()
default
""
;
/**
* The name of a permission that an entity must have in order to launch the
* service or bind to it. If a caller of startService(), bindService(), or
* stopService(), has not been granted this permission, the method will not
* work and the Intent object will not be delivered to the service.
*
* If this attribute is not set, the permission set by the <application>
* element's permission attribute applies to the service. If neither attribute
* is set, the service is not protected by a permission.
*
* @return the service permission attribute
*/
String
permission
()
default
""
;
/**
* The name of the process in which the service should run. Normally,
* all components of an application run in the default process created for the
* application. For our purposes, those components are services and
* activities. It has the same name as the application package. Each component
* can override the default with its own process attribute, allowing you to
* spread your application across multiple processes.
*
* If the name assigned to this attribute begins with a colon (':'), a new
* process, private to the application, is created when it's needed and the
* service runs in that process. If the process name begins with
* a lowercase character, the service will run in a global process of that
* name, provided that it has permission to do so. This allows components
* ( services and activities) in different applications to share
* a process, reducing resource usage.
*
* @return the service process attribute
*/
String
process
()
default
""
;
}
appinventor/components/src/com/google/appinventor/components/common/ComponentDescriptorConstants.java
View file @
c503528d
...
...
@@ -26,6 +26,8 @@ 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
SERVICES_TARGET
=
"services"
;
public
static
final
String
CONTENT_PROVIDERS_TARGET
=
"contentProviders"
;
public
static
final
String
ANDROIDMINSDK_TARGET
=
"androidMinSdk"
;
public
static
final
String
CONDITIONALS_TARGET
=
"conditionals"
;
...
...
appinventor/components/src/com/google/appinventor/components/scripts/ComponentDescriptorGenerator.java
View file @
c503528d
...
...
@@ -213,7 +213,9 @@ public final class ComponentDescriptorGenerator extends ComponentProcessor {
*/
private
void
outputConditionalAnnotations
(
ComponentInfo
component
,
StringBuilder
sb
)
{
if
(
component
.
conditionalPermissions
.
size
()
+
component
.
conditionalBroadcastReceivers
.
size
()
==
0
)
{
component
.
conditionalBroadcastReceivers
.
size
()
+
component
.
conditionalServices
.
size
()
+
component
.
conditionalContentProviders
.
size
()
==
0
)
{
return
;
}
sb
.
append
(
",\n \"conditionals\":{\n "
);
...
...
@@ -229,6 +231,18 @@ public final class ComponentDescriptorGenerator extends ComponentProcessor {
outputMultimap
(
sb
,
" "
,
component
.
conditionalBroadcastReceivers
);
first
=
false
;
}
if
(
component
.
conditionalServices
.
size
()
>
0
)
{
if
(!
first
)
sb
.
append
(
",\n "
);
sb
.
append
(
"\"services\": "
);
outputMultimap
(
sb
,
" "
,
component
.
conditionalServices
);
first
=
false
;
}
if
(
component
.
conditionalContentProviders
.
size
()
>
0
)
{
if
(!
first
)
sb
.
append
(
",\n "
);
sb
.
append
(
"\"contentProviders\": "
);
outputMultimap
(
sb
,
" "
,
component
.
conditionalContentProviders
);
first
=
false
;
}
// Add other annotations here as needed
sb
.
append
(
"\n }"
);
}
...
...
appinventor/components/src/com/google/appinventor/components/scripts/ComponentListGenerator.java
View file @
c503528d
...
...
@@ -18,8 +18,8 @@ import javax.tools.Diagnostic;
import
javax.tools.FileObject
;
/**
* Tool to generate a list of the simple component types, permissions, libraries, activities
*
and Broadcast Receiv
ers (build info) required for each component.
* Tool to generate a list of the simple component types, permissions, libraries, activities
,
*
Broadcast Receivers, Services and Content Provid
ers (build info) required for each component.
*
* @author lizlooney@google.com (Liz Looney)
*/
...
...
@@ -85,6 +85,8 @@ 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
.
SERVICES_TARGET
,
component
.
services
);
appendComponentInfo
(
sb
,
ComponentDescriptorConstants
.
CONTENT_PROVIDERS_TARGET
,
component
.
contentProviders
);
appendConditionalComponentInfo
(
component
,
sb
);
// TODO(Will): Remove the following call once the deprecated
// @SimpleBroadcastReceiver annotation is removed. It should
...
...
@@ -103,7 +105,9 @@ public final class ComponentListGenerator extends ComponentProcessor {
*/
private
static
void
appendConditionalComponentInfo
(
ComponentInfo
component
,
StringBuilder
sb
)
{
if
(
component
.
conditionalPermissions
.
size
()
+
component
.
conditionalBroadcastReceivers
.
size
()
==
0
)
{
component
.
conditionalBroadcastReceivers
.
size
()
+
component
.
conditionalServices
.
size
()
+
component
.
conditionalContentProviders
.
size
()
==
0
)
{
return
;
}
sb
.
append
(
", \""
+
ComponentDescriptorConstants
.
CONDITIONALS_TARGET
+
"\": { "
);
...
...
@@ -111,6 +115,10 @@ public final class ComponentListGenerator extends ComponentProcessor {
appendMap
(
sb
,
component
.
conditionalPermissions
);
sb
.
append
(
", \""
+
ComponentDescriptorConstants
.
BROADCAST_RECEIVERS_TARGET
+
"\": "
);
appendMap
(
sb
,
component
.
conditionalBroadcastReceivers
);
sb
.
append
(
", \""
+
ComponentDescriptorConstants
.
SERVICES_TARGET
+
"\": "
);
appendMap
(
sb
,
component
.
conditionalServices
);
sb
.
append
(
", \""
+
ComponentDescriptorConstants
.
CONTENT_PROVIDERS_TARGET
+
"\": "
);
appendMap
(
sb
,
component
.
conditionalContentProviders
);
sb
.
append
(
"}"
);
}
...
...
appinventor/components/src/com/google/appinventor/components/scripts/ComponentProcessor.java
View file @
c503528d
...
...
@@ -23,6 +23,8 @@ import com.google.appinventor.components.annotations.UsesNativeLibraries;
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.UsesServices
;
import
com.google.appinventor.components.annotations.androidmanifest.ActivityElement
;
import
com.google.appinventor.components.annotations.androidmanifest.ReceiverElement
;
import
com.google.appinventor.components.annotations.androidmanifest.IntentFilterElement
;
...
...
@@ -30,6 +32,10 @@ import com.google.appinventor.components.annotations.androidmanifest.MetaDataEle
import
com.google.appinventor.components.annotations.androidmanifest.ActionElement
;
import
com.google.appinventor.components.annotations.androidmanifest.DataElement
;
import
com.google.appinventor.components.annotations.androidmanifest.CategoryElement
;
import
com.google.appinventor.components.annotations.androidmanifest.ServiceElement
;
import
com.google.appinventor.components.annotations.androidmanifest.ProviderElement
;
import
com.google.appinventor.components.annotations.androidmanifest.PathPermissionElement
;
import
com.google.appinventor.components.annotations.androidmanifest.GrantUriPermissionElement
;
import
com.google.appinventor.components.common.PropertyTypeConstants
;
import
com.google.common.collect.ImmutableSet
;
import
com.google.common.collect.Lists
;
...
...
@@ -141,7 +147,9 @@ public abstract class ComponentProcessor extends AbstractProcessor {
"com.google.appinventor.components.annotations.UsesNativeLibraries"
,
"com.google.appinventor.components.annotations.UsesActivities"
,
"com.google.appinventor.components.annotations.UsesBroadcastReceivers"
,
"com.google.appinventor.components.annotations.UsesPermissions"
);
"com.google.appinventor.components.annotations.UsesPermissions"
,
"com.google.appinventor.components.annotations.UsesServices"
,
"com.google.appinventor.components.annotations.UsesContentProviders"
);
// Returned by getRwString()
private
static
final
String
READ_WRITE
=
"read-write"
;
...
...
@@ -653,6 +661,18 @@ public abstract class ComponentProcessor extends AbstractProcessor {
*/
protected
final
Map
<
String
,
String
[]>
conditionalBroadcastReceivers
;
/**
* Mapping of component block names to services that should be
* included if the block is used.
*/
protected
final
Map
<
String
,
String
[]>
conditionalServices
;
/**
* Mapping of component block names to content providers that should be
* included if the block is used.
*/
protected
final
Map
<
String
,
String
[]>
conditionalContentProviders
;
/**
* Libraries required by this component.
*/
...
...
@@ -687,6 +707,16 @@ public abstract class ComponentProcessor extends AbstractProcessor {
* Broadcast receivers required by this component.
*/
protected
final
Set
<
String
>
broadcastReceivers
;
/**
* Services required by this component.
*/
protected
final
Set
<
String
>
services
;
/**
* Content providers required by this component.
*/
protected
final
Set
<
String
>
contentProviders
;
/**
* TODO(Will): Remove the following field once the deprecated {@link SimpleBroadcastReceiver}
...
...
@@ -761,6 +791,8 @@ public abstract class ComponentProcessor extends AbstractProcessor {
permissions
=
Sets
.
newHashSet
();
conditionalPermissions
=
Maps
.
newTreeMap
();
conditionalBroadcastReceivers
=
Maps
.
newTreeMap
();
conditionalServices
=
Maps
.
newTreeMap
();
conditionalContentProviders
=
Maps
.
newTreeMap
();
libraries
=
Sets
.
newHashSet
();
nativeLibraries
=
Sets
.
newHashSet
();
assets
=
Sets
.
newHashSet
();
...
...
@@ -768,6 +800,8 @@ public abstract class ComponentProcessor extends AbstractProcessor {
metadata
=
Sets
.
newHashSet
();
activityMetadata
=
Sets
.
newHashSet
();
broadcastReceivers
=
Sets
.
newHashSet
();
services
=
Sets
.
newHashSet
();
contentProviders
=
Sets
.
newHashSet
();
classNameAndActionsBR
=
Sets
.
newHashSet
();
designerProperties
=
Maps
.
newTreeMap
();
properties
=
Maps
.
newTreeMap
();
...
...
@@ -1116,6 +1150,8 @@ public abstract class ComponentProcessor extends AbstractProcessor {
componentInfo
.
metadata
.
addAll
(
parentComponent
.
metadata
);
componentInfo
.
activityMetadata
.
addAll
(
parentComponent
.
activityMetadata
);
componentInfo
.
broadcastReceivers
.
addAll
(
parentComponent
.
broadcastReceivers
);
componentInfo
.
services
.
addAll
(
parentComponent
.
services
);
componentInfo
.
contentProviders
.
addAll
(
parentComponent
.
contentProviders
);
// TODO(Will): Remove the following call once the deprecated
// @SimpleBroadcastReceiver annotation is removed. It should
// should remain for the time being because otherwise we'll break
...
...
@@ -1256,6 +1292,42 @@ public abstract class ComponentProcessor extends AbstractProcessor {
throw
new
RuntimeException
(
e
);
}
}
// Gather the required services and build their element strings.
UsesServices
usesServices
=
element
.
getAnnotation
(
UsesServices
.
class
);
if
(
usesServices
!=
null
)
{
try
{
for
(
ServiceElement
se
:
usesServices
.
services
())
{
updateWithNonEmptyValue
(
componentInfo
.
services
,
serviceElementToString
(
se
));
}
}
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 content providers and build their element strings.
UsesContentProviders
usesContentProviders
=
element
.
getAnnotation
(
UsesContentProviders
.
class
);
if
(
usesContentProviders
!=
null
)
{
try
{
for
(
ProviderElement
pe
:
usesContentProviders
.
providers
())
{
updateWithNonEmptyValue
(
componentInfo
.
contentProviders
,
providerElementToString
(
pe
));
}
}
catch
(
IllegalAccessException
e
)
{
messager
.
printMessage
(
Diagnostic
.
Kind
.
ERROR
,
"IllegalAccessException when gathering "
+
"provider attributes and subelements for component "
+
componentInfo
.
name
);
throw
new
RuntimeException
(
e
);
}
catch
(
InvocationTargetException
e
)
{
messager
.
printMessage
(
Diagnostic
.
Kind
.
ERROR
,
"InvocationTargetException when gathering "
+
"provider attributes and subelements for component "
+
componentInfo
.
name
);
throw
new
RuntimeException
(
e
);
}
}
// TODO(Will): Remove the following legacy code once the deprecated
// @SimpleBroadcastReceiver annotation is removed. It should
...
...
@@ -1425,6 +1497,43 @@ public abstract class ComponentProcessor extends AbstractProcessor {
return
elementString
.
append
(
" </receiver>\\n"
).
toString
();
}
// Transform a @ServiceElement into an XML element String for use later
// in creating AndroidManifest.xml.
private
static
String
serviceElementToString
(
ServiceElement
element
)
throws
IllegalAccessException
,
InvocationTargetException
{
// First, we build the <service> element's opening tag including any
// service element attributes.
StringBuilder
elementString
=
new
StringBuilder
(
" <service "
);
elementString
.
append
(
elementAttributesToString
(
element
));
elementString
.
append
(
">\\n"
);
// Now, we collect any <service> subelements.
elementString
.
append
(
subelementsToString
(
element
.
metaDataElements
()));
elementString
.
append
(
subelementsToString
(
element
.
intentFilters
()));
// Finally, we close the <service> element and create its String.
return
elementString
.
append
(
" </service>\\n"
).
toString
();
}
// Transform a @ProviderElement into an XML element String for use later
// in creating AndroidManifest.xml.
private
static
String
providerElementToString
(
ProviderElement
element
)
throws
IllegalAccessException
,
InvocationTargetException
{
// First, we build the <provider> element's opening tag including any
// content provider element attributes.
StringBuilder
elementString
=
new
StringBuilder
(
" <provider "
);
elementString
.
append
(
elementAttributesToString
(
element
));
elementString
.
append
(
">\\n"
);
// Now, we collect any <provider> subelements.
elementString
.
append
(
subelementsToString
(
element
.
metaDataElements
()));
elementString
.
append
(
subelementsToString
(
element
.
pathPermissionElement
()));
elementString
.
append
(
subelementsToString
(
element
.
grantUriPermissionElement
()));
// Finally, we close the <provider> element and create its String.
return
elementString
.
append
(
" </provider>\\n"
).
toString
();
}
// Transform a @MetaDataElement into an XML element String for use later
// in creating AndroidManifest.xml.
private
static
String
metaDataElementToString
(
MetaDataElement
element
)
...
...
@@ -1468,7 +1577,7 @@ public abstract class ComponentProcessor extends AbstractProcessor {
return
elementString
.
append
(
"/>\\n"
).
toString
();
}
// Transform a
n
@CategoryElement into an XML element String for use later
// Transform a @CategoryElement into an XML element String for use later
// in creating AndroidManifest.xml.
private
static
String
categoryElementToString
(
CategoryElement
element
)
throws
IllegalAccessException
,
InvocationTargetException
{
...
...
@@ -1480,7 +1589,7 @@ public abstract class ComponentProcessor extends AbstractProcessor {
return
elementString
.
append
(
"/>\\n"
).
toString
();
}
// Transform a
n
@DataElement into an XML element String for use later
// Transform a @DataElement into an XML element String for use later
// in creating AndroidManifest.xml.
private
static
String
dataElementToString
(
DataElement
element
)
throws
IllegalAccessException
,
InvocationTargetException
{
...
...
@@ -1492,6 +1601,30 @@ public abstract class ComponentProcessor extends AbstractProcessor {
return
elementString
.
append
(
"/>\\n"
).
toString
();
}
// Transform a @PathPermissionElement into an XML element String for use later
// in creating AndroidManifest.xml.
private
static
String
pathPermissionElementToString
(
PathPermissionElement
element
)
throws
IllegalAccessException
,
InvocationTargetException
{
// First, we build the <path-permission> element's opening tag including any
// receiver element attributes.
StringBuilder
elementString
=
new
StringBuilder
(
" <path-permission "
);
elementString
.
append
(
elementAttributesToString
(
element
));
// Finally, we close the <path-permission> element and create its String.
return
elementString
.
append
(
"/>\\n"
).
toString
();
}
// Transform a @GrantUriPermissionElement into an XML element String for use later
// in creating AndroidManifest.xml.
private
static
String
grantUriPermissionElementToString
(
GrantUriPermissionElement
element
)
throws
IllegalAccessException
,
InvocationTargetException
{
// First, we build the <grant-uri-permission> element's opening tag including any
// receiver element attributes.
StringBuilder
elementString
=
new
StringBuilder
(
" <grant-uri-permission "
);
elementString
.
append
(
elementAttributesToString
(
element
));
// Finally, we close the <grant-uri-permission> element and create its String.
return
elementString
.
append
(
"/>\\n"
).
toString
();
}
// Build the attribute String for a given XML element modeled by an
// annotation.
//
...
...
@@ -1541,6 +1674,10 @@ public abstract class ComponentProcessor extends AbstractProcessor {
subelementString
.
append
(
categoryElementToString
((
CategoryElement
)
subelement
));
}
else
if
(
subelement
instanceof
DataElement
)
{
subelementString
.
append
(
dataElementToString
((
DataElement
)
subelement
));
}
else
if
(
subelement
instanceof
PathPermissionElement
)
{
subelementString
.
append
(
pathPermissionElementToString
((
PathPermissionElement
)
subelement
));
}
else
if
(
subelement
instanceof
GrantUriPermissionElement
)
{
subelementString
.
append
(
grantUriPermissionElementToString
((
GrantUriPermissionElement
)
subelement
));
}
}
return
subelementString
.
toString
();
...
...
@@ -1793,7 +1930,7 @@ public abstract class ComponentProcessor extends AbstractProcessor {
*
* @param componentInfo Component info in which to store the conditional information.
* @param element The currently processed Java language element. This should be a method
* annotated with either @UsesPermission
or @UsesBroadcastReceivers.
* annotated with either @UsesPermission
, @UsesBroadcastReceivers, @UsesServices or @UsesContentProviders
* @param blockName The name of the block as it appears in the sources.
*/
private
void
processConditionalAnnotations
(
ComponentInfo
componentInfo
,
Element
element
,
...
...
@@ -1816,10 +1953,36 @@ public abstract class ComponentProcessor extends AbstractProcessor {
messager
.
printMessage
(
Kind
.
ERROR
,
"Unable to process broadcast receiver"
,
element
);
}
}
UsesServices
service
=
element
.
getAnnotation
(
UsesServices
.
class
);
if
(
service
!=
null
)
{
try
{
Set
<
String
>
services
=
new
HashSet
<>();
for
(
ServiceElement
se
:
service
.
services
())
{
updateWithNonEmptyValue
(
services
,
serviceElementToString
(
se
));
}
componentInfo
.
conditionalServices
.
put
(
blockName
,
services
.
toArray
(
new
String
[
0
]));
}
catch
(
Exception
e
)
{
messager
.
printMessage
(
Kind
.
ERROR
,
"Unable to process service"
,
element
);
}
}
UsesContentProviders
contentProvider
=
element
.
getAnnotation
(
UsesContentProviders
.
class
);
if
(
contentProvider
!=
null
)
{
try
{
Set
<
String
>
providers
=
new
HashSet
<>();
for
(
ProviderElement
pe
:
contentProvider
.
providers
())
{
updateWithNonEmptyValue
(
providers
,
providerElementToString
(
pe
));
}
componentInfo
.
conditionalContentProviders
.
put
(
blockName
,
providers
.
toArray
(
new
String
[
0
]));
}
catch
(
Exception
e
)
{
messager
.
printMessage
(
Kind
.
ERROR
,
"Unable to process content provider"
,
element
);
}
}
}
/**
* <p>Outputs the required component information in the desired format.
It is called by
* <p>Outputs the required component information in the desired format. It is called by
* {@link #process} after the fields {@link #components} and {@link #messager}
* have been populated.</p>
*
...
...
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